Compare commits

...

5 Commits

Author SHA1 Message Date
xboard
6b436255a0 fix: correct know file issues
Some checks are pending
Docker Build and Publish / build (push) Waiting to run
2025-01-09 18:47:00 +08:00
xboard
e1db186ee7 fix: correct know file issues 2025-01-09 18:36:14 +08:00
xboard
720aa415ac fix: correct know file issues 2025-01-09 15:58:32 +08:00
xboard
cd7c1ca34b update compose.sample.yaml 2025-01-09 12:21:21 +08:00
xboard
652c6eb125 fix: correct know file issues 2025-01-09 11:21:48 +08:00
30 changed files with 446 additions and 571 deletions

View File

@ -1,15 +1,6 @@
<?php
use App\Support\Setting;
if (! function_exists("get_request_content")){
function get_request_content(){
return request()->getContent() ?: json_encode($_POST);
}
}
if (! function_exists('admin_setting')) {
/**
* 获取或保存配置参数.

View File

@ -23,7 +23,7 @@ class TelegramController extends Controller
if ($request->input('access_token') !== md5(admin_setting('telegram_bot_token'))) {
throw new ApiException('access_token is error', 401);
}
$data = json_decode(get_request_content(),true);
$data = json_decode(request()->getContent(),true);
$this->formatMessage($data);
$this->formatChatJoinRequest($data);
$this->handle();

View File

@ -36,15 +36,34 @@ class UniProxyController extends Controller
// 后端提交数据
public function push(Request $request)
{
$res = json_decode(get_request_content(), true);
$res = json_decode(request()->getContent(), true);
if (!is_array($res)) {
return $this->fail([422, 'Invalid data format']);
}
$data = array_filter($res, function ($item) {
return is_array($item) && count($item) === 2 && is_numeric($item[0]) && is_numeric($item[1]);
return is_array($item)
&& count($item) === 2
&& is_numeric($item[0])
&& is_numeric($item[1]);
});
if (empty($data)) {
return $this->success(true);
}
$node = $request->input('node_info');
$nodeType = $node->type;
$nodeId = $node->id;
Cache::put(CacheKey::get('SERVER_' . strtoupper($nodeType) . '_ONLINE_USER', $nodeId), count($data), 3600);
Cache::put(CacheKey::get('SERVER_' . strtoupper($nodeType) . '_LAST_PUSH_AT', $nodeId), time(), 3600);
Cache::put(
CacheKey::get('SERVER_' . strtoupper($nodeType) . '_ONLINE_USER', $nodeId),
count($data),
3600
);
Cache::put(
CacheKey::get('SERVER_' . strtoupper($nodeType) . '_LAST_PUSH_AT', $nodeId),
time(),
3600
);
$userService = new UserService();
$userService->trafficFetch($node->toArray(), $nodeType, $data);
return $this->success(true);
@ -55,48 +74,50 @@ class UniProxyController extends Controller
{
$node = $request->input('node_info');
$nodeType = $node->type;
$protocolSettings = $node->protocol_settings;
$serverPort = $node->server_port;
$host = $node->host;
$baseConfig = [
'server_port' => $serverPort,
'network' => $protocolSettings['network'] ?? null,
'network_settings' => $protocolSettings['network_settings'] ?? null,
];
$response = match ($nodeType) {
'shadowsocks' => [
'server_port' => $node->server_port,
...$baseConfig,
'cipher' => $protocolSettings['cipher'],
'obfs' => $protocolSettings['obfs'],
'obfs_settings' => $protocolSettings['obfs_settings'],
'server_key' => $protocolSettings['cipher'] === '2022-blake3-aes-128-gcm'
? Helper::getServerKey($node->created_at, 16)
: ($protocolSettings['cipher'] === '2022-blake3-aes-256-gcm'
? Helper::getServerKey($node->created_at, 32)
: null)
'server_key' => match ($protocolSettings['cipher']) {
'2022-blake3-aes-128-gcm' => Helper::getServerKey($node->created_at, 16),
'2022-blake3-aes-256-gcm' => Helper::getServerKey($node->created_at, 32),
default => null
}
],
'vmess' => [
'server_port' => $node->server_port,
'network' => $protocolSettings['network'],
'networkSettings' => $protocolSettings['network_settings'],
...$baseConfig,
'tls' => $protocolSettings['tls']
],
'trojan' => [
'host' => $node->host,
'server_port' => $node->server_port,
...$baseConfig,
'host' => $host,
'server_name' => $protocolSettings['server_name'],
'network' => $protocolSettings['network'],
'networkSettings' => $protocolSettings['network_settings'],
],
'vless' => [
'server_port' => $node->server_port,
'network' => $protocolSettings['network'],
'network_settings' => $protocolSettings['network_settings'],
...$baseConfig,
'tls' => $protocolSettings['tls'],
'flow' => $protocolSettings['flow'],
'tls_settings' => match ((int) $protocolSettings['tls']) {
1 => $protocolSettings['tls_settings'],
2 => $protocolSettings['reality_settings']
}
'tls_settings' => (int) $protocolSettings['tls'] === 1
? $protocolSettings['tls_settings']
: $protocolSettings['reality_settings']
],
'hysteria' => [
'version' => $protocolSettings['version'],
'host' => $node->host,
'server_port' => $node->server_port,
'host' => $host,
'server_port' => $serverPort,
'server_name' => $protocolSettings['tls']['server_name'],
'up_mbps' => $protocolSettings['bandwidth']['up'],
'down_mbps' => $protocolSettings['bandwidth']['down'],
@ -104,18 +125,20 @@ class UniProxyController extends Controller
],
default => []
};
$response['base_config'] = [
'push_interval' => (int) admin_setting('server_push_interval', 60),
'pull_interval' => (int) admin_setting('server_pull_interval', 60)
];
if ($node['route_id']) {
$response['routes'] = ServerService::getRoutes($node['route_id']);
}
$eTag = sha1(json_encode($response));
if (strpos($request->header('If-None-Match'), $eTag) !== false) {
return response(null, 304);
if (!empty($node['route_ids'])) {
$response['routes'] = ServerService::getRoutes($node['route_ids']);
}
$eTag = sha1(json_encode($response));
if (strpos($request->header('If-None-Match') ?? '', $eTag) !== false) {
return response(null, 304);
}
return response($response)->header('ETag', "\"{$eTag}\"");
}

View File

@ -17,6 +17,7 @@ class ManageController extends Controller
{
$servers = collect(ServerService::getAllServers())->map(function ($item) {
$item['groups'] = ServerGroup::whereIn('id', $item['group_ids'])->get(['name', 'id']);
$item['parent'] = $item->parent;
return $item;
});
return $this->success($servers);

View File

@ -89,8 +89,8 @@ class StatController extends Controller
'paid_count' => 0,
'commission_total' => 0,
'commission_count' => 0,
'start_date' => $request->input('start_date', date('Y-m-d', $statistics->last()->record_at)),
'end_date' => $request->input('end_date', date('Y-m-d', $statistics->first()->record_at)),
'start_date' => $request->input('start_date', date('Y-m-d', $statistics->last()?->record_at)),
'end_date' => $request->input('end_date', date('Y-m-d', $statistics->first()?->record_at)),
'avg_paid_amount' => 0,
'avg_commission_amount' => 0
];

View File

@ -13,6 +13,7 @@ use App\Models\Plan;
use App\Models\User;
use App\Services\AuthService;
use App\Utils\Helper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@ -28,59 +29,128 @@ class UserController extends Controller
return $this->success($user->save());
}
private function applyFiltersAndSorts(Request $request, $builder)
/**
* Apply filters and sorts to the query builder
*
* @param Request $request
* @param Builder $builder
* @return void
*/
private function applyFiltersAndSorts(Request $request, Builder $builder): void
{
if ($request->has('filter')) {
collect($request->input('filter'))->each(function ($filter) use ($builder) {
$key = $filter['id'];
$value = $filter['value'];
$builder->where(function ($query) use ($key, $value) {
if (is_array($value)) {
if ($key === 'group_ids') {
$query->where(function ($subQuery) use ($value) {
$subQuery->whereIn('group_id', $value);
});
} else {
$query->whereIn($key, $value);
}
} else {
$query->where($key, 'like', "%{$value}%");
}
});
});
}
if ($request->has('sort')) {
collect($request->input('sort'))->each(function ($sort) use ($builder) {
$key = $sort['id'];
$value = $sort['desc'] ? 'DESC' : 'ASC';
$builder->orderBy($key, $value);
});
}
$this->applyFilters($request, $builder);
$this->applySorting($request, $builder);
}
/**
* Apply filters to the query builder
*
* @param Request $request
* @param Builder $builder
* @return void
*/
private function applyFilters(Request $request, Builder $builder): void
{
if (!$request->has('filter')) {
return;
}
collect($request->input('filter'))->each(function ($filter) use ($builder) {
$field = $filter['id'];
$value = $filter['value'];
$builder->where(function ($query) use ($field, $value) {
$this->buildFilterQuery($query, $field, $value);
});
});
}
/**
* Build the filter query based on field and value
*
* @param Builder $query
* @param string $field
* @param mixed $value
* @return void
*/
private function buildFilterQuery(Builder $query, string $field, mixed $value): void
{
if (!is_array($value)) {
$query->where($field, 'like', "%{$value}%");
return;
}
if ($field === 'group_ids') {
$query->whereIn('group_id', $value);
return;
}
$query->whereIn($field, $value);
}
/**
* Apply sorting to the query builder
*
* @param Request $request
* @param Builder $builder
* @return void
*/
private function applySorting(Request $request, Builder $builder): void
{
if (!$request->has('sort')) {
return;
}
collect($request->input('sort'))->each(function ($sort) use ($builder) {
$field = $sort['id'];
$direction = $sort['desc'] ? 'DESC' : 'ASC';
$builder->orderBy($field, $direction);
});
}
/**
* Fetch paginated user list with filters and sorting
*
* @param Request $request
* @return \Illuminate\Http\Response
*/
public function fetch(Request $request)
{
$current = $request->input('current', 1);
$pageSize = $request->input('pageSize', 10);
$userModel = User::with(['plan:id,name', 'invite_user:id,email', 'group:id,name'])->select(
DB::raw('*'),
DB::raw('(u+d) as total_used')
);
$userModel = User::with(['plan:id,name', 'invite_user:id,email', 'group:id,name'])
->select(DB::raw('*, (u+d) as total_used'));
$this->applyFiltersAndSorts($request, $userModel);
$users = $userModel->orderBy('id', 'desc')->paginate($pageSize, ['*'], 'page', $current);
$users = $userModel->orderBy('id', 'desc')
->paginate($pageSize, ['*'], 'page', $current);
$users->getCollection()->transform(function ($user) {
$user->subscribe_url = Helper::getSubscribeUrl($user->token);
$user->balance = $user->balance / 100;
$user->commission_balance = $user->commission_balance / 100;
return $user;
return $this->transformUserData($user);
});
return response([
'data' => $users->items(),
'total' => $users->total()
]);
}
/**
* Transform user data for response
*
* @param User $user
* @return User
*/
private function transformUserData(User $user): User
{
$user->subscribe_url = Helper::getSubscribeUrl($user->token);
$user->balance = $user->balance / 100;
$user->commission_balance = $user->commission_balance / 100;
return $user;
}
public function getUserInfoById(Request $request)
{
$request->validate([

View File

@ -93,9 +93,9 @@ class ServerSave extends FormRequest
{
return [
'name.required' => '节点名称不能为空',
'group_id.required' => '权限组不能为空',
'group_id.array' => '权限组格式不正确',
'route_id.array' => '路由组格式不正确',
'group_ids.required' => '权限组不能为空',
'group_ids.array' => '权限组格式不正确',
'route_ids.array' => '路由组格式不正确',
'parent_id.integer' => '父ID格式不正确',
'host.required' => '节点地址不能为空',
'port.required' => '连接端口不能为空',

View File

@ -1,54 +0,0 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ServerShadowsocksSave extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'show' => '',
'name' => 'required',
'group_id' => 'required|array',
'parent_id' => 'nullable|integer',
'route_id' => 'nullable|array',
'host' => 'required',
'port' => 'required',
'server_port' => 'required',
'cipher' => 'required|in:aes-128-gcm,aes-192-gcm,aes-256-gcm,chacha20-ietf-poly1305,2022-blake3-aes-128-gcm,2022-blake3-aes-256-gcm',
'obfs' => 'nullable|in:http',
'obfs_settings' => 'nullable|array',
'tags' => 'nullable|array',
'excludes' => 'nullable|array',
'ips' => 'nullable|array',
'rate' => 'required|numeric'
];
}
public function messages()
{
return [
'name.required' => '节点名称不能为空',
'group_id.required' => '权限组不能为空',
'group_id.array' => '权限组格式不正确',
'route_id.array' => '路由组格式不正确',
'parent_id.integer' => '父节点格式不正确',
'host.required' => '节点地址不能为空',
'port.required' => '连接端口不能为空',
'server_port.required' => '后端服务端口不能为空',
'cipher.required' => '加密方式不能为空',
'tags.array' => '标签格式不正确',
'rate.required' => '倍率不能为空',
'rate.numeric' => '倍率格式不正确',
'obfs.in' => '混淆格式不正确',
'obfs_settings.array' => '混淆设置格式不正确'
];
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ServerShadowsocksUpdate extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'show' => 'in:0,1'
];
}
public function messages()
{
return [
'show.in' => '显示状态格式不正确'
];
}
}

View File

@ -1,54 +0,0 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ServerTrojanSave extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'show' => '',
'name' => 'required',
'network' => 'required',
'networkSettings' => 'nullable',
'group_id' => 'required|array',
'route_id' => 'nullable|array',
'parent_id' => 'nullable|integer',
'host' => 'required',
'port' => 'required',
'server_port' => 'required',
'allow_insecure' => 'nullable|in:0,1',
'server_name' => 'nullable',
'tags' => 'nullable|array',
'excludes' => 'nullable|array',
'ips' => 'nullable|array',
'rate' => 'required|numeric'
];
}
public function messages()
{
return [
'name.required' => '节点名称不能为空',
'network.required' => '传输协议不能为空',
'group_id.required' => '权限组不能为空',
'group_id.array' => '权限组格式不正确',
'route_id.array' => '路由组格式不正确',
'parent_id.integer' => '父节点格式不正确',
'host.required' => '节点地址不能为空',
'port.required' => '连接端口不能为空',
'server_port.required' => '后端服务端口不能为空',
'allow_insecure.in' => '允许不安全格式不正确',
'tags.array' => '标签格式不正确',
'rate.required' => '倍率不能为空',
'rate.numeric' => '倍率格式不正确'
];
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ServerTrojanUpdate extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'show' => 'in:0,1'
];
}
public function messages()
{
return [
'show.in' => '显示状态格式不正确'
];
}
}

