Files
Xboard/app/Services/ServerService.php
T
yinjianm 4f84034814 • 你这个现象我已经定位并修了,核心原因是节点匹配和设备映射都有歧义。
已修改:

  - 节点识别优先用 id,只有找不到才回退 code,避免子节点被匹配成父节点
    ServerService.php (/E:/code/php/Xboard-new/app/Services/ServerService.php#L101)
  - 在线设备解析补全 node_key/node_id,并按真实节点键归类
    UserOnlineService.php (/E:/code/php/Xboard-new/app/Services/UserOnlineService.php#L43)
  - 用户端流量日志设备映射改为按 node_key 精确匹配
    StatController.php (/E:/code/php/Xboard-new/app/Http/Controllers/V1/User/StatController.php#L43)
  - 管理端同样改为按 node_key 映射
    StatController.php (/E:/code/php/Xboard-new/app/Http/Controllers/V2/Admin/StatController.php#L270)

  说明:

  - 这次不涉及数据库结构变更,不需要 migrate。
  - 对管理后台现有统计接口兼容,不会破坏原有 u/d/record_at/server_rate 显示。
  - 旧的历史日志如果之前已经按父节点入库,不会自动改名;新流量会按修复后的逻辑记录。
2026-02-26 05:13:19 +08:00

123 lines
3.5 KiB
PHP

<?php
namespace App\Services;
use App\Models\Server;
use App\Models\ServerRoute;
use App\Models\User;
use App\Services\Plugin\HookManager;
use App\Utils\Helper;
use Illuminate\Support\Collection;
class ServerService
{
/**
* 获取所有服务器列表
* @return Collection
*/
public static function getAllServers(): Collection
{
$query = Server::orderBy('sort', 'ASC');
return $query->get()->append([
'last_check_at',
'last_push_at',
'online',
'is_online',
'available_status',
'cache_key',
'load_status'
]);
}
/**
* 获取指定用户可用的服务器列表
* @param User $user
* @return array
*/
public static function getAvailableServers(User $user): array
{
$servers = Server::whereJsonContains('group_ids', (string) $user->group_id)
->where('show', true)
->orderBy('sort', 'ASC')
->get()
->append(['last_check_at', 'last_push_at', 'online', 'is_online', 'available_status', 'cache_key', 'server_key']);
$servers = collect($servers)->map(function ($server) use ($user) {
// 判断动态端口
if (str_contains($server->port, '-')) {
$port = $server->port;
$server->port = (int) Helper::randomPort($port);
$server->ports = $port;
} else {
$server->port = (int) $server->port;
}
$server->password = $server->generateServerPassword($user);
return $server;
})->toArray();
return $servers;
}
/**
* 根据权限组获取可用的用户列表
* @param array $groupIds
* @return Collection
*/
public static function getAvailableUsers(Server $node)
{
$users = User::toBase()
->whereIn('group_id', $node->group_ids)
->whereRaw('u + d < transfer_enable')
->where(function ($query) {
$query->where('expired_at', '>=', time())
->orWhere('expired_at', NULL);
})
->where('banned', 0)
->select([
'id',
'uuid',
'speed_limit',
'device_limit'
])
->get();
return HookManager::filter('server.users.get', $users, $node);
}
// 获取路由规则
public static function getRoutes(array $routeIds)
{
$routes = ServerRoute::select(['id', 'match', 'action', 'action_value'])->whereIn('id', $routeIds)->get();
return $routes;
}
/**
* 根据协议类型和标识获取服务器
* @param int $serverId
* @param string $serverType
* @return Server|null
*/
public static function getServer($serverId, ?string $serverType)
{
$baseQuery = Server::query()
->when($serverType, function ($query) use ($serverType) {
$query->where('type', Server::normalizeType($serverType));
});
$serverIdValue = is_scalar($serverId) ? (string) $serverId : '';
$isCanonicalInt = preg_match('/^(0|[1-9][0-9]*)$/', $serverIdValue) === 1;
if ($isCanonicalInt) {
$serverById = (clone $baseQuery)->whereKey((int) $serverIdValue)->first();
if ($serverById) {
return $serverById;
}
}
return (clone $baseQuery)
->where('code', $serverIdValue)
->first();
}
}