diff --git a/composer.json b/composer.json index 38745f32..de2ab240 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,10 @@ "laravel": { "providers": [ "Laravel\\Reverb\\ServiceProvider" - ] + ], + "aliases": { + "Output": "Laravel\\Reverb\\Output" + } } }, "config": { diff --git a/src/Channels/Channel.php b/src/Channels/Channel.php index aed4d94a..8581ce11 100644 --- a/src/Channels/Channel.php +++ b/src/Channels/Channel.php @@ -7,6 +7,7 @@ use Laravel\Reverb\Application; use Laravel\Reverb\Contracts\ChannelManager; use Laravel\Reverb\Contracts\Connection; +use Laravel\Reverb\Output; class Channel { @@ -78,7 +79,8 @@ public function broadcast(Application $app, array $payload, Connection $except = try { $connection->send(json_encode($payload)); } catch (Exception $e) { - echo $e->getMessage().PHP_EOL; + Output::error('Broadcasting to '.$connection->id().' resulted in an error'); + Output::info($e->getMessage()); } }); } diff --git a/src/Console/Components/Message.php b/src/Console/Components/Message.php new file mode 100644 index 00000000..1348b567 --- /dev/null +++ b/src/Console/Components/Message.php @@ -0,0 +1,44 @@ +renderView('message', [ + 'message' => $message, + ], $verbosity); + } + + /** + * Compile the given view contents. + * + * @param string $view + * @param array $data + * @return void + */ + protected function compile($view, $data) + { + extract($data); + + ob_start(); + + include __DIR__."/views/$view.php"; + + return tap(ob_get_contents(), function () { + ob_end_clean(); + }); + } +} diff --git a/src/Console/Components/views/message.php b/src/Console/Components/views/message.php new file mode 100644 index 00000000..7261b536 --- /dev/null +++ b/src/Console/Components/views/message.php @@ -0,0 +1,5 @@ +
+ + + +
\ No newline at end of file diff --git a/src/Contracts/Logger.php b/src/Contracts/Logger.php new file mode 100644 index 00000000..08500b90 --- /dev/null +++ b/src/Contracts/Logger.php @@ -0,0 +1,39 @@ +components = new Factory($output); + } + + /** + * Log an infomational message. + * + * @param string $title + * @param string|null $message + * @return void + */ + public function info(string $title, ?string $message = null): void + { + $this->components->twoColumnDetail($title, $message); + } + + /** + * Log an error message. + * + * @param string $message + * @return void + */ + public function error(string $string): void + { + $this->output->error($string); + } + + /** + * Append a new line to the log. + * + * @param int $lines + * @return void + */ + public function line(?int $lines = 1): void + { + $this->output->newLine($lines); + } + + /** + * Log a message sent to the server. + * + * @param string $message + * @return void + */ + public function message(string $message): void + { + $message = json_decode($message, true); + + if (isset($message['data']['channel_data'])) { + $message['data']['channel_data'] = json_decode($message['data']['channel_data'], true); + } + + $message = json_encode($message, JSON_PRETTY_PRINT); + + with(new Message($this->output))->render( + $message + ); + } +} diff --git a/src/Loggers/NullLogger.php b/src/Loggers/NullLogger.php new file mode 100644 index 00000000..89b39dd2 --- /dev/null +++ b/src/Loggers/NullLogger.php @@ -0,0 +1,53 @@ +id()})".PHP_EOL; + Output::info('New Connection', $connection->id()); } /** @@ -36,7 +36,8 @@ public function open(Connection $connection) */ public function message(Connection $from, string $message) { - echo 'Message from '.$from->id().': '.$message.PHP_EOL; + Output::info('Message Received', $from->id()); + Output::message($message); $event = json_decode($message, true); @@ -51,11 +52,13 @@ public function message(Connection $from, string $message) default => ClientEvent::handle($from, $event) }; - echo 'Message from '.$from->id().' handled'.PHP_EOL; + Output::info('Message Handled', $from->id()); + Output::line(); } catch (PusherException $e) { $from->send(json_encode($e->payload())); - echo 'Message from '.$from->id().' resulted in a pusher error'.PHP_EOL; + Output::error('Message from '.$from->id().' resulted in a pusher error'); + Output::info($e->getMessage()); } catch (Exception $e) { $from->send(json_encode([ 'event' => 'pusher:error', @@ -65,8 +68,8 @@ public function message(Connection $from, string $message) ]), ])); - echo 'Message from '.$from->id().' resulted in an unknown error'.PHP_EOL; - echo $e->getMessage().PHP_EOL; + Output::error('Message from '.$from->id().' resulted in an unknown error'); + Output::info($e->getMessage()); } } @@ -82,7 +85,7 @@ public function close(Connection $connection) ->for($connection->app()) ->unsubscribeFromAll($connection); - echo "Disconnected: ({$connection->id()})".PHP_EOL; + Output::info('Connection closed', $connection->id()); } /** @@ -97,9 +100,20 @@ public function error(Connection $connection, Exception $exception) if ($exception instanceof PusherException) { $connection->send(json_encode($exception->payload())); - echo 'Message from '.$connection->id().' resulted in a pusher error'.PHP_EOL; + Output::error('Message from '.$connection->id().' resulted in a pusher error'); + + return Output::info($exception->getMessage()); } - echo 'Error: '.$exception->getMessage().PHP_EOL; + $connection->send(json_encode([ + 'event' => 'pusher:error', + 'data' => json_encode([ + 'code' => 4200, + 'message' => 'Invalid message format', + ]), + ])); + + Output::error('Message from '.$connection->id().' resulted in an unknown error'); + Output::info($exception->getMessage()); } } diff --git a/src/Servers/ApiGateway/Connection.php b/src/Servers/ApiGateway/Connection.php index 6ed8686a..495b5ce3 100644 --- a/src/Servers/ApiGateway/Connection.php +++ b/src/Servers/ApiGateway/Connection.php @@ -9,6 +9,7 @@ use Laravel\Reverb\Concerns\SerializesConnections; use Laravel\Reverb\Contracts\Connection as ConnectionInterface; use Laravel\Reverb\Contracts\SerializableConnection; +use Laravel\Reverb\Output; use Throwable; class Connection implements ConnectionInterface, SerializableConnection @@ -73,7 +74,8 @@ public function send(string $message): void 'Data' => $message, ]); } catch (Throwable $e) { - echo 'Unable to send message to connection: '.$e->getMessage(); + Output::error('Unable to send message.'); + Output::info($e->getMessage()); } }); } diff --git a/src/Servers/Ratchet/Connection.php b/src/Servers/Ratchet/Connection.php index f7642089..4b340cca 100644 --- a/src/Servers/Ratchet/Connection.php +++ b/src/Servers/Ratchet/Connection.php @@ -5,6 +5,7 @@ use Laravel\Reverb\Application; use Laravel\Reverb\Concerns\GeneratesPusherIdentifiers; use Laravel\Reverb\Contracts\Connection as ConnectionInterface; +use Laravel\Reverb\Output; use Ratchet\ConnectionInterface as RatchetConnectionInterface; use Throwable; @@ -60,7 +61,8 @@ public function send(string $message): void try { $this->connection->send($message); } catch (Throwable $e) { - echo 'Unable to send message to connection: '.$e->getMessage(); + Output::error('Unable to send message.'); + Output::info($e->getMessage()); } } diff --git a/src/Servers/Ratchet/Console/Commands/StartServer.php b/src/Servers/Ratchet/Console/Commands/StartServer.php index 9015272c..d3cfbeee 100644 --- a/src/Servers/Ratchet/Console/Commands/StartServer.php +++ b/src/Servers/Ratchet/Console/Commands/StartServer.php @@ -7,9 +7,11 @@ use Exception; use Illuminate\Console\Command; use Laravel\Reverb\Channels\Channel; +use Laravel\Reverb\Contracts\Logger; use Laravel\Reverb\Event; use Laravel\Reverb\Http\Controllers\EventController; use Laravel\Reverb\Http\Controllers\StatsController; +use Laravel\Reverb\Loggers\CliLogger; use Laravel\Reverb\Server as ReverbServer; use Laravel\Reverb\Servers\Ratchet\Server; use Ratchet\Http\HttpServer; @@ -49,6 +51,8 @@ class StartServer extends Command */ public function handle() { + $this->laravel->instance(Logger::class, new CliLogger($this->output)); + $config = $this->laravel['config']['reverb.servers.ratchet']; $host = $this->option('host') ?: $config['host']; $port = $this->option('port') ?: $config['port']; @@ -138,7 +142,7 @@ protected function subscribe(LoopInterface $loop): void $redis->subscribe($config['channel']); $redis->on('error', function (Exception $e) { - echo 'Error: '.$e->getMessage().PHP_EOL; + $this->components->error($e->getMessage()); }); $redis->on('message', function (string $channel, string $payload) { diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 531beb4c..9f542377 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -6,6 +6,8 @@ use InvalidArgumentException; use Laravel\Reverb\Console\Commands\StartServer; use Laravel\Reverb\Contracts\ChannelManager as ChannelManagerInterface; +use Laravel\Reverb\Contracts\Logger; +use Laravel\Reverb\Loggers\StandardLogger; use Laravel\Reverb\Managers\ChannelManager; use Laravel\Reverb\Servers\ApiGateway\ServiceProvider as ApiGatewayServiceProvider; use Laravel\Reverb\Servers\Ratchet\ServiceProvider as RatchetServiceProvider; @@ -42,6 +44,8 @@ public function register() ); }); + $this->app->instance(Logger::class, new StandardLogger); + $this->app->register( $this->getServerProvider($config['default']) ); diff --git a/tests/TestCase.php b/tests/TestCase.php index bf95d313..67429c5f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,11 +2,23 @@ namespace Laravel\Reverb\Tests; +use Laravel\Reverb\Contracts\Logger; +use Laravel\Reverb\Loggers\NullLogger; use Laravel\Reverb\ServiceProvider; use Orchestra\Testbench\TestCase as TestbenchTestCase; class TestCase extends TestbenchTestCase { + /** + * Setup the test environment. + */ + protected function setUp(): void + { + parent::setUp(); + + $this->app->instance(Logger::class, new NullLogger); + } + /** * Get package providers. *