laravel-websockets/src/Channels/PresenceChannel.php

148 lines
4.1 KiB
PHP
Raw Normal View History

2020-09-10 19:59:26 +00:00
<?php
namespace BeyondCode\LaravelWebSockets\Channels;
2020-09-11 05:34:21 +00:00
use BeyondCode\LaravelWebSockets\DashboardLogger;
2020-09-10 19:59:26 +00:00
use BeyondCode\LaravelWebSockets\Server\Exceptions\InvalidSignature;
use Ratchet\ConnectionInterface;
use stdClass;
class PresenceChannel extends PrivateChannel
{
/**
* Subscribe to the channel.
*
* @see https://pusher.com/docs/pusher_protocol#presence-channel-events
* @param \Ratchet\ConnectionInterface $connection
* @param \stdClass $payload
* @return void
* @throws InvalidSignature
*/
public function subscribe(ConnectionInterface $connection, stdClass $payload)
{
2020-09-11 05:34:21 +00:00
$this->verifySignature($connection, $payload);
$this->saveConnection($connection);
2020-09-10 19:59:26 +00:00
$this->channelManager->userJoinedPresenceChannel(
$connection,
$user = json_decode($payload->channel_data),
$this->getName(),
$payload
);
$this->channelManager
->getChannelMembers($connection->app->id, $this->getName())
->then(function ($users) use ($connection) {
$connection->send(json_encode([
'event' => 'pusher_internal:subscription_succeeded',
'channel' => $this->getName(),
'data' => json_encode($this->getChannelData($users)),
]));
});
$memberAddedPayload = [
'event' => 'pusher_internal:member_added',
'channel' => $this->getName(),
'data' => $payload->channel_data,
];
$this->broadcastToEveryoneExcept(
(object) $memberAddedPayload, $connection->socketId,
$connection->app->id
);
2020-09-11 05:34:21 +00:00
DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_SUBSCRIBED, [
'socketId' => $connection->socketId,
'channel' => $this->getName(),
]);
2020-09-10 19:59:26 +00:00
}
/**
* Unsubscribe connection from the channel.
*
* @param \Ratchet\ConnectionInterface $connection
* @return void
*/
public function unsubscribe(ConnectionInterface $connection)
{
parent::unsubscribe($connection);
$this->channelManager
->getChannelMember($connection, $this->getName())
->then(function ($user) use ($connection) {
$user = @json_decode($user);
if (! $user) {
return;
}
$this->channelManager->userLeftPresenceChannel(
$connection, $user, $this->getName()
);
$memberRemovedPayload = [
'event' => 'pusher_internal:member_removed',
'channel' => $this->getName(),
'data' => json_encode([
'user_id' => $user->user_id,
]),
];
$this->broadcastToEveryoneExcept(
(object) $memberRemovedPayload, $connection->socketId,
$connection->app->id
);
});
}
/**
* Get the Presence channel data.
*
* @param array $users
* @return array
*/
protected function getChannelData(array $users): array
{
return [
'presence' => [
'ids' => $this->getUserIds($users),
'hash' => $this->getHash($users),
'count' => count($users),
],
];
}
/**
* Get the Presence Channel's users.
*
* @param array $users
* @return array
*/
protected function getUserIds(array $users): array
{
return collect($users)
->map(function ($user) {
return (string) $user->user_id;
})
->values();
}
/**
* Compute the hash for the presence channel integrity.
*
* @param array $users
* @return array
*/
protected function getHash(array $users): array
{
$hash = [];
foreach ($users as $socketId => $user) {
$hash[$user->user_id] = $user->user_info ?? [];
}
return $hash;
}
}