View File

@ -1,61 +0,0 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ServerVmessSave extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'show' => '',
'name' => 'required',
'group_id' => 'required|array',
'route_id' => 'nullable|array',
'parent_id' => 'nullable|integer',
'host' => 'required',
'port' => 'required',
'server_port' => 'required',
'tls' => 'required',
'tags' => 'nullable|array',
'excludes' => 'nullable|array',
'ips' => 'nullable|array',
'rate' => 'required|numeric',
'network' => 'required|in:tcp,kcp,ws,http,domainsocket,quic,grpc',
'networkSettings' => 'nullable|array',
'ruleSettings' => 'nullable|array',
'tlsSettings' => 'nullable|array',
'dnsSettings' => 'nullable|array'
];
}
public function messages()
{
return [
'name.required' => '节点名称不能为空',
'group_id.required' => '权限组不能为空',
'group_id.array' => '权限组格式不正确',
'route_id.array' => '路由组格式不正确',
'parent_id.integer' => '父ID格式不正确',
'host.required' => '节点地址不能为空',
'port.required' => '连接端口不能为空',
'server_port.required' => '后端服务端口不能为空',
'tls.required' => 'TLS不能为空',
'tags.array' => '标签格式不正确',
'rate.required' => '倍率不能为空',
'rate.numeric' => '倍率格式不正确',
'network.required' => '传输协议不能为空',
'network.in' => '传输协议格式不正确',
'networkSettings.array' => '传输协议配置有误',
'ruleSettings.array' => '规则配置有误',
'tlsSettings.array' => 'tls配置有误',
'dnsSettings.array' => 'dns配置有误'
];
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace App\Http\Requests\Admin;
use Illuminate\Foundation\Http\FormRequest;
class ServerVmessUpdate extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'show' => 'in:0,1'
];
}
public function messages()
{
return [
'show.in' => '显示状态格式不正确'
];
}
}

