diff --git a/composer.json b/composer.json index 64b6d48..7ce2fd3 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "socketstream" ], "type": "library", - "version": "v1.1.0", + "version": "v1.2.0", "license": "MIT", "authors": [ { @@ -36,7 +36,8 @@ "autoload": { "psr-4": { "MatviiB\\Notifier\\": "src/" - } + }, + "files": ["src/helper_connector.php"] }, "extra": { "laravel": { diff --git a/readme.md b/readme.md index db70e54..a8798cf 100644 --- a/readme.md +++ b/readme.md @@ -5,9 +5,22 @@

### Usage Example -#### For example send new values to chart on some page synchronously to each user. +#### Send new values to chart on some page synchronously to each user: +#### `event(new Notify($data, ['chart']));` +#### Or to users with `id` 3 and 5: `event(new Notify($data, ['chart'], [3, 5]));` ![laravel socket server](https://gitlab.com/MatviiB/assets/raw/master/ezgif.com-video-to-gif.gif) +### Base concepts +This package sends data ONLY to named routes declared as `GET`. + +To view available routes you can run `php artisan notifier:init show` command. It will display available routes in the table and initiate the socket server. + +`event(new Notify($data));` - send to all routes. + +`event(new Notify($data, $routes));` - send to routes in `$routes` array. + +`event(new Notify($data, $routes, $users));` - send to routes in `$routes` and only to users in `$users`. + ### Installation ``` @@ -51,17 +64,11 @@ Also you can run `php artisan notifier:init show` - this command will show you l ### Usage -At first you need to add `@include('notifier::connect')` before than you will use `socket.addEventListener()` to your view or main layout to use on the ALL pages. - -Anywhere in your application add next event to send data to array of NAMED ROUTES. Example: +At first you need to add `@include('notifier::connect')` before you'll use `socket.addEventListener()` to your view or main layout to use it with ALL pages. -`event(new Notify($data, ['chart', 'index']));` +Anywhere in your application add next event: -Event WITHOUT array of routes will send data to EACH page which are listen the sockets. Example: - -`event(new Notify($data));` - -Event with urls instead of named routes WILL NOT WORK. +`event(new Notify($data, ['some-route-name']));` On front-end part add event listener ``` @@ -147,9 +154,3 @@ Run: `php artisan notifier:init` Run in another shell: `php artisan test` Open `/chart` page. - -## Will develop next - -Add abillity to send messages to special user. - -`event(new Notify($data, $routes, $users));` diff --git a/src/Commands/Notifier.php b/src/Commands/Notifier.php index 32362eb..773180b 100644 --- a/src/Commands/Notifier.php +++ b/src/Commands/Notifier.php @@ -2,6 +2,7 @@ namespace MatviiB\Notifier\Commands; +use Cache; use Closure; use Illuminate\Routing\Router; use Illuminate\Console\Command; @@ -49,7 +50,28 @@ class Notifier extends Command * * @var array */ - protected $headers = ['Method', 'Name', 'Middleware']; + private $headers = ['Method', 'Name', 'Middleware']; + + /** + * Socket connections. + * + * @var array + */ + private $connects; + + /** + * Connections to pages. + * + * @array + */ + private $per_pages; + + /** + * Connections to users. + * + * @array + */ + private $per_users; /** * Create a new command instance. @@ -62,7 +84,9 @@ public function __construct(Router $router) $this->server = new SocketServer(); $this->router = $router; - $this->routes = $router->getRoutes(); + $this->routes = $this->getRoutes(); + + $this->connects = $this->per_pages = $this->per_users = []; } /** @@ -72,19 +96,14 @@ public function __construct(Router $router) */ public function handle() { - $routes = $this->getRoutes(); - if ($this->argument('show')) { - $this->displayRoutes($routes); + $this->displayRoutes(); } $socket = $this->server->init(); - $connects = []; - $per_pages = []; - while (true) { - $read = $connects; + $read = $this->connects; $read[] = $socket; $write = $except = []; @@ -94,25 +113,8 @@ public function handle() if (in_array($socket, $read) && ($connection = stream_socket_accept($socket, -1))) { - $info = $this->server->handshake($connection); - - if ($info) { - if (isset($info['Socket-pass']) && $info['Socket-pass'] === config('notifier.socket_pass')) { - foreach ($connects as $key => $c) { - if (isset($per_pages[$key])) { - if (isset($info['Routes'])) { - if (in_array($per_pages[$key], json_decode($info['Routes']))) { - fwrite($c, $this->server->encode($info['Payload'])); - } - } elseif (!isset($info['Route'])) { - fwrite($c, $this->server->encode($info['Payload'])); - } - } - } - } else { - $connects[] = $connection; -// $this->server->onOpen($connection, $info); - } + if ($info = $this->server->handshake($connection)) { + $this->computeIncomingInfo($info, $connection); } unset($read[array_search($socket, $read)]); @@ -123,42 +125,117 @@ public function handle() $data = fread($connection, 100000); if (!$data) { - fclose($connection); - $connection_key = array_search($connection, $connects); - unset($connects[$connection_key]); - unset($per_pages[$connection_key]); + $this->close($connection); continue; } - $route = $this->server->decode($data)['payload']; + $connection_request = explode(':', $this->server->decode($data)['payload']); + $route = $connection_request[0]; - if (in_array($route, array_column($routes, 'name'))) { - $connection_key = array_search($connection, $connects); - $per_pages[$connection_key] = $route; + if (isset($connection_request[1])) { + $unique_id = $connection_request[1]; + } + + if (in_array($route, array_column($this->routes, 'name'))) { + $connection_key = array_search($connection, $this->connects); + $this->per_pages[$connection_key] = $route; + + if (isset($unique_id) && Cache::has('notifier:' . $unique_id)) { + $this->per_users[$connection_key] = Cache::get('notifier:' . $unique_id); + } } else { - fclose($connection); - $connection_key = array_search($connection, $connects); - unset($connects[$connection_key]); - unset($per_pages[$connection_key]); + $this->close($connection); continue; } -// $this->server->onMessage($connect, $data); + + unset($route, $unique_id, $connection_request); + //$this->server->onMessage($connect, $data); } } fclose($socket); } + /** + * @param $info + * @param $connection + */ + private function computeIncomingInfo($info, $connection) + { + if (isset($info['Socket-pass']) && $info['Socket-pass'] === config('notifier.socket_pass')) { + $this->computeSystemMessage($info); + } else { + $this->connects[] =$connection; + //$this->server->onOpen($connection, $info); + } + } + + /** + * @param $info + */ + private function computeSystemMessage($info) + { + foreach ($this->connects as $key => $connection) { + if (isset($this->per_pages[$key])) { + if (isset($info['Routes'])) { + $this->sendToRoutes($key, $connection, $info); + } elseif (!isset($info['Route'])) { + fwrite($connection, $this->server->encode($info['Payload'])); + } + } + } + } + + /** + * @param $key + * @param $connection + * @param $info + */ + private function sendToRoutes($key, $connection, $info) + { + if (in_array($this->per_pages[$key], json_decode($info['Routes']))) { + if (isset($info['Users'])) { + $this->sendToUsers($key, $connection, $info); + } else { + fwrite($connection, $this->server->encode($info['Payload'])); + } + } + } + + /** + * @param $key + * @param $connection + * @param $info + */ + private function sendToUsers($key, $connection, $info) + { + if (isset($this->per_users[$key]) && in_array($this->per_users[$key], json_decode($info['Users']))) { + fwrite($connection, $this->server->encode($info['Payload'])); + } + } + + /** + * @param $connection + */ + private function close($connection) + { + fclose($connection); + $connection_key = array_search($connection, $this->connects); + unset($this->connects[$connection_key]); + unset($this->per_pages[$connection_key]); + unset($this->per_users[$connection_key]); + } + /** * Compile the routes into a displayable format. * * @return array */ - protected function getRoutes() + private function getRoutes() { $result = []; - foreach ($this->routes as $route) { + foreach ($this->router->getRoutes() as $route) { $methods = $route->methods(); if (!in_array('GET', $methods)) { @@ -188,12 +265,11 @@ protected function getRoutes() /** * Display the route information on the console. * - * @param array $routes * @return void */ - protected function displayRoutes(array $routes) + private function displayRoutes() { - $this->table($this->headers, $routes); + $this->table($this->headers, $this->routes); } /** @@ -202,7 +278,7 @@ protected function displayRoutes(array $routes) * @param \Illuminate\Routing\Route $route * @return array */ - protected function getMiddleware($route) + private function getMiddleware($route) { return collect($route->gatherMiddleware())->map(function ($middleware) { return $middleware instanceof Closure ? 'Closure' : $middleware; diff --git a/src/Events/Notify.php b/src/Events/Notify.php index 743485c..8a91e84 100644 --- a/src/Events/Notify.php +++ b/src/Events/Notify.php @@ -14,18 +14,25 @@ class Notify /** * @var */ - public $route; + public $routes; + + /** + * @var + */ + public $users; /** * Create a new event instance. * * @param $data - * @param $route + * @param $routes + * @param $users */ - public function __construct($data, $route = false) + public function __construct($data, $routes = false, $users = false) { $this->data = $data; - $this->route = $route; + $this->routes = $routes; + $this->users = $users; } /** diff --git a/src/Listeners/NotifyListener.php b/src/Listeners/NotifyListener.php index 6864ae8..e28669a 100644 --- a/src/Listeners/NotifyListener.php +++ b/src/Listeners/NotifyListener.php @@ -25,6 +25,6 @@ public function __construct() */ public function handle(Notify $event) { - with(new SystemMessage())->send($event->data, $event->route); + with(new SystemMessage())->send($event->data, $event->routes, $event->users); } } diff --git a/src/NotifierServiceProvider.php b/src/NotifierServiceProvider.php index bdfd4b4..550f8f5 100644 --- a/src/NotifierServiceProvider.php +++ b/src/NotifierServiceProvider.php @@ -30,6 +30,8 @@ public function boot() */ public function register() { + require_once('helper_connector.php'); + $events = $this->app->make(Dispatcher::class); foreach ($this->events as $event => $listeners) { @@ -38,7 +40,7 @@ public function register() } } - $this->loadViewsFrom(__DIR__.'/views', 'notifier'); + $this->loadViewsFrom(__DIR__ . '/views', 'notifier'); if ($this->app->runningInConsole()) { diff --git a/src/SocketServer.php b/src/SocketServer.php index 0c9ee36..603f9a2 100644 --- a/src/SocketServer.php +++ b/src/SocketServer.php @@ -67,6 +67,10 @@ public function getMessage($data, $routes = false, $users = false) $request .= "\r\n" . "Routes: " . json_encode($routes); } + if (isset($users) && is_array($users) && count($users)) { + $request .= "\r\n" . "Users: " . json_encode($users); + } + return $request; } diff --git a/src/SystemMessage.php b/src/SystemMessage.php index d695db6..2eff83d 100644 --- a/src/SystemMessage.php +++ b/src/SystemMessage.php @@ -24,12 +24,13 @@ public function __construct() /** * @param $data - * @param bool $route + * @param bool $routes + * @param bool $users */ - public function send($data, $route = false) + public function send($data, $routes = false, $users = false) { try { - $this->create()->connect()->write($data, $route)->close(); + $this->create()->connect()->write($data, $routes, $users)->close(); } catch (\Exception $e) { $error_code = socket_last_error(); $error_msg = socket_strerror($error_code); @@ -60,12 +61,13 @@ private function connect() /** * @param $data - * @param $route + * @param $routes + * @param $users * @return $this */ - private function write($data, $route) + private function write($data, $routes, $users) { - $message = $this->server->getMessage($data, $route); + $message = $this->server->getMessage($data, $routes, $users); socket_send($this->socket, $message, strlen($message), 0); diff --git a/src/helper_connector.php b/src/helper_connector.php new file mode 100644 index 0000000..58648fb --- /dev/null +++ b/src/helper_connector.php @@ -0,0 +1,29 @@ +getName()) { + echo ''; + } +} + +function getUniqueId() +{ + if ($user_id = \Auth::id()) { + $unique_id = uniqid(); + + \Cache::put( + 'notifier:' . $unique_id, + $user_id, + config('session.lifetime') + ); + + return ':' . $unique_id; + } +} diff --git a/src/views/connect.blade.php b/src/views/connect.blade.php index 0e9e083..21d0939 100644 --- a/src/views/connect.blade.php +++ b/src/views/connect.blade.php @@ -1,11 +1 @@ - \ No newline at end of file +{{ notifier_js() }} \ No newline at end of file