Refactored the dashboard logger
This commit is contained in:
parent
38b2e4d404
commit
5890659102
|
|
@ -10,9 +10,9 @@ class DashboardLogger
|
||||||
{
|
{
|
||||||
const LOG_CHANNEL_PREFIX = 'private-websockets-dashboard-';
|
const LOG_CHANNEL_PREFIX = 'private-websockets-dashboard-';
|
||||||
|
|
||||||
const TYPE_DISCONNECTION = 'disconnection';
|
const TYPE_DISCONNECTED = 'disconnected';
|
||||||
|
|
||||||
const TYPE_CONNECTION = 'connection';
|
const TYPE_CONNECTED = 'connected';
|
||||||
|
|
||||||
const TYPE_VACATED = 'vacated';
|
const TYPE_VACATED = 'vacated';
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ class DashboardLogger
|
||||||
|
|
||||||
const TYPE_SUBSCRIBED = 'subscribed';
|
const TYPE_SUBSCRIBED = 'subscribed';
|
||||||
|
|
||||||
const TYPE_CLIENT_MESSAGE = 'client-message';
|
const TYPE_WS_MESSAGE = 'ws-message';
|
||||||
|
|
||||||
const TYPE_API_MESSAGE = 'api-message';
|
const TYPE_API_MESSAGE = 'api-message';
|
||||||
|
|
||||||
|
|
@ -28,101 +28,36 @@ class DashboardLogger
|
||||||
|
|
||||||
const TYPE_REPLICATOR_UNSUBSCRIBED = 'replicator-unsubscribed';
|
const TYPE_REPLICATOR_UNSUBSCRIBED = 'replicator-unsubscribed';
|
||||||
|
|
||||||
public static function connection(ConnectionInterface $connection)
|
const TYPE_REPLICATOR_JOINED_CHANNEL = 'replicator-joined';
|
||||||
{
|
|
||||||
/** @var \GuzzleHttp\Psr7\Request $request */
|
|
||||||
$request = $connection->httpRequest;
|
|
||||||
|
|
||||||
static::log($connection->app->id, static::TYPE_CONNECTION, [
|
const TYPE_REPLICATOR_LEFT_CHANNEL = 'replicator-left';
|
||||||
'details' => [
|
|
||||||
'origin' => "{$request->getUri()->getScheme()}://{$request->getUri()->getHost()}",
|
|
||||||
'socketId' => $connection->socketId,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function occupied(ConnectionInterface $connection, string $channelName)
|
const TYPE_REPLICATOR_MESSAGE_PUBLISHED = 'replicator-message-published';
|
||||||
{
|
|
||||||
static::log($connection->app->id, static::TYPE_OCCUPIED, [
|
|
||||||
'details' => [
|
|
||||||
'channel' => $channelName,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function subscribed(ConnectionInterface $connection, string $channelName)
|
const TYPE_REPLICATOR_MESSAGE_RECEIVED = 'replicator-message-received';
|
||||||
{
|
|
||||||
static::log($connection->app->id, static::TYPE_SUBSCRIBED, [
|
|
||||||
'details' => [
|
|
||||||
'socketId' => $connection->socketId,
|
|
||||||
'channel' => $channelName,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function clientMessage(ConnectionInterface $connection, stdClass $payload)
|
/**
|
||||||
{
|
* The list of all channels.
|
||||||
static::log($connection->app->id, static::TYPE_CLIENT_MESSAGE, [
|
*
|
||||||
'details' => [
|
* @var array
|
||||||
'socketId' => $connection->socketId,
|
*/
|
||||||
'channel' => $payload->channel,
|
public static $channels = [
|
||||||
'event' => $payload->event,
|
self::TYPE_DISCONNECTED,
|
||||||
'data' => $payload,
|
self::TYPE_CONNECTED,
|
||||||
],
|
self::TYPE_VACATED,
|
||||||
]);
|
self::TYPE_OCCUPIED,
|
||||||
}
|
self::TYPE_SUBSCRIBED,
|
||||||
|
self::TYPE_WS_MESSAGE,
|
||||||
|
self::TYPE_API_MESSAGE,
|
||||||
|
self::TYPE_REPLICATOR_SUBSCRIBED,
|
||||||
|
self::TYPE_REPLICATOR_UNSUBSCRIBED,
|
||||||
|
self::TYPE_REPLICATOR_JOINED_CHANNEL,
|
||||||
|
self::TYPE_REPLICATOR_LEFT_CHANNEL,
|
||||||
|
self::TYPE_REPLICATOR_MESSAGE_PUBLISHED,
|
||||||
|
self::TYPE_REPLICATOR_MESSAGE_RECEIVED,
|
||||||
|
];
|
||||||
|
|
||||||
public static function disconnection(ConnectionInterface $connection)
|
public static function log($appId, string $type, array $details = [])
|
||||||
{
|
|
||||||
static::log($connection->app->id, static::TYPE_DISCONNECTION, [
|
|
||||||
'details' => [
|
|
||||||
'socketId' => $connection->socketId,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function vacated(ConnectionInterface $connection, string $channelName)
|
|
||||||
{
|
|
||||||
static::log($connection->app->id, static::TYPE_VACATED, [
|
|
||||||
'details' => [
|
|
||||||
'socketId' => $connection->socketId,
|
|
||||||
'channel' => $channelName,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function apiMessage($appId, string $channel, string $event, string $payload)
|
|
||||||
{
|
|
||||||
static::log($appId, static::TYPE_API_MESSAGE, [
|
|
||||||
'details' => [
|
|
||||||
'channel' => $connection,
|
|
||||||
'event' => $event,
|
|
||||||
'payload' => $payload,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function replicatorSubscribed(string $appId, string $channel, string $serverId)
|
|
||||||
{
|
|
||||||
static::log($appId, static::TYPE_REPLICATOR_SUBSCRIBED, [
|
|
||||||
'details' => [
|
|
||||||
'serverId' => $serverId,
|
|
||||||
'channel' => $channel,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function replicatorUnsubscribed(string $appId, string $channel, string $serverId)
|
|
||||||
{
|
|
||||||
static::log($appId, static::TYPE_REPLICATOR_UNSUBSCRIBED, [
|
|
||||||
'details' => [
|
|
||||||
'serverId' => $serverId,
|
|
||||||
'channel' => $channel,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function log($appId, string $type, array $attributes = [])
|
|
||||||
{
|
{
|
||||||
$channelName = static::LOG_CHANNEL_PREFIX.$type;
|
$channelName = static::LOG_CHANNEL_PREFIX.$type;
|
||||||
|
|
||||||
|
|
@ -134,7 +69,8 @@ class DashboardLogger
|
||||||
'data' => [
|
'data' => [
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
'time' => strftime('%H:%M:%S'),
|
'time' => strftime('%H:%M:%S'),
|
||||||
] + $attributes,
|
'details' => $details,
|
||||||
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,11 @@ class TriggerEventController extends Controller
|
||||||
'data' => $request->json()->get('data'),
|
'data' => $request->json()->get('data'),
|
||||||
], $request->json()->get('socket_id'), $request->appId);
|
], $request->json()->get('socket_id'), $request->appId);
|
||||||
|
|
||||||
DashboardLogger::apiMessage(
|
DashboardLogger::log($request->appId, DashboardLogger::TYPE_API_MESSAGE, [
|
||||||
$request->appId,
|
'channel' => $channelName,
|
||||||
$channelName,
|
'event' => $request->json()->get('name'),
|
||||||
$request->json()->get('name'),
|
'payload' => $request->json()->get('data'),
|
||||||
$request->json()->get('data')
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
StatisticsLogger::apiMessage($request->appId);
|
StatisticsLogger::apiMessage($request->appId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use React\EventLoop\LoopInterface;
|
||||||
use React\Promise\PromiseInterface;
|
use React\Promise\PromiseInterface;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
class RedisClient implements ReplicationInterface
|
class RedisClient extends LocalClient
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The running loop.
|
* The running loop.
|
||||||
|
|
@ -90,49 +90,29 @@ class RedisClient implements ReplicationInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a message received from Redis on a specific channel.
|
* Publish a message to a channel on behalf of a websocket user.
|
||||||
*
|
*
|
||||||
* @param string $redisChannel
|
* @param string $appId
|
||||||
* @param string $payload
|
* @param string $channel
|
||||||
* @return void
|
* @param stdClass $payload
|
||||||
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function onMessage(string $redisChannel, string $payload)
|
public function publish(string $appId, string $channel, stdClass $payload): bool
|
||||||
{
|
{
|
||||||
$payload = json_decode($payload);
|
$payload->appId = $appId;
|
||||||
|
$payload->serverId = $this->getServerId();
|
||||||
|
|
||||||
// Ignore messages sent by ourselves.
|
$payload = json_encode($payload);
|
||||||
if (isset($payload->serverId) && $this->serverId === $payload->serverId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull out the app ID. See RedisPusherBroadcaster
|
$this->publishClient->__call('publish', ["$appId:$channel", $payload]);
|
||||||
$appId = $payload->appId;
|
|
||||||
|
|
||||||
// We need to put the channel name in the payload.
|
DashboardLogger::log($appId, DashboardLogger::TYPE_REPLICATOR_MESSAGE_PUBLISHED, [
|
||||||
// We strip the app ID from the channel name, websocket clients
|
'channel' => $channel,
|
||||||
// expect the channel name to not include the app ID.
|
'serverId' => $this->getServerId(),
|
||||||
$payload->channel = Str::after($redisChannel, "{$appId}:");
|
'payload' => $payload,
|
||||||
|
]);
|
||||||
|
|
||||||
$channelManager = app(ChannelManager::class);
|
return true;
|
||||||
|
|
||||||
// Load the Channel instance to sync.
|
|
||||||
$channel = $channelManager->find($appId, $payload->channel);
|
|
||||||
|
|
||||||
// If no channel is found, none of our connections want to
|
|
||||||
// receive this message, so we ignore it.
|
|
||||||
if (! $channel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$socket = $payload->socket ?? null;
|
|
||||||
|
|
||||||
// Remove fields intended for internal use from the payload.
|
|
||||||
unset($payload->socket);
|
|
||||||
unset($payload->serverId);
|
|
||||||
unset($payload->appId);
|
|
||||||
|
|
||||||
// Push the message out to connected websocket clients.
|
|
||||||
$channel->broadcastToEveryoneExcept($payload, $socket, $appId, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -153,7 +133,10 @@ class RedisClient implements ReplicationInterface
|
||||||
$this->subscribedChannels["$appId:$channel"]++;
|
$this->subscribedChannels["$appId:$channel"]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DashboardLogger::replicatorSubscribed($appId, $channel, $this->serverId);
|
DashboardLogger::log($appId, DashboardLogger::TYPE_REPLICATOR_SUBSCRIBED, [
|
||||||
|
'channel' => $channel,
|
||||||
|
'serverId' => $this->getServerId(),
|
||||||
|
]);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -181,25 +164,10 @@ class RedisClient implements ReplicationInterface
|
||||||
unset($this->subscribedChannels["$appId:$channel"]);
|
unset($this->subscribedChannels["$appId:$channel"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DashboardLogger::replicatorUnsubscribed($appId, $channel, $this->serverId);
|
DashboardLogger::log($appId, DashboardLogger::TYPE_REPLICATOR_UNSUBSCRIBED, [
|
||||||
|
'channel' => $channel,
|
||||||
return true;
|
'serverId' => $this->getServerId(),
|
||||||
}
|
]);
|
||||||
|
|
||||||
/**
|
|
||||||
* Publish a message to a channel on behalf of a websocket user.
|
|
||||||
*
|
|
||||||
* @param string $appId
|
|
||||||
* @param string $channel
|
|
||||||
* @param stdClass $payload
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function publish(string $appId, string $channel, stdClass $payload): bool
|
|
||||||
{
|
|
||||||
$payload->appId = $appId;
|
|
||||||
$payload->serverId = $this->serverId;
|
|
||||||
|
|
||||||
$this->publishClient->__call('publish', ["$appId:$channel", json_encode($payload)]);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -217,6 +185,13 @@ class RedisClient implements ReplicationInterface
|
||||||
public function joinChannel(string $appId, string $channel, string $socketId, string $data)
|
public function joinChannel(string $appId, string $channel, string $socketId, string $data)
|
||||||
{
|
{
|
||||||
$this->publishClient->__call('hset', ["$appId:$channel", $socketId, $data]);
|
$this->publishClient->__call('hset', ["$appId:$channel", $socketId, $data]);
|
||||||
|
|
||||||
|
DashboardLogger::log($appId, DashboardLogger::TYPE_REPLICATOR_JOINED_CHANNEL, [
|
||||||
|
'channel' => $channel,
|
||||||
|
'serverId' => $this->getServerId(),
|
||||||
|
'socketId' => $socketId,
|
||||||
|
'data' => $data,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -231,6 +206,12 @@ class RedisClient implements ReplicationInterface
|
||||||
public function leaveChannel(string $appId, string $channel, string $socketId)
|
public function leaveChannel(string $appId, string $channel, string $socketId)
|
||||||
{
|
{
|
||||||
$this->publishClient->__call('hdel', ["$appId:$channel", $socketId]);
|
$this->publishClient->__call('hdel', ["$appId:$channel", $socketId]);
|
||||||
|
|
||||||
|
DashboardLogger::log($appId, DashboardLogger::TYPE_REPLICATOR_LEFT_CHANNEL, [
|
||||||
|
'channel' => $channel,
|
||||||
|
'serverId' => $this->getServerId(),
|
||||||
|
'socketId' => $socketId,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -272,6 +253,62 @@ class RedisClient implements ReplicationInterface
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a message received from Redis on a specific channel.
|
||||||
|
*
|
||||||
|
* @param string $redisChannel
|
||||||
|
* @param string $payload
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function onMessage(string $redisChannel, string $payload)
|
||||||
|
{
|
||||||
|
$payload = json_decode($payload);
|
||||||
|
|
||||||
|
// Ignore messages sent by ourselves.
|
||||||
|
if (isset($payload->serverId) && $this->getServerId() === $payload->serverId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull out the app ID. See RedisPusherBroadcaster
|
||||||
|
$appId = $payload->appId;
|
||||||
|
|
||||||
|
// We need to put the channel name in the payload.
|
||||||
|
// We strip the app ID from the channel name, websocket clients
|
||||||
|
// expect the channel name to not include the app ID.
|
||||||
|
$payload->channel = Str::after($redisChannel, "{$appId}:");
|
||||||
|
|
||||||
|
$channelManager = app(ChannelManager::class);
|
||||||
|
|
||||||
|
// Load the Channel instance to sync.
|
||||||
|
$channel = $channelManager->find($appId, $payload->channel);
|
||||||
|
|
||||||
|
// If no channel is found, none of our connections want to
|
||||||
|
// receive this message, so we ignore it.
|
||||||
|
if (! $channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$socket = $payload->socket ?? null;
|
||||||
|
$serverId = $payload->serverId ?? null;
|
||||||
|
|
||||||
|
// Remove fields intended for internal use from the payload.
|
||||||
|
unset($payload->socket);
|
||||||
|
unset($payload->serverId);
|
||||||
|
unset($payload->appId);
|
||||||
|
|
||||||
|
// Push the message out to connected websocket clients.
|
||||||
|
$channel->broadcastToEveryoneExcept($payload, $socket, $appId, false);
|
||||||
|
|
||||||
|
DashboardLogger::log($appId, DashboardLogger::TYPE_REPLICATOR_MESSAGE_RECEIVED, [
|
||||||
|
'channel' => $channel->getChannelName(),
|
||||||
|
'redisChannel' => $redisChannel,
|
||||||
|
'serverId' => $this->getServer(),
|
||||||
|
'incomingServerId' => $serverId,
|
||||||
|
'incomingSocketId' => $socket,
|
||||||
|
'payload' => $payload,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the Redis connection URL from Laravel database config.
|
* Build the Redis connection URL from Laravel database config.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,10 @@ class Channel
|
||||||
$this->replicator->unsubscribe($connection->app->id, $this->channelName);
|
$this->replicator->unsubscribe($connection->app->id, $this->channelName);
|
||||||
|
|
||||||
if (! $this->hasConnections()) {
|
if (! $this->hasConnections()) {
|
||||||
DashboardLogger::vacated($connection, $this->channelName);
|
DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_VACATED, [
|
||||||
|
'socketId' => $connection->socketId,
|
||||||
|
'channel' => $this->channelName,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,10 +96,15 @@ class Channel
|
||||||
$this->subscribedConnections[$connection->socketId] = $connection;
|
$this->subscribedConnections[$connection->socketId] = $connection;
|
||||||
|
|
||||||
if (! $hadConnectionsPreviously) {
|
if (! $hadConnectionsPreviously) {
|
||||||
DashboardLogger::occupied($connection, $this->channelName);
|
DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_OCCUPIED, [
|
||||||
|
'channel' => $this->channelName,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DashboardLogger::subscribed($connection, $this->channelName);
|
DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_SUBSCRIBED, [
|
||||||
|
'socketId' => $connection->socketId,
|
||||||
|
'channel' => $this->channelName,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function broadcast($payload)
|
public function broadcast($payload)
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,12 @@ class PusherClientMessage implements PusherMessage
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DashboardLogger::clientMessage($this->connection, $this->payload);
|
DashboardLogger::log($this->connection->app->id, DashboardLogger::TYPE_WS_MESSAGE, [
|
||||||
|
'socketId' => $this->connection->socketId,
|
||||||
|
'channel' => $this->payload->channel,
|
||||||
|
'event' => $this->payload->event,
|
||||||
|
'data' => $this->payload,
|
||||||
|
]);
|
||||||
|
|
||||||
$channel = $this->channelManager->find($this->connection->app->id, $this->payload->channel);
|
$channel = $this->channelManager->find($this->connection->app->id, $this->payload->channel);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,9 @@ class WebSocketHandler implements MessageComponentInterface
|
||||||
{
|
{
|
||||||
$this->channelManager->removeFromAllChannels($connection);
|
$this->channelManager->removeFromAllChannels($connection);
|
||||||
|
|
||||||
DashboardLogger::disconnection($connection);
|
DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_DISCONNECTED, [
|
||||||
|
'socketId' => $connection->socketId,
|
||||||
|
]);
|
||||||
|
|
||||||
StatisticsLogger::disconnection($connection);
|
StatisticsLogger::disconnection($connection);
|
||||||
}
|
}
|
||||||
|
|
@ -106,9 +108,13 @@ class WebSocketHandler implements MessageComponentInterface
|
||||||
]),
|
]),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
DashboardLogger::connection($connection);
|
/** @var \GuzzleHttp\Psr7\Request $request */
|
||||||
|
$request = $connection->httpRequest;
|
||||||
|
|
||||||
StatisticsLogger::connection($connection);
|
DashboardLogger::log($connection->app->id, DashboardLogger::TYPE_CONNECTED, [
|
||||||
|
'origin' => "{$request->getUri()->getScheme()}://{$request->getUri()->getHost()}",
|
||||||
|
'socketId' => $connection->socketId,
|
||||||
|
]);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue