Showing
1 changed file
with
71 additions
and
46 deletions
| @@ -62,46 +62,50 @@ $config = require __DIR__ . '/config.php'; | @@ -62,46 +62,50 @@ $config = require __DIR__ . '/config.php'; | ||
| 62 | // Define Heartbeat Interval | 62 | // Define Heartbeat Interval |
| 63 | define('HEARTBEAT_TIME', $config['heartbeat']['interval']); | 63 | define('HEARTBEAT_TIME', $config['heartbeat']['interval']); |
| 64 | 64 | ||
| 65 | -// Database Connection | ||
| 66 | -$pdo = null; | ||
| 67 | -try { | ||
| 68 | - $db_config = $config['database']; | ||
| 69 | - $dsn = "mysql:host={$db_config['host']};port={$db_config['port']};dbname={$db_config['database']};charset=utf8mb4"; | ||
| 70 | - $pdo = new PDO($dsn, $db_config['username'], $db_config['password'], [ | ||
| 71 | - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, | ||
| 72 | - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC | ||
| 73 | - ]); | ||
| 74 | - echo "✅ Connected to MySQL at {$db_config['host']}:{$db_config['port']}\n"; | ||
| 75 | -} catch (Exception $e) { | ||
| 76 | - echo "⚠️ MySQL Connection Failed: " . $e->getMessage() . "\n"; | ||
| 77 | -} | ||
| 78 | - | ||
| 79 | -// Redis Connection | ||
| 80 | -$redis = null; | ||
| 81 | -try { | ||
| 82 | - $redis_config = $config['redis']; | ||
| 83 | - | ||
| 84 | - $params = [ | ||
| 85 | - 'scheme' => 'tcp', | ||
| 86 | - 'host' => $redis_config['host'], | ||
| 87 | - 'port' => $redis_config['port'], | ||
| 88 | - ]; | 65 | +// --------------------------------------------------------- |
| 66 | +// Helper: Initialize Connections & Services | ||
| 67 | +// --------------------------------------------------------- | ||
| 68 | +$initConnections = function($config) { | ||
| 69 | + // Database Connection | ||
| 70 | + $pdo = null; | ||
| 71 | + try { | ||
| 72 | + $db_config = $config['database']; | ||
| 73 | + $dsn = "mysql:host={$db_config['host']};port={$db_config['port']};dbname={$db_config['database']};charset=utf8mb4"; | ||
| 74 | + $pdo = new PDO($dsn, $db_config['username'], $db_config['password'], [ | ||
| 75 | + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, | ||
| 76 | + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, | ||
| 77 | + PDO::ATTR_TIMEOUT => 5, | ||
| 78 | + ]); | ||
| 79 | + echo "✅ Connected to MySQL at {$db_config['host']}:{$db_config['port']}\n"; | ||
| 80 | + } catch (Exception $e) { | ||
| 81 | + echo "⚠️ MySQL Connection Failed: " . $e->getMessage() . "\n"; | ||
| 82 | + } | ||
| 89 | 83 | ||
| 90 | - if (!empty($redis_config['password'])) { | ||
| 91 | - $params['password'] = $redis_config['password']; | 84 | + // Redis Connection |
| 85 | + $redis = null; | ||
| 86 | + try { | ||
| 87 | + $redis_config = $config['redis']; | ||
| 88 | + $params = [ | ||
| 89 | + 'scheme' => 'tcp', | ||
| 90 | + 'host' => $redis_config['host'], | ||
| 91 | + 'port' => $redis_config['port'], | ||
| 92 | + ]; | ||
| 93 | + if (!empty($redis_config['password'])) { | ||
| 94 | + $params['password'] = $redis_config['password']; | ||
| 95 | + } | ||
| 96 | + $redis = new Predis\Client($params, ['prefix' => $redis_config['prefix']]); | ||
| 97 | + $redis->connect(); | ||
| 98 | + echo "✅ Connected to Redis at {$redis_config['host']}:{$redis_config['port']} ({$redis_config['prefix']})\n"; | ||
| 99 | + } catch (Exception $e) { | ||
| 100 | + echo "⚠️ Redis Connection Failed: " . $e->getMessage() . "\n"; | ||
| 92 | } | 101 | } |
| 93 | 102 | ||
| 94 | - // Predis Client | ||
| 95 | - $redis = new Predis\Client($params, ['prefix' => $redis_config['prefix']]); | ||
| 96 | - $redis->connect(); | ||
| 97 | - echo "✅ Connected to Redis at {$redis_config['host']}:{$redis_config['port']} ({$redis_config['prefix']})\n"; | ||
| 98 | -} catch (Exception $e) { | ||
| 99 | - echo "⚠️ Redis Connection Failed: " . $e->getMessage() . "\n"; | ||
| 100 | -} | 103 | + // Initialize Services |
| 104 | + $authService = $pdo ? new AuthService($pdo, $config, $redis) : null; | ||
| 105 | + $deviceService = $pdo ? new DeviceService($pdo, $config) : null; | ||
| 101 | 106 | ||
| 102 | -// Initialize Services | ||
| 103 | -$authService = $pdo ? new AuthService($pdo, $config, $redis) : null; | ||
| 104 | -$deviceService = $pdo ? new DeviceService($pdo, $config) : null; | 107 | + return [$pdo, $redis, $authService, $deviceService]; |
| 108 | +}; | ||
| 105 | 109 | ||
| 106 | // Create a WebSocket worker | 110 | // Create a WebSocket worker |
| 107 | $ws_host = $config['server']['websocket_host']; | 111 | $ws_host = $config['server']['websocket_host']; |
| @@ -112,7 +116,11 @@ $ws_worker = new Worker("websocket://{$ws_host}:{$ws_port}"); | @@ -112,7 +116,11 @@ $ws_worker = new Worker("websocket://{$ws_host}:{$ws_port}"); | ||
| 112 | $clients = []; // ClientID -> Connection | 116 | $clients = []; // ClientID -> Connection |
| 113 | $devices = []; // DeviceID -> Connection | 117 | $devices = []; // DeviceID -> Connection |
| 114 | 118 | ||
| 115 | -$ws_worker->onWorkerStart = function ($worker) use ($config) { | 119 | +$ws_worker->onWorkerStart = function ($worker) use ($config, $initConnections) { |
| 120 | + // Each worker process needs its own connection | ||
| 121 | + global $pdo, $redis, $authService, $deviceService; | ||
| 122 | + list($pdo, $redis, $authService, $deviceService) = $initConnections($config); | ||
| 123 | + | ||
| 116 | $ws_host = $config['server']['websocket_host']; | 124 | $ws_host = $config['server']['websocket_host']; |
| 117 | $ws_port = $config['server']['websocket_port']; | 125 | $ws_port = $config['server']['websocket_port']; |
| 118 | echo "Relay Server Started on {$ws_host}:{$ws_port}\n"; | 126 | echo "Relay Server Started on {$ws_host}:{$ws_port}\n"; |
| @@ -123,14 +131,23 @@ $ws_worker->onWorkerStart = function ($worker) use ($config) { | @@ -123,14 +131,23 @@ $ws_worker->onWorkerStart = function ($worker) use ($config) { | ||
| 123 | file_put_contents(__DIR__ . '/debug.log', $logMsg, FILE_APPEND); | 131 | file_put_contents(__DIR__ . '/debug.log', $logMsg, FILE_APPEND); |
| 124 | echo $logMsg; // Keep echo just in case | 132 | echo $logMsg; // Keep echo just in case |
| 125 | 133 | ||
| 126 | - // Heartbeat check | 134 | + // MySQL Heartbeat to prevent "MySQL server has gone away" |
| 135 | + Timer::add(60, function() use (&$pdo) { | ||
| 136 | + if ($pdo) { | ||
| 137 | + try { | ||
| 138 | + $pdo->query('SELECT 1'); | ||
| 139 | + } catch (Exception $e) { | ||
| 140 | + // Connection lost, will attempt to reconnect on next needed activity if handled, | ||
| 141 | + // but Workerman long-running processes prefer proactive ping | ||
| 142 | + echo "⚠️ Database heartbeat failed: " . $e->getMessage() . "\n"; | ||
| 143 | + } | ||
| 144 | + } | ||
| 145 | + }); | ||
| 146 | + | ||
| 147 | + // Heartbeat check for connections | ||
| 127 | $check_interval = $config['heartbeat']['check_interval']; | 148 | $check_interval = $config['heartbeat']['check_interval']; |
| 128 | Timer::add($check_interval, function () use ($worker) { | 149 | Timer::add($check_interval, function () use ($worker) { |
| 129 | - $time_now = time(); | ||
| 130 | - foreach ($worker->connections as $connection) { | ||
| 131 | - // Check if connection is alive possibly? | ||
| 132 | - // Workerman handles basic disconnects, but we can enforce ping logic here if needed | ||
| 133 | - } | 150 | + // ...Existing connection check logic (if any) |
| 134 | }); | 151 | }); |
| 135 | }; | 152 | }; |
| 136 | 153 | ||
| @@ -139,7 +156,8 @@ $ws_worker->onConnect = function ($connection) { | @@ -139,7 +156,8 @@ $ws_worker->onConnect = function ($connection) { | ||
| 139 | $connection->authVerified = false; | 156 | $connection->authVerified = false; |
| 140 | }; | 157 | }; |
| 141 | 158 | ||
| 142 | -$ws_worker->onMessage = function ($connection, $data) use (&$clients, &$devices, $authService, $deviceService) { | 159 | +$ws_worker->onMessage = function ($connection, $data) use (&$clients, &$devices, $config) { |
| 160 | + global $authService, $deviceService; | ||
| 143 | $msg = json_decode($data, true); | 161 | $msg = json_decode($data, true); |
| 144 | if (!$msg || !isset($msg['type'])) { | 162 | if (!$msg || !isset($msg['type'])) { |
| 145 | return; | 163 | return; |
| @@ -280,7 +298,8 @@ $ws_worker->onMessage = function ($connection, $data) use (&$clients, &$devices, | @@ -280,7 +298,8 @@ $ws_worker->onMessage = function ($connection, $data) use (&$clients, &$devices, | ||
| 280 | } | 298 | } |
| 281 | }; | 299 | }; |
| 282 | 300 | ||
| 283 | -$ws_worker->onClose = function ($connection) use (&$clients, &$devices, $deviceService) { | 301 | +$ws_worker->onClose = function ($connection) use (&$clients, &$devices) { |
| 302 | + global $deviceService; | ||
| 284 | if (isset($connection->role)) { | 303 | if (isset($connection->role)) { |
| 285 | if ($connection->role === 'device' && isset($connection->deviceId)) { | 304 | if ($connection->role === 'device' && isset($connection->deviceId)) { |
| 286 | unset($devices[$connection->deviceId]); | 305 | unset($devices[$connection->deviceId]); |
| @@ -303,7 +322,13 @@ $http_host = $config['server']['http_host']; | @@ -303,7 +322,13 @@ $http_host = $config['server']['http_host']; | ||
| 303 | $http_port = $config['server']['http_port']; | 322 | $http_port = $config['server']['http_port']; |
| 304 | $http_worker = new Worker("http://{$http_host}:{$http_port}"); | 323 | $http_worker = new Worker("http://{$http_host}:{$http_port}"); |
| 305 | $http_worker->count = $config['server']['worker_count']; | 324 | $http_worker->count = $config['server']['worker_count']; |
| 306 | -$http_worker->onMessage = function ($connection, $request) use ($config, $authService, $deviceService) { | 325 | +$http_worker->onWorkerStart = function($worker) use ($config, $initConnections) { |
| 326 | + global $pdo, $redis, $authService, $deviceService; | ||
| 327 | + list($pdo, $redis, $authService, $deviceService) = $initConnections($config); | ||
| 328 | +}; | ||
| 329 | + | ||
| 330 | +$http_worker->onMessage = function ($connection, $request) use ($config) { | ||
| 331 | + global $authService, $deviceService; | ||
| 307 | $path = $request->path(); | 332 | $path = $request->path(); |
| 308 | $method = $request->method(); | 333 | $method = $request->method(); |
| 309 | 334 |
Please
register
or
login
to post a comment