laravel-websockets/src/WebSockets/Channels/Channel.php

136 lines
4.0 KiB
PHP
Raw Normal View History

2018-11-21 11:13:40 +00:00
<?php
2018-11-27 15:21:31 +00:00
namespace BeyondCode\LaravelWebSockets\WebSockets\Channels;
2018-11-21 11:13:40 +00:00
2018-12-04 21:22:33 +00:00
use stdClass;
use Illuminate\Support\Str;
2018-12-04 21:22:33 +00:00
use Ratchet\ConnectionInterface;
2018-11-29 10:59:17 +00:00
use BeyondCode\LaravelWebSockets\Dashboard\DashboardLogger;
2019-03-25 22:37:14 +00:00
use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface;
2018-11-27 15:35:28 +00:00
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\InvalidSignature;
2018-11-21 11:13:40 +00:00
class Channel
{
2018-11-21 21:11:44 +00:00
/** @var string */
2018-12-01 11:26:08 +00:00
protected $channelName;
2018-11-21 11:13:40 +00:00
2018-11-21 23:14:22 +00:00
/** @var \Ratchet\ConnectionInterface[] */
2018-12-01 14:21:31 +00:00
protected $subscribedConnections = [];
2018-11-21 11:13:40 +00:00
2018-12-01 11:26:08 +00:00
public function __construct(string $channelName)
2018-11-21 11:13:40 +00:00
{
2018-12-01 11:41:58 +00:00
$this->channelName = $channelName;
2018-11-21 11:13:40 +00:00
}
2018-11-21 21:36:50 +00:00
public function hasConnections(): bool
{
2018-12-01 14:21:31 +00:00
return count($this->subscribedConnections) > 0;
2018-11-21 21:36:50 +00:00
}
2018-12-01 14:21:31 +00:00
public function getSubscribedConnections(): array
2018-11-28 23:22:01 +00:00
{
2018-12-01 14:21:31 +00:00
return $this->subscribedConnections;
2018-11-28 23:22:01 +00:00
}
2018-11-22 09:54:51 +00:00
protected function verifySignature(ConnectionInterface $connection, stdClass $payload)
{
2018-12-01 11:41:58 +00:00
$signature = "{$connection->socketId}:{$this->channelName}";
2018-11-22 09:54:51 +00:00
if (isset($payload->channel_data)) {
$signature .= ":{$payload->channel_data}";
}
if (Str::after($payload->auth, ':') !== hash_hmac('sha256', $signature, $connection->app->secret)) {
2018-11-26 23:13:22 +00:00
throw new InvalidSignature();
2018-11-22 09:54:51 +00:00
}
}
2018-11-21 23:14:22 +00:00
/*
2018-11-21 14:42:04 +00:00
* @link https://pusher.com/docs/pusher_protocol#presence-channel-events
*/
2018-11-22 09:54:51 +00:00
public function subscribe(ConnectionInterface $connection, stdClass $payload)
2018-11-21 11:13:40 +00:00
{
2018-11-21 23:03:13 +00:00
$this->saveConnection($connection);
2018-11-21 11:13:40 +00:00
if (config('websockets.replication.enabled') === true) {
// Subscribe for broadcasted messages from the pub/sub backend
app(ReplicationInterface::class)
->subscribe($connection->app->id, $this->channelName);
}
2018-11-21 23:03:13 +00:00
$connection->send(json_encode([
2018-11-21 14:42:04 +00:00
'event' => 'pusher_internal:subscription_succeeded',
2018-12-04 21:22:33 +00:00
'channel' => $this->channelName,
2018-11-21 14:42:04 +00:00
]));
}
2018-11-21 21:36:50 +00:00
public function unsubscribe(ConnectionInterface $connection)
{
2018-12-01 14:21:31 +00:00
unset($this->subscribedConnections[$connection->socketId]);
2018-11-25 21:24:31 +00:00
if (config('websockets.replication.enabled') === true) {
// Unsubscribe from the pub/sub backend
app(ReplicationInterface::class)
->unsubscribe($connection->app->id, $this->channelName);
}
2018-11-25 21:24:31 +00:00
if (! $this->hasConnections()) {
2018-12-01 11:41:58 +00:00
DashboardLogger::vacated($connection, $this->channelName);
2018-11-25 21:24:31 +00:00
}
2018-11-21 21:36:50 +00:00
}
2018-11-21 23:14:22 +00:00
protected function saveConnection(ConnectionInterface $connection)
2018-11-21 14:42:04 +00:00
{
2018-11-26 21:29:24 +00:00
$hadConnectionsPreviously = $this->hasConnections();
2018-11-25 21:24:31 +00:00
2018-12-01 14:21:31 +00:00
$this->subscribedConnections[$connection->socketId] = $connection;
2018-11-25 21:24:31 +00:00
2018-11-26 21:29:24 +00:00
if (! $hadConnectionsPreviously) {
2018-12-01 11:41:58 +00:00
DashboardLogger::occupied($connection, $this->channelName);
2018-11-26 21:29:24 +00:00
}
2018-12-01 11:41:58 +00:00
DashboardLogger::subscribed($connection, $this->channelName);
2018-11-21 14:42:04 +00:00
}
public function broadcast($payload)
{
2018-12-01 14:21:31 +00:00
foreach ($this->subscribedConnections as $connection) {
2018-11-21 14:42:04 +00:00
$connection->send(json_encode($payload));
}
}
2018-12-04 20:12:10 +00:00
public function broadcastToOthers(ConnectionInterface $connection, $payload)
{
if (config('websockets.replication.enabled') === true) {
// Also broadcast via the other websocket servers
app(ReplicationInterface::class)
->publish($connection->app->id, $payload);
}
$this->broadcastToEveryoneExcept($payload, $connection->socketId, $connection->app->id);
2018-12-04 20:12:10 +00:00
}
public function broadcastToEveryoneExcept($payload, ?string $socketId = null, ?string $appId = null)
2018-11-21 14:42:04 +00:00
{
2018-11-29 15:41:27 +00:00
if (is_null($socketId)) {
$this->broadcast($payload);
2019-03-25 22:37:14 +00:00
return;
2018-11-29 15:41:27 +00:00
}
2018-12-01 14:21:31 +00:00
foreach ($this->subscribedConnections as $connection) {
2018-11-29 15:41:27 +00:00
if ($connection->socketId !== $socketId) {
$connection->send(json_encode($payload));
}
}
2018-11-21 11:13:40 +00:00
}
2018-11-22 21:02:36 +00:00
public function toArray(): array
{
return [
2018-12-01 14:21:31 +00:00
'occupied' => count($this->subscribedConnections) > 0,
2018-12-04 21:22:33 +00:00
'subscription_count' => count($this->subscribedConnections),
2018-11-22 21:02:36 +00:00
];
}
2018-12-04 21:22:33 +00:00
}