From 2344c7b704c71b363f298f1d282d17ce69ce81d4 Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Wed, 21 Nov 2018 15:42:04 +0100 Subject: [PATCH] wip --- composer.json | 1 + .../Http/Controllers/EventController.php | 18 ++++++++++ src/LaravelEcho/Pusher/Channels/Channel.php | 34 +++++++++++++++++++ .../Pusher/Channels/ChannelManager.php | 5 +++ .../Pusher/Channels/PresenceChannel.php | 2 ++ src/LaravelEcho/WebSocket/EchoServer.php | 22 +++++++++--- 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 4e6e03a..63aa8d6 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ ], "require": { "php": "^7.1", + "ext-json": "*", "cboden/ratchet": "^0.4.1", "illuminate/console": "5.6.*|5.7.*", "illuminate/http": "5.6.*|5.7.*", diff --git a/src/LaravelEcho/Http/Controllers/EventController.php b/src/LaravelEcho/Http/Controllers/EventController.php index c3c9d54..1df4fc1 100644 --- a/src/LaravelEcho/Http/Controllers/EventController.php +++ b/src/LaravelEcho/Http/Controllers/EventController.php @@ -2,13 +2,31 @@ namespace BeyondCode\LaravelWebSockets\LaravelEcho\Http\Controllers; +use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels\ChannelManager; use Illuminate\Http\Request; class EventController extends EchoController { + /** @var ChannelManager */ + private $channelManager; + + public function __construct(ChannelManager $channelManager) + { + $this->channelManager = $channelManager; + } + public function __invoke(Request $request) { + foreach ($request->json()->get('channels', []) as $channelId) { + $channel = $this->channelManager->find($channelId); + + $channel->broadcast([ + 'channel' => $channelId, + 'event' => $request->json()->get('name'), + 'data' => $request->json()->get('data'), + ]); + } return $request->json()->all(); } } \ No newline at end of file diff --git a/src/LaravelEcho/Pusher/Channels/Channel.php b/src/LaravelEcho/Pusher/Channels/Channel.php index 4adc13e..b1693e5 100644 --- a/src/LaravelEcho/Pusher/Channels/Channel.php +++ b/src/LaravelEcho/Pusher/Channels/Channel.php @@ -2,20 +2,54 @@ namespace BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels; +use Illuminate\Support\Collection; use Ratchet\ConnectionInterface; class Channel { protected $channelId; + /** @var ConnectionInterface[] */ + protected $connections = []; public function __construct($channelId) { $this->channelId = $channelId; } + /** + * @link https://pusher.com/docs/pusher_protocol#presence-channel-events + * + * @param ConnectionInterface $conn + * @param $payload + */ public function subscribe(ConnectionInterface $conn, $payload) { + $this->saveConnection($conn); + // Send the success event + $conn->send(json_encode([ + 'event' => 'pusher_internal:subscription_succeeded', + 'channel' => $this->channelId + ])); + } + + protected function saveConnection(ConnectionInterface $conn) + { + $this->connections[$conn->socketId] = $conn; + } + + public function broadcast($payload) + { + foreach ($this->connections as $connection) { + $connection->send(json_encode($payload)); + } + } + + public function broadcastToOthers($conn, $payload) + { + Collection::make($this->connections)->reject(function($connection) use ($conn) { + return $connection->socketId === $conn->socketId; + })->each->send(json_encode($payload)); } } \ No newline at end of file diff --git a/src/LaravelEcho/Pusher/Channels/ChannelManager.php b/src/LaravelEcho/Pusher/Channels/ChannelManager.php index b246e3d..5db52cd 100644 --- a/src/LaravelEcho/Pusher/Channels/ChannelManager.php +++ b/src/LaravelEcho/Pusher/Channels/ChannelManager.php @@ -17,6 +17,11 @@ class ChannelManager return $this->channels[$channelId]; } + public function find(string $channelId) + { + return $this->channels[$channelId] ?? null; + } + protected function detectChannelClass($channelId) : string { if (starts_with($channelId, 'private-')) { diff --git a/src/LaravelEcho/Pusher/Channels/PresenceChannel.php b/src/LaravelEcho/Pusher/Channels/PresenceChannel.php index 2f4319b..1a88de7 100644 --- a/src/LaravelEcho/Pusher/Channels/PresenceChannel.php +++ b/src/LaravelEcho/Pusher/Channels/PresenceChannel.php @@ -16,6 +16,8 @@ class PresenceChannel extends Channel */ public function subscribe(ConnectionInterface $conn, $payload) { + $this->saveConnection($conn); + $channelData = json_decode($payload->channel_data); $this->subscriptions[$channelData->user_id] = $channelData; diff --git a/src/LaravelEcho/WebSocket/EchoServer.php b/src/LaravelEcho/WebSocket/EchoServer.php index 3de747c..4b0e216 100644 --- a/src/LaravelEcho/WebSocket/EchoServer.php +++ b/src/LaravelEcho/WebSocket/EchoServer.php @@ -25,6 +25,10 @@ class EchoServer extends WebSocketController function onOpen(ConnectionInterface $conn) { dump("Client connected"); + /** + * There are a couple things we need to do here: + * 1. Authenticate the incoming request by validating the provided APP-ID is known to us (JSON file lookup?) + */ $socketId = sprintf("%d.%d", getmypid(), random_int(1, 100000000)); @@ -43,11 +47,21 @@ class EchoServer extends WebSocketController dump("Received payload", $payload); - // todo: validate payload - $event = camel_case(str_replace(':', '_', $payload->event)); + /** + * Pusher events get a special treatment + */ + if (starts_with($payload->event, 'pusher:')) { + $event = camel_case(str_replace(':', '_', $payload->event)); - if (method_exists($this, $event)) { - call_user_func([$this, $event], $conn, $payload->data); + if (method_exists($this, $event)) { + call_user_func([$this, $event], $conn, $payload->data); + } + } else { + // Try to find a channel and broadcast the message to the clients. + $channel = $this->channelManager->find($payload->channel); + if ($channel) { + $channel->broadcast($payload); + } } }