2018-11-20 10:51:00 +00:00
|
|
|
<?php
|
|
|
|
|
|
2018-11-21 11:13:40 +00:00
|
|
|
namespace BeyondCode\LaravelWebSockets\Console;
|
2018-11-20 10:51:00 +00:00
|
|
|
|
2018-12-03 12:33:20 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Facades\StatisticsLogger;
|
2018-11-30 14:51:30 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Facades\WebSocketsRouter;
|
2020-08-14 12:35:36 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\PubSub\Drivers\LocalClient;
|
|
|
|
|
use BeyondCode\LaravelWebSockets\PubSub\Drivers\RedisClient;
|
2019-03-25 22:37:14 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface;
|
2018-12-04 21:22:33 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Server\Logger\ConnectionLogger;
|
2020-03-04 09:58:39 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Server\Logger\HttpLogger;
|
2018-11-30 14:52:11 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Server\Logger\WebsocketsLogger;
|
2020-03-04 09:58:39 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Server\WebSocketServerFactory;
|
|
|
|
|
use BeyondCode\LaravelWebSockets\Statistics\DnsResolver;
|
2018-12-03 15:29:47 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Statistics\Logger\StatisticsLogger as StatisticsLoggerInterface;
|
2020-03-04 09:58:39 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\WebSockets\Channels\ChannelManager;
|
|
|
|
|
use Clue\React\Buzz\Browser;
|
|
|
|
|
use Illuminate\Console\Command;
|
2019-11-06 08:25:55 +00:00
|
|
|
use Illuminate\Support\Facades\Cache;
|
2020-03-04 09:58:39 +00:00
|
|
|
use React\Dns\Config\Config as DnsConfig;
|
|
|
|
|
use React\Dns\Resolver\Factory as DnsFactory;
|
|
|
|
|
use React\Dns\Resolver\ResolverInterface;
|
|
|
|
|
use React\EventLoop\Factory as LoopFactory;
|
|
|
|
|
use React\Socket\Connector;
|
2018-12-03 15:29:47 +00:00
|
|
|
|
2018-11-20 10:51:00 +00:00
|
|
|
class StartWebSocketServer extends Command
|
|
|
|
|
{
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* The name and signature of the console command.
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
2020-08-13 11:21:06 +00:00
|
|
|
protected $signature = 'websockets:serve
|
|
|
|
|
{--host=0.0.0.0}
|
|
|
|
|
{--port=6001}
|
2020-08-19 06:00:53 +00:00
|
|
|
{--statistics-interval= : Overwrite the statistics interval set in the config.}
|
2020-08-13 11:21:06 +00:00
|
|
|
{--debug : Forces the loggers to be enabled and thereby overriding the APP_DEBUG setting.}
|
|
|
|
|
{--test : Prepare the server, but do not start it.}
|
|
|
|
|
';
|
2018-11-20 10:51:00 +00:00
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* The console command description.
|
|
|
|
|
*
|
|
|
|
|
* @var string|null
|
|
|
|
|
*/
|
2018-11-20 10:51:00 +00:00
|
|
|
protected $description = 'Start the Laravel WebSocket Server';
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Get the loop instance.
|
|
|
|
|
*
|
|
|
|
|
* @var \React\EventLoop\LoopInterface
|
|
|
|
|
*/
|
2018-12-03 12:33:20 +00:00
|
|
|
protected $loop;
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* The Pusher server instance.
|
|
|
|
|
*
|
|
|
|
|
* @var \Ratchet\Server\IoServer
|
|
|
|
|
*/
|
|
|
|
|
public $server;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Track the last restart.
|
|
|
|
|
*
|
|
|
|
|
* @var int
|
|
|
|
|
*/
|
2019-11-06 08:25:55 +00:00
|
|
|
protected $lastRestart;
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Initialize the command.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-12-03 12:33:20 +00:00
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
parent::__construct();
|
|
|
|
|
|
|
|
|
|
$this->loop = LoopFactory::create();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Run the command.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-11-20 10:51:00 +00:00
|
|
|
public function handle()
|
|
|
|
|
{
|
2018-11-24 00:25:40 +00:00
|
|
|
$this
|
2018-12-03 12:33:20 +00:00
|
|
|
->configureStatisticsLogger()
|
2018-11-27 20:30:33 +00:00
|
|
|
->configureHttpLogger()
|
2018-11-24 14:23:59 +00:00
|
|
|
->configureMessageLogger()
|
|
|
|
|
->configureConnectionLogger()
|
2019-11-06 08:25:55 +00:00
|
|
|
->configureRestartTimer()
|
2020-08-14 12:35:36 +00:00
|
|
|
->configurePubSub()
|
2020-08-18 17:21:22 +00:00
|
|
|
->registerRoutes()
|
2018-11-24 00:25:40 +00:00
|
|
|
->startWebSocketServer();
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Configure the statistics logger class.
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
2018-12-03 13:46:51 +00:00
|
|
|
protected function configureStatisticsLogger()
|
|
|
|
|
{
|
2018-12-03 20:44:43 +00:00
|
|
|
$connector = new Connector($this->loop, [
|
2018-12-10 09:31:19 +00:00
|
|
|
'dns' => $this->getDnsResolver(),
|
2020-08-13 10:34:12 +00:00
|
|
|
'tls' => config('websockets.statistics.tls'),
|
2018-12-03 20:44:43 +00:00
|
|
|
]);
|
2018-12-03 13:46:51 +00:00
|
|
|
|
2018-12-03 20:06:49 +00:00
|
|
|
$browser = new Browser($this->loop, $connector);
|
2018-12-03 13:46:51 +00:00
|
|
|
|
2019-03-29 14:51:13 +00:00
|
|
|
$this->laravel->singleton(StatisticsLoggerInterface::class, function () use ($browser) {
|
2020-08-19 06:00:53 +00:00
|
|
|
$class = config('websockets.statistics.logger', \BeyondCode\LaravelWebSockets\Statistics\Logger\MemoryStatisticsLogger::class);
|
2020-08-13 07:15:52 +00:00
|
|
|
|
2020-08-13 12:16:30 +00:00
|
|
|
return new $class(
|
|
|
|
|
$this->laravel->make(ChannelManager::class),
|
|
|
|
|
$browser
|
|
|
|
|
);
|
2018-12-03 13:46:51 +00:00
|
|
|
});
|
|
|
|
|
|
2020-08-19 06:00:53 +00:00
|
|
|
$this->loop->addPeriodicTimer($this->option('statistics-interval') ?: config('websockets.statistics.interval_in_seconds'), function () {
|
|
|
|
|
$this->line('Saving statistics...');
|
|
|
|
|
|
2018-12-03 20:02:21 +00:00
|
|
|
StatisticsLogger::save();
|
2018-12-03 13:46:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Configure the HTTP logger class.
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
2018-11-27 20:30:33 +00:00
|
|
|
protected function configureHttpLogger()
|
|
|
|
|
{
|
2019-03-29 14:51:13 +00:00
|
|
|
$this->laravel->singleton(HttpLogger::class, function () {
|
2018-11-27 20:30:33 +00:00
|
|
|
return (new HttpLogger($this->output))
|
2018-12-05 13:56:01 +00:00
|
|
|
->enable($this->option('debug') ?: config('app.debug'))
|
2018-11-27 20:30:33 +00:00
|
|
|
->verbose($this->output->isVerbose());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Configure the logger for messages.
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
2018-11-24 14:23:59 +00:00
|
|
|
protected function configureMessageLogger()
|
2018-11-24 00:25:40 +00:00
|
|
|
{
|
2019-03-29 14:51:13 +00:00
|
|
|
$this->laravel->singleton(WebsocketsLogger::class, function () {
|
2018-11-30 14:52:11 +00:00
|
|
|
return (new WebsocketsLogger($this->output))
|
2018-12-05 13:56:01 +00:00
|
|
|
->enable($this->option('debug') ?: config('app.debug'))
|
2018-11-26 07:55:08 +00:00
|
|
|
->verbose($this->output->isVerbose());
|
2018-11-24 14:23:59 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Configure the connection logger.
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
2018-11-24 14:23:59 +00:00
|
|
|
protected function configureConnectionLogger()
|
|
|
|
|
{
|
2019-03-29 14:51:13 +00:00
|
|
|
$this->laravel->bind(ConnectionLogger::class, function () {
|
2018-11-24 14:23:59 +00:00
|
|
|
return (new ConnectionLogger($this->output))
|
2018-11-24 00:25:40 +00:00
|
|
|
->enable(config('app.debug'))
|
2018-11-26 07:55:08 +00:00
|
|
|
->verbose($this->output->isVerbose());
|
2018-11-24 00:25:40 +00:00
|
|
|
});
|
2018-11-22 07:49:26 +00:00
|
|
|
|
2018-11-24 00:25:40 +00:00
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Configure the Redis PubSub handler.
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
2019-11-06 08:25:55 +00:00
|
|
|
public function configureRestartTimer()
|
|
|
|
|
{
|
|
|
|
|
$this->lastRestart = $this->getLastRestart();
|
|
|
|
|
|
|
|
|
|
$this->loop->addPeriodicTimer(10, function () {
|
|
|
|
|
if ($this->getLastRestart() !== $this->lastRestart) {
|
|
|
|
|
$this->loop->stop();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-14 12:35:36 +00:00
|
|
|
/**
|
|
|
|
|
* 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);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
$this->laravel
|
|
|
|
|
->get(ReplicationInterface::class)
|
|
|
|
|
->boot($this->loop);
|
2018-11-22 07:49:26 +00:00
|
|
|
|
2018-11-24 00:25:40 +00:00
|
|
|
return $this;
|
2018-11-22 07:49:26 +00:00
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Register the routes.
|
|
|
|
|
*
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
|
|
|
|
protected function registerRoutes()
|
2019-05-11 06:46:25 +00:00
|
|
|
{
|
2020-08-18 17:21:22 +00:00
|
|
|
WebSocketsRouter::routes();
|
2019-07-28 19:29:16 +00:00
|
|
|
|
2019-05-11 06:46:25 +00:00
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Start the server.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2018-11-24 00:25:40 +00:00
|
|
|
protected function startWebSocketServer()
|
2018-11-22 07:49:26 +00:00
|
|
|
{
|
2018-11-24 00:35:08 +00:00
|
|
|
$this->info("Starting the WebSocket server on port {$this->option('port')}...");
|
2018-11-20 10:51:00 +00:00
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
$this->buildServer();
|
2020-08-13 11:21:06 +00:00
|
|
|
|
2020-08-18 20:09:12 +00:00
|
|
|
// 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();
|
|
|
|
|
});
|
2020-08-13 11:21:06 +00:00
|
|
|
}
|
2020-08-18 20:09:12 +00:00
|
|
|
|
|
|
|
|
/* 🛰 Start the server 🛰 */
|
|
|
|
|
$this->server->run();
|
2018-11-20 10:51:00 +00:00
|
|
|
}
|
2018-12-10 09:31:19 +00:00
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Build the server instance.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
protected function buildServer()
|
2018-12-17 12:12:53 +00:00
|
|
|
{
|
2020-08-18 17:21:22 +00:00
|
|
|
$this->server = new WebSocketServerFactory(
|
|
|
|
|
$this->option('host'), $this->option('port')
|
|
|
|
|
);
|
2018-12-17 12:12:53 +00:00
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
$this->server = $this->server
|
|
|
|
|
->setLoop($this->loop)
|
|
|
|
|
->useRoutes(WebSocketsRouter::getRoutes())
|
|
|
|
|
->setConsoleOutput($this->output)
|
|
|
|
|
->createServer();
|
2018-12-17 12:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Create a DNS resolver for the stats manager.
|
|
|
|
|
*
|
|
|
|
|
* @return \React\Dns\Resolver\ResolverInterface
|
|
|
|
|
*/
|
2019-07-28 18:18:22 +00:00
|
|
|
protected function getDnsResolver(): ResolverInterface
|
2018-12-10 09:31:19 +00:00
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-11-06 08:25:55 +00:00
|
|
|
|
2020-08-18 17:21:22 +00:00
|
|
|
/**
|
|
|
|
|
* Get the last time the server restarted.
|
|
|
|
|
*
|
|
|
|
|
* @return int
|
|
|
|
|
*/
|
2019-11-06 08:25:55 +00:00
|
|
|
protected function getLastRestart()
|
|
|
|
|
{
|
|
|
|
|
return Cache::get('beyondcode:websockets:restart', 0);
|
|
|
|
|
}
|
2018-11-24 00:25:40 +00:00
|
|
|
}
|