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

154 lines
4.6 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-11-26 23:07:35 +00:00
use stdClass;
2018-12-04 21:22:33 +00:00
use Ratchet\ConnectionInterface;
use React\Promise\PromiseInterface;
use BeyondCode\LaravelWebSockets\PubSub\ReplicationInterface;
use BeyondCode\LaravelWebSockets\WebSockets\Exceptions\InvalidSignature;
2018-11-21 11:13:40 +00:00
class PresenceChannel extends Channel
{
/**
* Data for the users connected to this channel
*
* Note: If replication is enabled, this will only contain entries
* for the users directly connected to this server instance. Requests
* for data for all users in the channel should be routed through
* ReplicationInterface.
*
* @var string[]
*/
2018-11-22 21:02:36 +00:00
protected $users = [];
2018-11-21 11:13:40 +00:00
/**
* @param string $appId
* @return array|PromiseInterface
*/
public function getUsers(string $appId)
2018-11-22 21:09:32 +00:00
{
// Get the members list from the replication backend
return app(ReplicationInterface::class)
->channelMembers($appId, $this->channelName);
}
/**
2018-11-21 11:14:45 +00:00
* @link https://pusher.com/docs/pusher_protocol#presence-channel-events
*
* @param ConnectionInterface $connection
* @param stdClass $payload
* @throws InvalidSignature
2018-11-21 11:14:45 +00:00
*/
2018-11-26 23:07:35 +00:00
public function subscribe(ConnectionInterface $connection, stdClass $payload)
2018-11-21 11:13:40 +00:00
{
2018-11-22 09:54:51 +00:00
$this->verifySignature($connection, $payload);
2018-11-21 23:03:13 +00:00
$this->saveConnection($connection);
2018-11-21 14:42:04 +00:00
2018-11-21 11:13:40 +00:00
$channelData = json_decode($payload->channel_data);
2018-11-27 15:55:30 +00:00
$this->users[$connection->socketId] = $channelData;
2018-11-21 11:13:40 +00:00
// Add the connection as a member of the channel
app(ReplicationInterface::class)
->joinChannel(
$connection->app->id,
$this->channelName,
$connection->socketId,
json_encode($channelData)
);
// We need to pull the channel data from the replication backend,
// otherwise we won't be sending the full details of the channel
app(ReplicationInterface::class)
->channelMembers($connection->app->id, $this->channelName)
->then(function ($users) use ($connection) {
// Send the success event
$connection->send(json_encode([
'event' => 'pusher_internal:subscription_succeeded',
'channel' => $this->channelName,
'data' => json_encode($this->getChannelData($users)),
]));
});
2018-11-21 20:23:25 +00:00
$this->broadcastToOthers($connection, (object) [
2018-11-21 23:03:13 +00:00
'event' => 'pusher_internal:member_added',
2018-12-01 11:41:58 +00:00
'channel' => $this->channelName,
2018-12-04 21:22:33 +00:00
'data' => json_encode($channelData),
2018-11-21 23:03:13 +00:00
]);
2018-11-21 11:13:40 +00:00
}
2018-11-21 21:36:50 +00:00
public function unsubscribe(ConnectionInterface $connection)
{
parent::unsubscribe($connection);
2018-12-03 21:11:44 +00:00
if (! isset($this->users[$connection->socketId])) {
return;
}
// Remove the connection as a member of the channel
app(ReplicationInterface::class)
->leaveChannel(
$connection->app->id,
$this->channelName,
$connection->socketId
);
$this->broadcastToOthers($connection, (object) [
2018-11-22 07:37:47 +00:00
'event' => 'pusher_internal:member_removed',
2018-12-01 11:41:58 +00:00
'channel' => $this->channelName,
2018-11-22 07:37:47 +00:00
'data' => json_encode([
2018-12-04 21:22:33 +00:00
'user_id' => $this->users[$connection->socketId]->user_id,
]),
2018-11-22 07:37:47 +00:00
]);
2018-11-22 21:02:36 +00:00
unset($this->users[$connection->socketId]);
2018-11-21 21:36:50 +00:00
}
/**
* @param string|null $appId
* @return PromiseInterface|array
*/
public function toArray(string $appId = null)
2018-11-21 11:13:40 +00:00
{
return app(ReplicationInterface::class)
->channelMembers($appId, $this->channelName)
->then(function ($users) {
return array_merge(parent::toArray(), [
'user_count' => count($users),
]);
});
2018-11-22 21:02:36 +00:00
}
2018-11-28 20:20:07 +00:00
protected function getChannelData(array $users): array
{
return [
'presence' => [
'ids' => $this->getUserIds($users),
'hash' => $this->getHash($users),
'count' => count($users),
],
];
}
protected function getUserIds(array $users): array
2018-11-28 20:20:07 +00:00
{
$userIds = array_map(function ($channelData) {
2018-12-04 21:22:33 +00:00
return (string) $channelData->user_id;
}, $users);
2018-11-28 20:20:07 +00:00
return array_values($userIds);
}
protected function getHash(array $users): array
2018-11-28 20:20:07 +00:00
{
$hash = [];
foreach ($users as $socketId => $channelData) {
2018-11-28 20:20:07 +00:00
$hash[$channelData->user_id] = $channelData->user_info;
}
return $hash;
}
2018-12-04 21:22:33 +00:00
}