View File

@ -27,9 +27,9 @@ class PlanResources extends JsonResource
'capacity_limit' => $this->formatCapacityLimit(),
'transfer_enable' => $this['transfer_enable'],
'speed_limit' => $this['speed_limit'],
'show' => (bool)$this['show'],
'sell' => (bool)$this['sell'],
'renew' => (bool)$this['renew'],
'show' => (bool) $this['show'],
'sell' => (bool) $this['sell'],
'renew' => (bool) $this['renew'],
'reset_traffic_method' => $this['reset_traffic_method'],
'sort' => $this['sort'],
'created_at' => $this['created_at'],
@ -46,7 +46,7 @@ class PlanResources extends JsonResource
{
$prices = [];
foreach (Plan::LEGACY_PERIOD_MAPPING as $legacyPeriod => $newPeriod) {
$prices[$legacyPeriod] = optional($this['prices'])[$newPeriod] ? (int)$this['prices'][$newPeriod] * 100 : null;
$prices[$legacyPeriod] = optional($this['prices'])[$newPeriod] ? (float) $this['prices'][$newPeriod] * 100 : null;
}
return $prices;
}
@ -66,6 +66,6 @@ class PlanResources extends JsonResource
return __('Sold out');
}
return (int)$this['capacity_limit'];
return (int) $this['capacity_limit'];
}
}

