loop = LoopFactory::create(); } /** * Run the command. * * @return void */ public function handle() { $this ->configureStatisticsLogger() ->configureHttpLogger() ->configureMessageLogger() ->configureConnectionLogger() ->configureRestartTimer() ->configurePubSub() ->registerRoutes() ->startWebSocketServer(); } /** * Configure the statistics logger class. * * @return $this */ protected function configureStatisticsLogger() { $connector = new Connector($this->loop, [ 'dns' => $this->getDnsResolver(), 'tls' => config('websockets.statistics.tls'), ]); $browser = new Browser($this->loop, $connector); $this->laravel->singleton(StatisticsLoggerInterface::class, function () use ($browser) { $class = config('websockets.statistics.logger', \BeyondCode\LaravelWebSockets\Statistics\Logger\MemoryStatisticsLogger::class); return new $class( $this->laravel->make(ChannelManager::class), $browser ); }); $this->loop->addPeriodicTimer($this->option('statistics-interval') ?: config('websockets.statistics.interval_in_seconds'), function () { $this->line('Saving statistics...'); StatisticsLogger::save(); }); return $this; } /** * Configure the HTTP logger class. * * @return $this */ protected function configureHttpLogger() { $this->laravel->singleton(HttpLogger::class, function () { return (new HttpLogger($this->output)) ->enable($this->option('debug') ?: config('app.debug')) ->verbose($this->output->isVerbose()); }); return $this; } /** * Configure the logger for messages. * * @return $this */ protected function configureMessageLogger() { $this->laravel->singleton(WebsocketsLogger::class, function () { return (new WebsocketsLogger($this->output)) ->enable($this->option('debug') ?: config('app.debug')) ->verbose($this->output->isVerbose()); }); return $this; } /** * Configure the connection logger. * * @return $this */ protected function configureConnectionLogger() { $this->laravel->bind(ConnectionLogger::class, function () { return (new ConnectionLogger($this->output)) ->enable(config('app.debug')) ->verbose($this->output->isVerbose()); }); return $this; } /** * Configure the Redis PubSub handler. * * @return $this */ public function configureRestartTimer() { $this->lastRestart = $this->getLastRestart(); $this->loop->addPeriodicTimer(10, function () { if ($this->getLastRestart() !== $this->lastRestart) { $this->loop->stop(); } }); return $this; } /** * Configure the replicators. * * @return void */ public function configurePubSub() { if (config('websockets.replication.driver', 'local') === 'local') { $this->laravel->singleton(ReplicationInterface::class, function () { return new LocalClient; }); } if (config('websockets.replication.driver', 'local') === 'redis') { $this->laravel->singleton(ReplicationInterface::class, function () { return (new RedisClient)->boot($this->loop); }); } $this->laravel ->get(ReplicationInterface::class) ->boot($this->loop); return $this; } /** * Register the routes. * * @return $this */ protected function registerRoutes() { WebSocketsRouter::routes(); return $this; } /** * Start the server. * * @return void */ protected function startWebSocketServer() { $this->info("Starting the WebSocket server on port {$this->option('port')}..."); $this->buildServer(); // For testing, just boot up the server, run it // but exit after the next tick. if ($this->option('test')) { $this->loop->futureTick(function () { $this->loop->stop(); }); } /* 🛰 Start the server 🛰 */ $this->server->run(); } /** * Build the server instance. * * @return void */ protected function buildServer() { $this->server = new WebSocketServerFactory( $this->option('host'), $this->option('port') ); $this->server = $this->server ->setLoop($this->loop) ->useRoutes(WebSocketsRouter::getRoutes()) ->setConsoleOutput($this->output) ->createServer(); } /** * Create a DNS resolver for the stats manager. * * @return \React\Dns\Resolver\ResolverInterface */ protected function getDnsResolver(): ResolverInterface { if (! config('websockets.statistics.perform_dns_lookup')) { return new DnsResolver; } $dnsConfig = DnsConfig::loadSystemConfigBlocking(); return (new DnsFactory)->createCached( $dnsConfig->nameservers ? reset($dnsConfig->nameservers) : '1.1.1.1', $this->loop ); } /** * Get the last time the server restarted. * * @return int */ protected function getLastRestart() { return Cache::get('beyondcode:websockets:restart', 0); } }