diff --git a/config/config.php b/config/websockets.php similarity index 57% rename from config/config.php rename to config/websockets.php index 5461cab..85bdf28 100644 --- a/config/config.php +++ b/config/websockets.php @@ -1,5 +1,7 @@ null ], - /* - * TODO:: add client config - * - * Default: one item in the array with env PUSHER_APP_ID, _KEY, _SECRET - * - * Add notice app id should be numeric - * - * "clients": [ - { - "appId": "cbf9b001405e51d4", - "key": "d886dd1900a5911d00996b41638d7026" - "secret": - } - ], -` + /** + * This package comes with multi tenancy out of the box. Here you can + * configure the diffente clients that can use the webSockets server. * + * You should make sure that the app id is numeric. + */ 'clients' => [ - ...[] + [ + 'app_id' => env('WEBSOCKETS_APP_ID'), + 'app_key' => env('WEBSOCKETS_APP_KEY'), + 'app_secret' => env('WEBSOCKETS_APP_SECRET') + ], ], - 'client_provider' => ConfigProvider - */ - + /** + * This class is responsible for finding the clients. The default provider + * will use the clients defined in this config file. + * + * You can create a custom provider by implementing the + * `ClientProvier` interface. + */ + 'client_provider' => ConfigClientProvider::class, ]; \ No newline at end of file diff --git a/src/ClientProviders/Client.php b/src/ClientProviders/Client.php new file mode 100644 index 0000000..3834e33 --- /dev/null +++ b/src/ClientProviders/Client.php @@ -0,0 +1,46 @@ +findClient($appKey); + } + + public function __construct($appId, string $appKey, string $appSecret) + { + if (!is_numeric($appId)) { + throw InvalidClient::appIdIsNotNumeric($appId); + } + + if ($appKey === '') { + throw InvalidClient::valueIsRequired('appKey', $appId); + } + + if ($appSecret === '') { + throw InvalidClient::valueIsRequired('appSecret', $appId); + } + + $this->appId = $appId; + + $this->appKey = $appKey; + + $this->appSecret = $appSecret; + } + + +} \ No newline at end of file diff --git a/src/ClientProviders/ClientProvider.php b/src/ClientProviders/ClientProvider.php new file mode 100644 index 0000000..cd77b03 --- /dev/null +++ b/src/ClientProviders/ClientProvider.php @@ -0,0 +1,9 @@ +firstWhere('app_key', $appKey); + + if (! $client) { + return null; + } + + return new Client( + $client['app_id'], + $client['app_key'], + $client['app_secret'] + ); + } +} \ No newline at end of file diff --git a/src/Console/StartWebSocketServer.php b/src/Console/StartWebSocketServer.php index 0e857e8..8342b40 100644 --- a/src/Console/StartWebSocketServer.php +++ b/src/Console/StartWebSocketServer.php @@ -3,6 +3,7 @@ namespace BeyondCode\LaravelWebSockets\Console; use BeyondCode\LaravelWebSockets\Facades\WebSocketRouter; +use BeyondCode\LaravelWebSockets\Server\Logger; use Illuminate\Console\Command; use BeyondCode\LaravelWebSockets\Server\WebSocketServer; @@ -16,30 +17,47 @@ class StartWebSocketServer extends Command public function handle() { - // TODO: add an option to not start the echo server - WebSocketRouter::echo(); - - // TODO: add flag for verbose mode, to send more things to console - - $websocketServer = $this->createWebsocketServer(); - $websocketServer->run(); + $this + ->configureLogger() + ->registerEchoRoutes() + ->startWebSocketServer(); } - protected function createWebsocketServer(): WebSocketServer + protected function configureLogger() + { + app()->singleton(Logger::class, function() { + return (new Logger($this->output)) + ->enable(config('app.debug')) + //TODO: use real option + ->verbose($this->hasOption('vvv')); + }); + + return $this; + } + + protected function registerEchoRoutes() + { + WebSocketRouter::echo(); + + return $this; + } + + protected function startWebSocketServer() { $routes = WebSocketRouter::getRoutes(); $loop = LoopFactory::create(); $loop->futureTick(function () { - $this->info('Started the WebSocket server on port '.$this->option('port')); + $this->info("Started the WebSocket server on port {$this->option('port')}"); }); + /** 🎩 Start the magic 🎩 */ return (new WebSocketServer($routes)) ->setHost($this->option('host')) ->setPort($this->option('port')) ->setConsoleOutput($this->output) - ->enableLogging(config('app.debug')) - ->setLoop($loop); + ->setLoop($loop) + ->run(); } -} \ No newline at end of file +} diff --git a/src/Exceptions/InvalidClient.php b/src/Exceptions/InvalidClient.php new file mode 100644 index 0000000..d81260d --- /dev/null +++ b/src/Exceptions/InvalidClient.php @@ -0,0 +1,24 @@ +getUri()->getQuery(), $queryParameters); - // Todo: Lookup app-id for multi-tenancy support - if ($queryParameters['appKey'] !== config('broadcasting.connections.pusher.key')) { + if (! $client = Client::find($queryParameters['appKey'])) { throw new UnknownAppKey($queryParameters['appKey']); } - $connection->appId = config('broadcasting.connections.pusher.app_id'); + $connection->appId = $client->appId; } protected function establishConnection(ConnectionInterface $connection) diff --git a/src/LaravelWebSocketsServiceProvider.php b/src/LaravelWebSocketsServiceProvider.php index cb34e5a..c96fe8b 100644 --- a/src/LaravelWebSocketsServiceProvider.php +++ b/src/LaravelWebSocketsServiceProvider.php @@ -2,6 +2,7 @@ namespace BeyondCode\LaravelWebSockets; +use BeyondCode\LaravelWebSockets\ClientProviders\ClientProvider; use Illuminate\Support\ServiceProvider; use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager; @@ -10,7 +11,7 @@ class LaravelWebSocketsServiceProvider extends ServiceProvider public function boot() { $this->publishes([ - __DIR__.'/../config/config.php' => base_path('config/websockets.php'), + __DIR__.'/../config/websockets.php' => base_path('config/websockets.php'), ], 'config'); $this->commands([ @@ -20,7 +21,7 @@ class LaravelWebSocketsServiceProvider extends ServiceProvider public function register() { - $this->mergeConfigFrom(__DIR__.'/../config/config.php', 'websockets'); + $this->mergeConfigFrom(__DIR__.'/../config/websockets.php', 'websockets'); $this->app->singleton('websockets.router', function() { return new Router(); @@ -29,5 +30,9 @@ class LaravelWebSocketsServiceProvider extends ServiceProvider $this->app->singleton(ChannelManager::class, function() { return new ChannelManager(); }); + + $this->app->singleton(ClientProvider::class, function() { + return app(config('websockets.client_provider')); + }); } } diff --git a/src/Router.php b/src/Router.php index da9aa99..da36156 100644 --- a/src/Router.php +++ b/src/Router.php @@ -7,7 +7,6 @@ use Ratchet\WebSocket\WsServer; use Symfony\Component\Routing\Route; use Ratchet\Http\HttpServerInterface; use Symfony\Component\Routing\RouteCollection; -use Ratchet\WebSocket\MessageComponentInterface; use BeyondCode\LaravelWebSockets\Exceptions\InvalidWebSocketController; class Router @@ -82,12 +81,13 @@ class Router protected function wrapAction($action) { if (is_subclass_of($action, WebSocketController::class)) { - $app = app($action); - $appThatLogs = new Logger($app); + if (Logger::isEnabled()) { + $app = Logger::decorate($app); + } - return new WsServer($appThatLogs); + return new WsServer($app); } return app($action); diff --git a/src/Server/Logger.php b/src/Server/Logger.php index ef54d1e..600f447 100644 --- a/src/Server/Logger.php +++ b/src/Server/Logger.php @@ -27,22 +27,47 @@ class Logger implements MessageComponentInterface protected $consoleOutput; /** @var bool */ - protected $enabled; + protected $enabled = false; - public function __construct(MessageComponentInterface $app) + /** @var bool */ + protected $verbose = false; + + public static function decorate(MessageComponentInterface $app): Logger + { + $logger = app(Logger::class); + + return $logger->setApp($app); + } + + public static function isEnabled(): bool + { + return app(Logger::class)->enabled; + } + + public function __construct(OutputInterface $consoleOutput) + { + $this->consoleOutput = $consoleOutput; + } + + public function enable($enabled = true) + { + $this->enabled = $enabled; + + return $this; + } + + public function verbose($verbose = false) + { + $this->verbose = $verbose; + + return $this; + } + + public function setApp(MessageComponentInterface $app) { $this->app = $app; - /* - $this->consoleOutput = $consoleOutput; - - $this->enabled = $enabled; - */ - } - - public function enable() - { - $this->enabled = true; + return $this; } public function onOpen(ConnectionInterface $connection) @@ -75,14 +100,13 @@ class Logger implements MessageComponentInterface { $exceptionClass = get_class($exception); - $message = "{$connection->appId}: execption `{$exceptionClass}` thrown: `{$exception->getMessage()}`"; + $appId = $connection->appId ?? 'Unknown app id'; - /* - * TODO: add verbose option - if ($this->isVerbose) { + $message = "{$appId}: exception `{$exceptionClass}` thrown: `{$exception->getMessage()}`"; + + if ($this->verbose) { $message .= $exception->getTraceAsString(); } - */ $this->error($message); @@ -106,10 +130,6 @@ class Logger implements MessageComponentInterface protected function line(string $message, string $style) { - echo $message; - - return; - $styled = $style ? "<$style>$message" : $message; $this->consoleOutput->writeln($styled); diff --git a/src/Server/WebSocketServer.php b/src/Server/WebSocketServer.php index a457eea..241f914 100644 --- a/src/Server/WebSocketServer.php +++ b/src/Server/WebSocketServer.php @@ -31,8 +31,6 @@ class WebSocketServer /** @var Symfony\Component\Console\Output\OutputInterface */ protected $consoleOutput; - protected $enableLogging = false; - public function __construct(RouteCollection $routes) { $this->loop = LoopFactory::create(); @@ -68,13 +66,6 @@ class WebSocketServer return $this; } - public function enableLogging($enableLogging = true) - { - $this->enableLogging = $enableLogging; - - return $this; - } - public function run() { $server = $this->createServer();