diff --git a/app/Http/Controllers/Admin/Server/ManageController.php b/app/Http/Controllers/Admin/Server/ManageController.php new file mode 100644 index 00000000..135d1b8b --- /dev/null +++ b/app/Http/Controllers/Admin/Server/ManageController.php @@ -0,0 +1,64 @@ +getShadowsocksServers(), + $serverService->getV2rayServers(), + $serverService->getTrojanServers() + ); + $tmp = array_column($servers, 'sort'); + array_multisort($tmp, SORT_ASC, $servers); + return response([ + 'data' => $servers + ]); + } + + public function sort(Request $request) + { + DB::beginTransaction(); + foreach ($request->input('sorts') as $k => $v) { + switch ($v['key']) { + case 'shadowsocks': + if (!ServerShadowsocks::find($v['value'])->update(['sort' => $k + 1])) { + DB::rollBack(); + abort(500, '保存失败'); + } + break; + case 'v2ray': + if (!Server::find($v['value'])->update(['sort' => $k + 1])) { + DB::rollBack(); + abort(500, '保存失败'); + } + break; + case 'trojan': + if (!ServerTrojan::find($v['value'])->update(['sort' => $k + 1])) { + DB::rollBack(); + abort(500, '保存失败'); + } + break; + } + } + DB::commit(); + return response([ + 'data' => true + ]); + } +} diff --git a/app/Http/Controllers/Client/AppController.php b/app/Http/Controllers/Client/AppController.php index d141008f..63d2b8b4 100644 --- a/app/Http/Controllers/Client/AppController.php +++ b/app/Http/Controllers/Client/AppController.php @@ -23,7 +23,7 @@ class AppController extends Controller $userService = new UserService(); if ($userService->isAvailable($user)) { $serverService = new ServerService(); - $servers = $serverService->getAllServers($user); + $servers = $serverService->getAvailableServers($user); } $config = Yaml::parseFile(base_path() . '/resources/rules/app.clash.yaml'); $proxy = []; diff --git a/app/Http/Controllers/Client/ClientController.php b/app/Http/Controllers/Client/ClientController.php index 877963b4..821702b2 100644 --- a/app/Http/Controllers/Client/ClientController.php +++ b/app/Http/Controllers/Client/ClientController.php @@ -30,52 +30,54 @@ class ClientController extends Controller $userService = new UserService(); if ($userService->isAvailable($user)) { $serverService = new ServerService(); - $servers = $serverService->getAllServers($user); + $servers = $serverService->getAvailableServers($user); if ($flag) { if (strpos($flag, 'quantumult%20x') !== false) { - die($this->quantumultX($user, $servers['shadowsocks'], $servers['vmess'], $servers['trojan'])); + die($this->quantumultX($user, $servers)); } if (strpos($flag, 'quantumult') !== false) { - die($this->quantumult($user, $servers['vmess'])); + die($this->quantumult($user, $servers)); } if (strpos($flag, 'clash') !== false) { - die($this->clash($user, $servers['shadowsocks'], $servers['vmess'], $servers['trojan'])); + die($this->clash($user, $servers)); } if (strpos($flag, 'surfboard') !== false) { - die($this->surfboard($user, $servers['shadowsocks'], $servers['vmess'])); + die($this->surfboard($user, $servers)); } if (strpos($flag, 'surge') !== false) { - die($this->surge($user, $servers['shadowsocks'], $servers['vmess'], $servers['trojan'])); + die($this->surge($user, $servers)); } if (strpos($flag, 'shadowrocket') !== false) { - die($this->shadowrocket($user, $servers['shadowsocks'], $servers['vmess'], $servers['trojan'])); + die($this->shadowrocket($user, $servers)); } } - die($this->origin($user, $servers['shadowsocks'], $servers['vmess'], $servers['trojan'])); + die($this->origin($user, $servers)); } } // TODO: Ready to stop support - private function quantumult($user, $vmess = []) + private function quantumult($user, $servers = []) { $uri = ''; header('subscription-userinfo: upload=' . $user->u . '; download=' . $user->d . ';total=' . $user->transfer_enable); - foreach ($vmess as $item) { - $str = ''; - $str .= $item->name . '= vmess, ' . $item->host . ', ' . $item->port . ', chacha20-ietf-poly1305, "' . $user->uuid . '", over-tls=' . ($item->tls ? "true" : "false") . ', certificate=0, group=' . config('v2board.app_name', 'V2Board'); - if ($item->network === 'ws') { - $str .= ', obfs=ws'; - if ($item->networkSettings) { - $wsSettings = json_decode($item->networkSettings); - if (isset($wsSettings->path)) $str .= ', obfs-path="' . $wsSettings->path . '"'; - if (isset($wsSettings->headers->Host)) $str .= ', obfs-header="Host:' . $wsSettings->headers->Host . '"'; + foreach ($servers as $item) { + if ($item['type'] === 'v2ray') { + $str = ''; + $str .= $item->name . '= vmess, ' . $item->host . ', ' . $item->port . ', chacha20-ietf-poly1305, "' . $user->uuid . '", over-tls=' . ($item->tls ? "true" : "false") . ', certificate=0, group=' . config('v2board.app_name', 'V2Board'); + if ($item->network === 'ws') { + $str .= ', obfs=ws'; + if ($item->networkSettings) { + $wsSettings = json_decode($item->networkSettings); + if (isset($wsSettings->path)) $str .= ', obfs-path="' . $wsSettings->path . '"'; + if (isset($wsSettings->headers->Host)) $str .= ', obfs-header="Host:' . $wsSettings->headers->Host . '"'; + } } + $uri .= "vmess://" . base64_encode($str) . "\r\n"; } - $uri .= "vmess://" . base64_encode($str) . "\r\n"; } return base64_encode($uri); } - private function shadowrocket($user, $shadowsocks = [], $vmess = [], $trojan = []) + private function shadowrocket($user, $servers = []) { $uri = ''; //display remaining traffic and expire date @@ -84,73 +86,79 @@ class ClientController extends Controller $totalTraffic = round($user->transfer_enable / (1024*1024*1024), 2); $expiredDate = date('Y-m-d', $user->expired_at); $uri .= "STATUS=🚀↑:{$upload}GB,↓:{$download}GB,TOT:{$totalTraffic}GB💡Expires:{$expiredDate}\r\n"; - foreach ($shadowsocks as $item) { - $uri .= Shadowrocket::buildShadowsocks($user->uuid, $item); - } - foreach ($vmess as $item) { - $uri .= Shadowrocket::buildVmess($user->uuid, $item); - } - foreach ($trojan as $item) { - $uri .= Shadowrocket::buildTrojan($user->uuid, $item); + foreach ($servers as $item) { + if ($item['type'] === 'shadowsocks') { + $uri .= Shadowrocket::buildShadowsocks($user->uuid, $item); + } + if ($item['type'] === 'v2ray') { + $uri .= Shadowrocket::buildVmess($user->uuid, $item); + } + if ($item['type'] === 'trojan') { + $uri .= Shadowrocket::buildTrojan($user->uuid, $item); + } } return base64_encode($uri); } - private function quantumultX($user, $shadowsocks = [], $vmess = [], $trojan = []) + private function quantumultX($user, $servers = []) { $uri = ''; header("subscription-userinfo: upload={$user->u}; download={$user->d}; total={$user->transfer_enable}; expire={$user->expired_at}"); - foreach ($shadowsocks as $item) { - $uri .= QuantumultX::buildShadowsocks($user->uuid, $item); - } - foreach ($vmess as $item) { - $uri .= QuantumultX::buildVmess($user->uuid, $item); - } - foreach ($trojan as $item) { - $uri .= QuantumultX::buildTrojan($user->uuid, $item); + foreach ($servers as $item) { + if ($item['type'] === 'shadowsocks') { + $uri .= QuantumultX::buildShadowsocks($user->uuid, $item); + } + if ($item['type'] === 'v2ray') { + $uri .= QuantumultX::buildVmess($user->uuid, $item); + } + if ($item['type'] === 'trojan') { + $uri .= QuantumultX::buildTrojan($user->uuid, $item); + } } return base64_encode($uri); } - private function origin($user, $shadowsocks = [], $vmess = [], $trojan = []) + private function origin($user, $servers = []) { $uri = ''; - foreach ($shadowsocks as $item) { - $uri .= URLSchemes::buildShadowsocks($item, $user); - } - foreach ($vmess as $item) { - $uri .= URLSchemes::buildVmess($item, $user); - } - foreach ($trojan as $item) { - $uri .= URLSchemes::buildTrojan($item, $user); + foreach ($servers as $item) { + if ($item['type'] === 'shadowsocks') { + $uri .= URLSchemes::buildShadowsocks($item, $user); + } + if ($item['type'] === 'v2ray') { + $uri .= URLSchemes::buildVmess($item, $user); + } + if ($item['type'] === 'trojan') { + $uri .= URLSchemes::buildTrojan($item, $user); + } } return base64_encode($uri); } - private function surge($user, $shadowsocks = [], $vmess = [], $trojan = []) + private function surge($user, $servers = []) { $proxies = ''; $proxyGroup = ''; - foreach ($shadowsocks as $item) { - // [Proxy] - $proxies .= Surge::buildShadowsocks($user->uuid, $item); - // [Proxy Group] - $proxyGroup .= $item->name . ', '; - } - - foreach ($vmess as $item) { - // [Proxy] - $proxies .= Surge::buildVmess($user->uuid, $item); - // [Proxy Group] - $proxyGroup .= $item->name . ', '; - } - - foreach ($trojan as $item) { - // [Proxy] - $proxies .= Surge::buildTrojan($user->uuid, $item); - // [Proxy Group] - $proxyGroup .= $item->name . ', '; + foreach ($servers as $item) { + if ($item['type'] === 'shadowsocks') { + // [Proxy] + $proxies .= Surge::buildShadowsocks($user->uuid, $item); + // [Proxy Group] + $proxyGroup .= $item->name . ', '; + } + if ($item['type'] === 'v2ray') { + // [Proxy] + $proxies .= Surge::buildVmess($user->uuid, $item); + // [Proxy Group] + $proxyGroup .= $item->name . ', '; + } + if ($item['type'] === 'trojan') { + // [Proxy] + $proxies .= Surge::buildTrojan($user->uuid, $item); + // [Proxy Group] + $proxyGroup .= $item->name . ', '; + } } $defaultConfig = base_path() . '/resources/rules/default.surge.conf'; @@ -170,23 +178,24 @@ class ClientController extends Controller return $config; } - private function surfboard($user, $shadowsocks = [], $vmess = []) + private function surfboard($user, $servers = []) { $proxies = ''; $proxyGroup = ''; - foreach ($shadowsocks as $item) { - // [Proxy] - $proxies .= Surfboard::buildShadowsocks($user->uuid, $item); - // [Proxy Group] - $proxyGroup .= $item->name . ', '; - } - - foreach ($vmess as $item) { - // [Proxy] - $proxies .= Surfboard::buildVmess($user->uuid, $item); - // [Proxy Group] - $proxyGroup .= $item->name . ', '; + foreach ($servers as $item) { + if ($item['type'] === 'shadowsocks') { + // [Proxy] + $proxies .= Surfboard::buildShadowsocks($user->uuid, $item); + // [Proxy Group] + $proxyGroup .= $item->name . ', '; + } + if ($item['type'] === 'v2ray') { + // [Proxy] + $proxies .= Surfboard::buildVmess($user->uuid, $item); + // [Proxy Group] + $proxyGroup .= $item->name . ', '; + } } $defaultConfig = base_path() . '/resources/rules/default.surfboard.conf'; @@ -206,7 +215,7 @@ class ClientController extends Controller return $config; } - private function clash($user, $shadowsocks = [], $vmess = [], $trojan = []) + private function clash($user, $servers = []) { $defaultConfig = base_path() . '/resources/rules/default.clash.yaml'; $customConfig = base_path() . '/resources/rules/custom.clash.yaml'; @@ -218,19 +227,19 @@ class ClientController extends Controller $proxy = []; $proxies = []; - foreach ($shadowsocks as $item) { - array_push($proxy, Clash::buildShadowsocks($user->uuid, $item)); - array_push($proxies, $item->name); - } - - foreach ($vmess as $item) { - array_push($proxy, Clash::buildVmess($user->uuid, $item)); - array_push($proxies, $item->name); - } - - foreach ($trojan as $item) { - array_push($proxy, Clash::buildTrojan($user->uuid, $item)); - array_push($proxies, $item->name); + foreach ($servers as $item) { + if ($item['type'] === 'shadowsocks') { + array_push($proxy, Clash::buildShadowsocks($user->uuid, $item)); + array_push($proxies, $item->name); + } + if ($item['type'] === 'v2ray') { + array_push($proxy, Clash::buildVmess($user->uuid, $item)); + array_push($proxies, $item->name); + } + if ($item['type'] === 'trojan') { + array_push($proxy, Clash::buildTrojan($user->uuid, $item)); + array_push($proxies, $item->name); + } } $config['proxies'] = array_merge($config['proxies'] ? $config['proxies'] : [], $proxy); diff --git a/app/Http/Controllers/User/ServerController.php b/app/Http/Controllers/User/ServerController.php index d178c177..4ab8890c 100644 --- a/app/Http/Controllers/User/ServerController.php +++ b/app/Http/Controllers/User/ServerController.php @@ -23,8 +23,7 @@ class ServerController extends Controller $userService = new UserService(); if ($userService->isAvailable($user)) { $serverService = new ServerService(); - $servers = $serverService->getAllServers($user); - $servers = array_merge($servers['shadowsocks'], $servers['vmess'], $servers['trojan']); + $servers = $serverService->getAvailableServers($user); } return response([ 'data' => $servers diff --git a/app/Http/Routes/AdminRoute.php b/app/Http/Routes/AdminRoute.php index 23f05c51..6186606c 100644 --- a/app/Http/Routes/AdminRoute.php +++ b/app/Http/Routes/AdminRoute.php @@ -26,6 +26,8 @@ class AdminRoute $router->get ('/server/group/fetch', 'Admin\\Server\\GroupController@fetch'); $router->post('/server/group/save', 'Admin\\Server\\GroupController@save'); $router->post('/server/group/drop', 'Admin\\Server\\GroupController@drop'); + $router->get ('/server/manage/getNodes', 'Admin\\Server\\ManageController@getNodes'); + $router->post('/server/manage/sort', 'Admin\\Server\\ManageController@sort'); $router->group([ 'prefix' => 'server/trojan' ], function ($router) { diff --git a/app/Services/ServerService.php b/app/Services/ServerService.php index eed2824b..9cca54e4 100644 --- a/app/Services/ServerService.php +++ b/app/Services/ServerService.php @@ -17,7 +17,7 @@ class ServerService CONST V2RAY_CONFIG = '{"api":{"services":["HandlerService","StatsService"],"tag":"api"},"dns":{},"stats":{},"inbound":{"port":443,"protocol":"vmess","settings":{"clients":[]},"sniffing":{"enabled":true,"destOverride":["http","tls"]},"streamSettings":{"network":"tcp"},"tag":"proxy"},"inboundDetour":[{"listen":"0.0.0.0","port":23333,"protocol":"dokodemo-door","settings":{"address":"0.0.0.0"},"tag":"api"}],"log":{"loglevel":"debug","access":"access.log","error":"error.log"},"outbound":{"protocol":"freedom","settings":{}},"outboundDetour":[{"protocol":"blackhole","settings":{},"tag":"block"}],"routing":{"rules":[{"inboundTag":"api","outboundTag":"api","type":"field"}]},"policy":{"levels":{"0":{"handshake":4,"connIdle":300,"uplinkOnly":5,"downlinkOnly":30,"statsUserUplink":true,"statsUserDownlink":true}}}}'; CONST TROJAN_CONFIG = '{"run_type":"server","local_addr":"0.0.0.0","local_port":443,"remote_addr":"www.taobao.com","remote_port":80,"password":[],"ssl":{"cert":"server.crt","key":"server.key","sni":"domain.com"},"api":{"enabled":true,"api_addr":"127.0.0.1","api_port":10000}}'; - public function getVmess(User $user, $all = false):array + public function getV2ray(User $user, $all = false):array { $vmess = []; $model = Server::orderBy('sort', 'ASC'); @@ -26,7 +26,7 @@ class ServerService } $vmesss = $model->get(); foreach ($vmesss as $k => $v) { - $vmesss[$k]['protocol_type'] = 'vmess'; + $vmesss[$k]['type'] = 'v2ray'; $groupId = json_decode($vmesss[$k]['group_id']); if (in_array($user->group_id, $groupId)) { $vmesss[$k]['link'] = URLSchemes::buildVmess($vmesss[$k], $user); @@ -52,7 +52,7 @@ class ServerService } $trojans = $model->get(); foreach ($trojans as $k => $v) { - $trojans[$k]['protocol_type'] = 'trojan'; + $trojans[$k]['type'] = 'trojan'; $groupId = json_decode($trojans[$k]['group_id']); $trojans[$k]['link'] = URLSchemes::buildTrojan($trojans[$k], $user); if (in_array($user->group_id, $groupId)) { @@ -77,7 +77,7 @@ class ServerService } $shadowsockss = $model->get(); foreach ($shadowsockss as $k => $v) { - $shadowsockss[$k]['protocol_type'] = 'shadowsocks'; + $shadowsockss[$k]['type'] = 'shadowsocks'; $groupId = json_decode($shadowsockss[$k]['group_id']); $shadowsockss[$k]['link'] = URLSchemes::buildShadowsocks($shadowsockss[$k], $user); if (in_array($user->group_id, $groupId)) { @@ -93,13 +93,16 @@ class ServerService return $shadowsocks; } - public function getAllServers(User $user, $all = false) + public function getAvailableServers(User $user, $all = false) { - return [ - 'shadowsocks' => $this->getShadowsocks($user, $all), - 'vmess' => $this->getVmess($user, $all), - 'trojan' => $this->getTrojan($user, $all) - ]; + $servers = array_merge( + $this->getShadowsocks($user, $all), + $this->getV2ray($user, $all), + $this->getTrojan($user, $all) + ); + $tmp = array_column($servers, 'sort'); + array_multisort($tmp, SORT_ASC, $servers); + return $servers; } @@ -288,4 +291,61 @@ class ServerService $serverLog->save(); } } + + public function getShadowsocksServers() + { + $server = ServerShadowsocks::orderBy('sort', 'ASC')->get(); + for ($i = 0; $i < count($server); $i++) { + $server[$i]['type'] = 'shadowsocks'; + if (!empty($server[$i]['tags'])) { + $server[$i]['tags'] = json_decode($server[$i]['tags']); + } + $server[$i]['group_id'] = json_decode($server[$i]['group_id']); + $server[$i]['online'] = Cache::get(CacheKey::get('SERVER_SHADOWSOCKS_ONLINE_USER', $server[$i]['parent_id'] ? $server[$i]['parent_id'] : $server[$i]['id'])); + if ($server[$i]['parent_id']) { + $server[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $server[$i]['parent_id'])); + } else { + $server[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_SHADOWSOCKS_LAST_CHECK_AT', $server[$i]['id'])); + } + } + return $server->toArray(); + } + + public function getV2rayServers() + { + $server = Server::orderBy('sort', 'ASC')->get(); + for ($i = 0; $i < count($server); $i++) { + $server[$i]['type'] = 'v2ray'; + if (!empty($server[$i]['tags'])) { + $server[$i]['tags'] = json_decode($server[$i]['tags']); + } + $server[$i]['group_id'] = json_decode($server[$i]['group_id']); + $server[$i]['online'] = Cache::get(CacheKey::get('SERVER_V2RAY_ONLINE_USER', $server[$i]['parent_id'] ? $server[$i]['parent_id'] : $server[$i]['id'])); + if ($server[$i]['parent_id']) { + $server[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $server[$i]['parent_id'])); + } else { + $server[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_V2RAY_LAST_CHECK_AT', $server[$i]['id'])); + } + } + return $server->toArray(); + } + + public function getTrojanServers() + { + $server = ServerTrojan::orderBy('sort', 'ASC')->get(); + for ($i = 0; $i < count($server); $i++) { + $server[$i]['type'] = 'trojan'; + if (!empty($server[$i]['tags'])) { + $server[$i]['tags'] = json_decode($server[$i]['tags']); + } + $server[$i]['group_id'] = json_decode($server[$i]['group_id']); + $server[$i]['online'] = Cache::get(CacheKey::get('SERVER_TROJAN_ONLINE_USER', $server[$i]['parent_id'] ? $server[$i]['parent_id'] : $server[$i]['id'])); + if ($server[$i]['parent_id']) { + $server[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $server[$i]['parent_id'])); + } else { + $server[$i]['last_check_at'] = Cache::get(CacheKey::get('SERVER_TROJAN_LAST_CHECK_AT', $server[$i]['id'])); + } + } + return $server->toArray(); + } }