From 6f115a2a72effb6fe2a6def64c64cb2055929dcd Mon Sep 17 00:00:00 2001 From: a6a2f5842 Date: Thu, 8 May 2025 10:54:11 +0200 Subject: [PATCH] A more default settings --- config/websockets.php | 2 +- src/Console/Commands/StartServer.php | 26 ++++++++++++++--- src/Events/WebsocketMessageEvent.php | 36 +++++++++++++++++++++++ src/Services/WebsocketService.php | 22 ++++++++++++++ src/WebSocketsServiceProvider.php | 13 +++++++++ src/Websocket/Handler.php | 43 +++++++++------------------- 6 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 src/Events/WebsocketMessageEvent.php create mode 100644 src/Services/WebsocketService.php diff --git a/config/websockets.php b/config/websockets.php index c1333bb..c3c14e7 100644 --- a/config/websockets.php +++ b/config/websockets.php @@ -170,7 +170,7 @@ return [ | */ - 'delete_statistics_older_than_days' => 60, + 'delete_statistics_older_than_days' => 7, ], diff --git a/src/Console/Commands/StartServer.php b/src/Console/Commands/StartServer.php index f97e363..9cd2636 100644 --- a/src/Console/Commands/StartServer.php +++ b/src/Console/Commands/StartServer.php @@ -27,7 +27,8 @@ class StartServer extends Command protected $signature = 'websockets:serve {--host=0.0.0.0} {--port=6001} - {--disable-statistics : Disable the statistics tracking.} + {--cache-driver=file : The cache driver to use for the server. Redis will not work due to concurrency issues.} + {--disable-statistics=true : Disable the statistics tracking.} {--statistics-interval= : The amount of seconds to tick between statistics saving.} {--debug : Forces the loggers to be enabled and thereby overriding the APP_DEBUG setting.} {--loop : Programatically inject the loop.} @@ -73,6 +74,21 @@ class StartServer extends Command */ public function handle() { + $this->components->info('Handling websocket server with pid ' . getmypid() . '...'); + + // For is_fork() helper + if (! defined('LARAVEL_PARENT_PID')) { + define('LARAVEL_PARENT_PID', getmypid()); + } + + // For is_websocket() helper + if (! defined('LARAVEL_IS_WEBSOCKET')) { + define('LARAVEL_IS_WEBSOCKET', true); + } + + // Fixes redis concurrency issues + config(['cache.default' => $this->option('cache-driver', 'file')]); + $this->laravel->singleton(LoopInterface::class, function () { return $this->loop; }); @@ -182,7 +198,7 @@ class StartServer extends Command // then stopping the loop. if (! extension_loaded('pcntl')) { - return; + throw new \RuntimeException('The pcntl extension is required to handle concurrency.'); } $this->loop->addSignal(SIGTERM, function () { @@ -279,7 +295,8 @@ class StartServer extends Command protected function buildServer() { $this->server = new ServerFactory( - $this->option('host'), $this->option('port') + $this->option('host'), + $this->option('port') ); if ($loop = $this->option('loop')) { @@ -301,7 +318,8 @@ class StartServer extends Command protected function getLastRestart() { return Cache::get( - 'blax:websockets:restart', 0 + 'blax:websockets:restart', + 0 ); } diff --git a/src/Events/WebsocketMessageEvent.php b/src/Events/WebsocketMessageEvent.php new file mode 100644 index 0000000..755c655 --- /dev/null +++ b/src/Events/WebsocketMessageEvent.php @@ -0,0 +1,36 @@ +data; + } + + public function broadcastAs() + { + return $this->event; + } +} diff --git a/src/Services/WebsocketService.php b/src/Services/WebsocketService.php new file mode 100644 index 0000000..e76e5e3 --- /dev/null +++ b/src/Services/WebsocketService.php @@ -0,0 +1,22 @@ +tenantable)->public_id, + // $d['event'], + // (is_array($d['data'])) + // ? $d['data'] + // : ['data' => $d['data']] + // ); + } +} diff --git a/src/WebSocketsServiceProvider.php b/src/WebSocketsServiceProvider.php index 4ac9929..e6de587 100644 --- a/src/WebSocketsServiceProvider.php +++ b/src/WebSocketsServiceProvider.php @@ -47,6 +47,8 @@ class WebSocketsServiceProvider extends ServiceProvider __DIR__.'/Websocket' => app_path('Websocket') ]); + $this->registerDefaultWebsocketChannels(); + $this->registerEventLoop(); $this->registerSQLiteDatabase(); @@ -78,6 +80,17 @@ class WebSocketsServiceProvider extends ServiceProvider // } + + /** + * Registers Broadcast::channel('websocket', fn () => true); in channels.php + * + * @return void + */ + protected function registerDefaultWebsocketChannels() + { + \Illuminate\Support\Facades\Broadcast::channel('websocket', fn() => true); + } + protected function registerEventLoop() { $this->app->singleton(LoopInterface::class, function () { diff --git a/src/Websocket/Handler.php b/src/Websocket/Handler.php index 64e0347..3281a18 100644 --- a/src/Websocket/Handler.php +++ b/src/Websocket/Handler.php @@ -19,6 +19,7 @@ use BlaxSoftware\LaravelWebSockets\Server\Exceptions\WebSocketException as Excep use BlaxSoftware\LaravelWebSockets\Server\Messages\PusherMessageFactory; use BlaxSoftware\LaravelWebSockets\Server\QueryParameters; use Exception; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use Ratchet\ConnectionInterface; @@ -160,14 +161,6 @@ class Handler implements MessageComponentInterface */ public function onClose(ConnectionInterface $connection): void { - if (optional($connection)->tenant) { - if (optional($connection->tenant)->tenantable) { - $connection->tenant->tenantable->logActivity('Disconnected from websocket', $connection->tenant->tenantable, 'info', 'websocket'); - } else { - $connection->tenant->logActivity('Disconnected from websocket', $connection->tenant, 'info', 'websocket'); - } - } - // remove connection from $channel_connections foreach ($this->channel_connections as $channel => $connections) { if (in_array($connection->socketId, $connections)) { @@ -179,16 +172,16 @@ class Handler implements MessageComponentInterface } cache()->forget( - 'ws_socket_tenantable_'.$connection->socketId, + 'ws_socket_tenantable_' . $connection->socketId, ); if (@$this->channel_connections[$channel]) { cache()->forever( - 'ws_channel_connections_'.$channel, + 'ws_channel_connections_' . $channel, @$this->channel_connections[$channel] ); } else { - cache()->forget('ws_channel_connections_'.$channel); + cache()->forget('ws_channel_connections_' . $channel); } cache()->forever( @@ -205,7 +198,7 @@ class Handler implements MessageComponentInterface ConnectionClosed::dispatch($connection->app->id, $connection->socketId); - cache()->forget('ws_connection_'.$connection->socketId); + cache()->forget('ws_connection_' . $connection->socketId); } }); } @@ -413,22 +406,6 @@ class Handler implements MessageComponentInterface request()->offsetUnset($key); } - if (optional($connection)->tenant) { - request()->merge([ - 'tenant' => $connection->tenant ?? null, - 'tenantable' => $connection->tenant->tenantable ?? null, - 'user' => optional($connection->tenant)->tenantable instanceof \App\Models\User ? $connection->tenant->tenantable : null, - 'organization' => optional($connection->tenant)->organization, - 'organization_id' => optional($connection->tenant)->organization_id, - ]); - } else { - request()->offsetUnset('tenant'); - request()->offsetUnset('tenantable'); - request()->offsetUnset('user'); - request()->offsetUnset('organization'); - request()->offsetUnset('organization_id'); - } - request()->merge(@$message['data'] ?? []); } @@ -455,8 +432,14 @@ class Handler implements MessageComponentInterface // Set auth or logout ($connection->user) - ? auth()->login($connection->user) - : auth()->logout(); + ? Auth::login($connection->user) + : Auth::logout(); + + if (Auth::user()) { + /** @var \App\Models\User */ + $user = Auth::user(); + $user->refresh(); + } } private function addDataCheckLoop(