2018-11-21 11:13:40 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Channels;
|
|
|
|
|
|
2018-11-26 08:22:30 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\Events\ChannelVacated;
|
2018-11-25 21:24:31 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Dashboard;
|
2018-11-22 09:54:51 +00:00
|
|
|
use BeyondCode\LaravelWebSockets\LaravelEcho\Pusher\Exceptions\InvalidSignatureException;
|
2018-11-21 14:42:04 +00:00
|
|
|
use Illuminate\Support\Collection;
|
2018-11-21 11:13:40 +00:00
|
|
|
use Ratchet\ConnectionInterface;
|
2018-11-22 09:54:51 +00:00
|
|
|
use stdClass;
|
2018-11-21 11:13:40 +00:00
|
|
|
|
|
|
|
|
class Channel
|
|
|
|
|
{
|
2018-11-21 21:11:44 +00:00
|
|
|
/** @var string */
|
2018-11-21 11:13:40 +00:00
|
|
|
protected $channelId;
|
|
|
|
|
|
2018-11-21 23:14:22 +00:00
|
|
|
/** @var \Ratchet\ConnectionInterface[] */
|
2018-11-22 21:02:36 +00:00
|
|
|
protected $subscriptions = [];
|
2018-11-21 11:13:40 +00:00
|
|
|
|
2018-11-21 21:11:44 +00:00
|
|
|
public function __construct(string $channelId)
|
2018-11-21 11:13:40 +00:00
|
|
|
{
|
|
|
|
|
$this->channelId = $channelId;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-21 21:36:50 +00:00
|
|
|
public function hasConnections(): bool
|
|
|
|
|
{
|
2018-11-22 21:02:36 +00:00
|
|
|
return count($this->subscriptions) > 0;
|
2018-11-21 21:36:50 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 09:54:51 +00:00
|
|
|
protected function verifySignature(ConnectionInterface $connection, stdClass $payload)
|
|
|
|
|
{
|
|
|
|
|
$auth = $payload->auth;
|
|
|
|
|
|
|
|
|
|
$signature = "{$connection->socketId}:{$this->channelId}";
|
|
|
|
|
|
|
|
|
|
if (isset($payload->channel_data)) {
|
|
|
|
|
$signature .= ":{$payload->channel_data}";
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-24 21:07:53 +00:00
|
|
|
if (str_after($auth, ':') !== hash_hmac('sha256', $signature, $connection->client->appSecret)) {
|
2018-11-22 09:54:51 +00:00
|
|
|
throw new InvalidSignatureException();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
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',
|
|
|
|
|
'channel' => $this->channelId
|
|
|
|
|
]));
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-21 21:36:50 +00:00
|
|
|
public function unsubscribe(ConnectionInterface $connection)
|
|
|
|
|
{
|
2018-11-22 21:02:36 +00:00
|
|
|
unset($this->subscriptions[$connection->socketId]);
|
2018-11-25 21:24:31 +00:00
|
|
|
|
|
|
|
|
if (! $this->hasConnections()) {
|
2018-11-26 08:22:30 +00:00
|
|
|
event(new ChannelVacated($connection, $this->channelId));
|
2018-11-25 21:24:31 +00:00
|
|
|
Dashboard::vacated($connection, $this->channelId);
|
|
|
|
|
}
|
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-25 21:24:31 +00:00
|
|
|
if (! $this->hasConnections()) {
|
|
|
|
|
Dashboard::occupied($connection, $this->channelId);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 21:02:36 +00:00
|
|
|
$this->subscriptions[$connection->socketId] = $connection;
|
2018-11-25 21:24:31 +00:00
|
|
|
|
|
|
|
|
Dashboard::subscribed($connection, $this->channelId);
|
2018-11-21 14:42:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function broadcast($payload)
|
|
|
|
|
{
|
2018-11-22 21:02:36 +00:00
|
|
|
foreach ($this->subscriptions as $connection) {
|
2018-11-21 14:42:04 +00:00
|
|
|
$connection->send(json_encode($payload));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 21:30:28 +00:00
|
|
|
public function broadcastToEveryoneExcept($payload, ?string $socketId = null)
|
2018-11-21 14:42:04 +00:00
|
|
|
{
|
2018-11-22 21:30:28 +00:00
|
|
|
Collection::make($this->subscriptions)->reject(function ($existingConnection) use ($socketId) {
|
|
|
|
|
return $existingConnection->socketId === $socketId;
|
2018-11-21 14:42:04 +00:00
|
|
|
})->each->send(json_encode($payload));
|
2018-11-21 11:13:40 +00:00
|
|
|
}
|
2018-11-22 21:02:36 +00:00
|
|
|
|
2018-11-22 21:30:28 +00:00
|
|
|
public function broadcastToOthers(ConnectionInterface $connection, $payload)
|
|
|
|
|
{
|
|
|
|
|
$this->broadcastToEveryoneExcept($payload, $connection->socketId);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 21:02:36 +00:00
|
|
|
public function toArray(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
'occupied' => count($this->subscriptions) > 0,
|
|
|
|
|
'subscription_count' => count($this->subscriptions)
|
|
|
|
|
];
|
|
|
|
|
}
|
2018-11-21 11:13:40 +00:00
|
|
|
}
|