View File

@ -185,11 +185,12 @@ class Server extends Model
$this->password = $user->uuid;
if (!isset($this->cipher) || !isset(self::CIPHER_CONFIGURATIONS[$this->cipher])) {
$cipher = data_get($this, 'protocol_settings.cipher');
if (!$cipher || !isset(self::CIPHER_CONFIGURATIONS[$cipher])) {
return;
}
$config = self::CIPHER_CONFIGURATIONS[$this->cipher];
$config = self::CIPHER_CONFIGURATIONS[$cipher];
$serverKey = Helper::getServerKey($this->created_at, $config['serverKeySize']);
$userKey = Helper::uuidToBase64($user->uuid, $config['userKeySize']);
$this->password = "{$serverKey}:{$userKey}";

View File

@ -1,28 +0,0 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class ServerShadowsocks extends Model
{
protected $table = 'v2_server_shadowsocks';
protected $dateFormat = 'U';
protected $guarded = ['id'];
protected $casts = [
'created_at' => 'timestamp',
'updated_at' => 'timestamp',
'group_id' => 'array',
'route_id' => 'array',
'tags' => 'array',
'excludes' => 'array',
'obfs_settings' => 'array',
'ips' => 'array'
];
public function parent(): BelongsTo
{
return $this->belongsTo(self::class, 'parent_id', 'id');
}
}

View File

@ -47,4 +47,9 @@ class User extends Authenticatable
{
return $this->hasMany(Ticket::class, 'user_id', 'id');
}
public function parent()
{
return $this->belongsTo(self::class, 'parent_id', 'id');
}
}

