mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-14 11:20:53 +08:00
fix: resolve device sync issues and refactor WebSocket server
This commit is contained in:
144
app/WebSocket/NodeEventHandlers.php
Normal file
144
app/WebSocket/NodeEventHandlers.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace App\WebSocket;
|
||||
|
||||
use App\Models\Server;
|
||||
use App\Services\DeviceStateService;
|
||||
use App\Services\NodeRegistry;
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Workerman\Connection\TcpConnection;
|
||||
|
||||
class NodeEventHandlers
|
||||
{
|
||||
/**
|
||||
* Handle pong heartbeat
|
||||
*/
|
||||
public static function handlePong(TcpConnection $conn, int $nodeId, array $data = []): void
|
||||
{
|
||||
Cache::put("node_ws_alive:{$nodeId}", true, 86400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle node status update
|
||||
*/
|
||||
public static function handleNodeStatus(TcpConnection $conn, int $nodeId, array $data): void
|
||||
{
|
||||
$node = Server::find($nodeId);
|
||||
if (!$node) return;
|
||||
|
||||
$nodeType = strtoupper($node->type);
|
||||
Cache::put(\App\Utils\CacheKey::get('SERVER_' . $nodeType . '_LAST_CHECK_AT', $nodeId), time(), 3600);
|
||||
ServerService::updateMetrics($node, $data);
|
||||
|
||||
Log::debug("[WS] Node#{$nodeId} status updated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle device report from node
|
||||
*
|
||||
* 数据格式: {"event": "report.devices", "data": {userId: [ip1, ip2, ...], ...}}
|
||||
*/
|
||||
public static function handleDeviceReport(TcpConnection $conn, int $nodeId, array $data): void
|
||||
{
|
||||
$service = app(DeviceStateService::class);
|
||||
|
||||
// Get old data
|
||||
$oldDevices = $service->getNodeDevices($nodeId);
|
||||
|
||||
// Calculate diff
|
||||
$removedUsers = array_diff_key($oldDevices, $data);
|
||||
$newDevices = [];
|
||||
|
||||
foreach ($data as $userId => $ips) {
|
||||
if (is_numeric($userId) && is_array($ips)) {
|
||||
$newDevices[(int) $userId] = $ips;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle removed users
|
||||
foreach ($removedUsers as $userId => $ips) {
|
||||
$service->removeNodeDevices($nodeId, $userId);
|
||||
$service->notifyUpdate($userId);
|
||||
}
|
||||
|
||||
// Handle new/updated users
|
||||
foreach ($newDevices as $userId => $ips) {
|
||||
$service->setDevices($userId, $nodeId, $ips);
|
||||
}
|
||||
|
||||
// Mark for push
|
||||
Redis::sadd('device:push_pending_nodes', $nodeId);
|
||||
|
||||
Log::debug("[WS] Node#{$nodeId} synced " . count($newDevices) . " users, removed " . count($removedUsers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle device state request from node
|
||||
*/
|
||||
public static function handleDeviceRequest(TcpConnection $conn, int $nodeId, array $data = []): void
|
||||
{
|
||||
$node = Server::find($nodeId);
|
||||
if (!$node) return;
|
||||
|
||||
$users = ServerService::getAvailableUsers($node);
|
||||
$userIds = $users->pluck('id')->toArray();
|
||||
|
||||
$service = app(DeviceStateService::class);
|
||||
$devices = $service->getUsersDevices($userIds);
|
||||
|
||||
$conn->send(json_encode([
|
||||
'event' => 'sync.devices',
|
||||
'data' => ['users' => $devices],
|
||||
]));
|
||||
|
||||
Log::debug("[WS] Node#{$nodeId} requested devices, sent " . count($devices) . " users");
|
||||
}
|
||||
|
||||
/**
|
||||
* Push device state to node
|
||||
*/
|
||||
public static function pushDeviceStateToNode(int $nodeId, DeviceStateService $service): void
|
||||
{
|
||||
$node = Server::find($nodeId);
|
||||
if (!$node) return;
|
||||
|
||||
$users = ServerService::getAvailableUsers($node);
|
||||
$userIds = $users->pluck('id')->toArray();
|
||||
$devices = $service->getUsersDevices($userIds);
|
||||
|
||||
NodeRegistry::send($nodeId, 'sync.devices', [
|
||||
'users' => $devices
|
||||
]);
|
||||
|
||||
Log::debug("[WS] Pushed device state to node#{$nodeId}: " . count($devices) . " users");
|
||||
}
|
||||
|
||||
/**
|
||||
* Push full config + users to newly connected node
|
||||
*/
|
||||
public static function pushFullSync(TcpConnection $conn, Server $node): void
|
||||
{
|
||||
$nodeId = $conn->nodeId;
|
||||
|
||||
// Push config
|
||||
$config = ServerService::buildNodeConfig($node);
|
||||
$conn->send(json_encode([
|
||||
'event' => 'sync.config',
|
||||
'data' => ['config' => $config]
|
||||
]));
|
||||
|
||||
// Push users
|
||||
$users = ServerService::getAvailableUsers($node)->toArray();
|
||||
$conn->send(json_encode([
|
||||
'event' => 'sync.users',
|
||||
'data' => ['users' => $users]
|
||||
]));
|
||||
|
||||
Log::info("[WS] Full sync pushed to node#{$nodeId}", [
|
||||
'users' => count($users),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user