View File

@ -68,7 +68,7 @@ class BTCPay implements PaymentInterface
public function notify($params): array|bool
{
$payload = trim(get_request_content());
$payload = trim(request()->getContent());
$headers = getallheaders();

View File

@ -68,7 +68,7 @@ class Coinbase implements PaymentInterface
public function notify($params): array
{
$payload = trim(get_request_content());
$payload = trim(request()->getContent());
$json_param = json_decode($payload, true);

View File

@ -130,7 +130,7 @@ class ClashMeta implements ProtocolInterface
$array['server'] = $server['host'];
$array['port'] = $server['port'];
$array['cipher'] = data_get($server['protocol_settings'], 'cipher');
$array['password'] = $password;
$array['password'] = data_get($server, 'password', $password);
$array['udp'] = true;
return $array;
}

View File

@ -53,6 +53,7 @@ class General implements ProtocolInterface
{
$protocol_settings = $server['protocol_settings'];
$name = rawurlencode($server['name']);
$password = data_get($server, 'password', $password);
$str = str_replace(
['+', '/', '='],
['-', '_', ''],

View File

@ -44,6 +44,7 @@ class QuantumultX implements ProtocolInterface
public static function buildShadowsocks($password, $server)
{
$protocol_settings = $server['protocol_settings'];
$password = data_get($server, 'password', $password);
$config = [
"shadowsocks={$server['host']}:{$server['port']}",
"method={$protocol_settings['cipher']}",

View File

@ -60,6 +60,7 @@ class Shadowrocket implements ProtocolInterface
{
$protocol_settings = $server['protocol_settings'];
$name = rawurlencode($server['name']);
$password = data_get($server, 'password', $password);
$str = str_replace(
['+', '/', '='],
['-', '_', ''],

View File

@ -107,7 +107,7 @@ class SingBox implements ProtocolInterface
$array['server'] = $server['host'];
$array['server_port'] = $server['port'];
$array['method'] = data_get($server, 'protocol_settings.cipher');
$array['password'] = $password;
$array['password'] = data_get($server, 'password', $password);
return $array;
}

View File

@ -40,7 +40,9 @@ class ServerService
$server->loadParentCreatedAt();
$server->handlePortAllocation();
$server->loadServerStatus();
$server->server_key = Helper::getServerKey($server->created_at, 16);
if ($server->type === 'shadowsocks') {
$server->server_key = Helper::getServerKey($server->created_at, 16);
}
$server->generateShadowsocksPassword($user);
return $server;
@ -48,6 +50,10 @@ class ServerService
->toArray();
}
/**
*
*/
/**
* 根据权限组获取可用的用户列表
* @param array $groupIds

View File

@ -2,20 +2,20 @@ services:
web:
image: ghcr.io/cedar2025/xboard:new
volumes:
- ./.docker/.data/redis/:/run/redis-socket
- ./:/www/
- redis-socket:/run/redis-socket
environment:
- docker=true
depends_on:
- redis
network_mode: host
command: php artisan octane:start --server="swoole" --port=7001
command: php artisan octane:start --server="swoole" --port=7001 --host=0.0.0.0
restart: on-failure
horizon:
image: ghcr.io/cedar2025/xboard:new
volumes:
- ./.docker/.data/redis/:/run/redis-socket
- ./:/www/
- redis-socket:/run/redis-socket
restart: on-failure
network_mode: host
command: php artisan horizon
@ -23,13 +23,9 @@ services:
- redis
redis:
image: redis:7-alpine
command: redis-server --unixsocket /run/redis-socket/redis.sock --unixsocketperm 777 --save 900 1 --save 300 10 --save 60 10000
command: redis-server --unixsocket /data/redis.sock --unixsocketperm 777 --save 900 1 --save 300 10 --save 60 10000
restart: unless-stopped
volumes:
- ./.docker/.data/redis:/data
- redis-socket:/run/redis-socket
sysctls:
net.core.somaxconn: 1024
volumes:
redis-socket: # 定义共享卷用于 socket 通信
net.core.somaxconn: 1024

View File

@ -191,6 +191,9 @@ return new class extends Migration {
]);
}
// Update parent_id for all servers
$this->updateParentIds();
// Drop old tables
Schema::dropIfExists('v2_server_trojan');
Schema::dropIfExists('v2_server_vmess');
@ -199,6 +202,56 @@ return new class extends Migration {
Schema::dropIfExists('v2_server_hysteria');
}
/**
* Update parent_id references for all servers
*/
private function updateParentIds(): void
{
// Get all servers that have a parent_id
$servers = DB::table('v2_server')
->whereNotNull('parent_id')
->get();
// Update each server's parent_id to reference the new table's id
foreach ($servers as $server) {
$parentId = DB::table('v2_server')
->where('type', $server->type)
->where('code', $server->parent_id)
->value('id');
if ($parentId) {
DB::table('v2_server')
->where('id', $server->id)
->update(['parent_id' => $parentId]);
}
}
}
/**
* Restore parent_id references when rolling back
*/
private function restoreParentIds(string $type, string $table): void
{
// Get all servers of the specified type that have a parent_id
$servers = DB::table($table)
->whereNotNull('parent_id')
->get();
// Update each server's parent_id to reference back to the original id
foreach ($servers as $server) {
$originalParentId = DB::table('v2_server')
->where('type', $type)
->where('id', $server->parent_id)
->value('code');
if ($originalParentId) {
DB::table($table)
->where('id', $server->id)
->update(['parent_id' => $originalParentId]);
}
}
}
/**
* Reverse the migrations.
*/
@ -457,6 +510,13 @@ return new class extends Migration {
}
}
// Restore parent_id references for each server type
$this->restoreParentIds('trojan', 'v2_server_trojan');
$this->restoreParentIds('vmess', 'v2_server_vmess');
$this->restoreParentIds('vless', 'v2_server_vless');
$this->restoreParentIds('shadowsocks', 'v2_server_shadowsocks');
$this->restoreParentIds('hysteria', 'v2_server_hysteria');
// Drop new table
Schema::dropIfExists('v2_server');
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long