Thruway управлять подписками

Я пытаюсь настроить сервер веб-сокетов через Thruway, который может управлять несколькими группами. Что-то вроде приложения чата, где каждый клиент может подписаться на одного или нескольких одновременно и транслировать сообщения на всю комнату чата. Мне удалось сделать это с древней версией Ratchet, но, поскольку она работает не очень гладко, я хотел переключиться на Thruway. К сожалению, я не могу найти что-либо для управления группами. Пока у меня есть следующее как websocket-manager, и клиенты используют текущую версию Autobahn | js (18.x).

У кого-нибудь есть подсказка, можно ли управлять группами подписок с помощью чего-то вроде следующего?

<?php

require_once __DIR__.'/../vendor/autoload.php';

use Thruway\Peer\Router;
use Thruway\Transport\RatchetTransportProvider;

$router = new Router();
$router->addTransportProvider(new RatchetTransportProvider("0.0.0.0", 9090));

$router->start();

1

Решение

С ThruWay все немного отличается от старого Ratchet. Во-первых, Thruway не является сервером WAMP. Это просто роутер. Так что у него нет экземпляра сервера, как у старого Rathcet, который позволяет обернуть все функции сервера. Но он получит только пакет сообщений и route их на другие сеансы в той же области в зависимости от их подписки. Если вы когда-либо использовали socket.io, идея области похожа на различные подключения, поэтому вы можете ограничить свои сеансы или подключения одним пространством имен или разделить функциональность различных экземпляров сокетов, таких как администрация, посетители и т. Д.

На стороне клиента с autobahn (последняя версия), когда вы подписываетесь на тему, а затем публикуете в этой теме, thruway автоматически обнаруживает подписчиков темы и отправляет им сообщения в той же области. Но в старых храповиках вам нужно обрабатывать это вручную, сохраняя массив доступных каналов, и добавлять пользователей к каждому каналу, когда они подписываются, а также рассылать сообщения этим пользователям в теме, просматривая их. Это было действительно больно.

Если вы хотите использовать вызовы RPC на стороне сервера и не хотите включать некоторые из ваших вещей на стороне клиента, вы все равно можете использовать класс internalClient на стороне сервера. Концептуально Внутренний клиент — это еще один сеанс, который подключается к вашему клиенту через клиент и обрабатывает некоторые функции внутри, не подвергая других клиентов. Он получает пакеты сообщений и делает что-то в нем, а затем возвращает результат обратно запрошенному клиентскому соединению. Мне потребовалось некоторое время, чтобы понять, как это работает, но однажды я понял, что идея позади имеет больше смысла.

так немного кода, чтобы объяснить лучше,

В вашем экземпляре маршрутизатора вам нужно будет добавить модуль (обратите внимание, что в примерах пакетов voxys / thruway нет ничего странного во внутреннем клиенте)

server.php

require __DIR__ . "/../bootstrap.php";
require __DIR__ . '/InternalClient.php';

$port = 8080;
$output->writeln([
sprintf('Starting Sockets Service on Port [%s]', $port),
]);
$router = new Router();

$router->registerModule(new RatchetTransportProvider("127.0.0.1", $port));   // use 0.0.0.0 if you want to expose outside world

// common realm ( realm1 )
$router->registerModule(
new InternalClient()    // instantiate the Socket class now
);

// administration realm (administration)
// $router->registerModule(new \AdminClient());

$router->start();

Это инициализирует маршрутизатор Thruway и подключит к нему экземпляр внутреннего клиента. Теперь в файле InternalClient.php вы сможете получить доступ как к текущему маршруту, так и к текущим подключенным клиентам. В приведенном ими примере маршрутизатор не является частью экземпляра, поэтому вы застреваете только со свойством идентификатора сеанса новых соединений.

InternalClient.php

<?php

use Thruway\Module\RouterModuleInterface;
use Thruway\Peer\Client;
use Thruway\Peer\Router;
use Thruway\Peer\RouterInterface;
use Thruway\Logging\Logger;
use React\EventLoop\LoopInterface;

class InternalClient extends Client implements RouterModuleInterface
{
protected $_router;

/**
* Contructor
*/
public function __construct()
{
parent::__construct("realm1");
}

/**
* @param RouterInterface $router
* @param LoopInterface $loop
*/
public function initModule(RouterInterface $router, LoopInterface $loop)
{
$this->_router = $router;

$this->setLoop($loop);

$this->_router->addInternalClient($this);
}

/**
* @param \Thruway\ClientSession $session
* @param \Thruway\Transport\TransportInterface $transport
*/
public function onSessionStart($session, $transport)
{
// TODO: now that the session has started, setup the stuff

echo "--------------- Hello from InternalClient ------------\n";
$session->register('com.example.getphpversion', [$this, 'getPhpVersion']);

$session->subscribe('wamp.metaevent.session.on_join',  [$this, 'onSessionJoin']);
$session->subscribe('wamp.metaevent.session.on_leave', [$this, 'onSessionLeave']);
}

/**
* Handle on new session joined.
* This is where session is initially created and client is connected to socket server
*
* @param array $args
* @param array $kwArgs
* @param array $options
* @return void
*/
public function onSessionJoin($args, $kwArgs, $options) {
$sessionId = $args && $args[0];
$connectedClientSession = $this->_router->getSessionBySessionId($sessionId);
Logger::debug($this, 'Client '. $sessionId. ' connected');
}

/**
* Handle on session left.
*
* @param array $args
* @param array $kwArgs
* @param array $options
* @return void
*/
public function onSessionLeave($args, $kwArgs, $options) {

$sessionId = $args && $args[0];

Logger::debug($this, 'Client '. $sessionId. ' left');

// Below won't work because once this event is triggered, client session is already ended
// and cleared from router. If you need to access closed session, you may need to implement
// a cache service such as Redis to access data manually.
//$connectedClientSession = $this->_router->getSessionBySessionId($sessionId);
}

/**
* RPC Call messages
* These methods will run internally when it is called from another client.
*/
private function getPhpVersion() {

// You can emit or broadcast another message in this case
$this->emitMessage('com.example.commonTopic', 'phpVersion', array('msg'=> phpVersion()));

$this->broadcastMessage('com.example.anotherTopic', 'phpVersionRequested', array('msg'=> phpVersion()));

// and return result of your rpc call back to requester
return [phpversion()];
}

/**
* @return Router
*/
public function getRouter()
{
return $this->_router;
}


/**
* @param $topic
* @param $eventName
* @param $msg
* @param null $exclude
*/
protected function broadcastMessage($topic, $eventName, $msg)
{
$this->emitMessage($topic, $eventName, $msg, false);
}

/**
* @param $topic
* @param $eventName
* @param $msg
* @param null $exclude
*/
protected function emitMessage($topic, $eventName, $msg, $exclude = true)
{
$this->session->publish($topic, array($eventName), array('data' => $msg), array('exclude_me' => $exclude));
}

}

Несколько вещей, чтобы отметить в приведенном выше примере кода,
— Чтобы получить сообщение в теме, на стороне клиента необходимо подписаться на эту тему.
— Внутренний клиент может публиковать / излучать / транслировать любую тему без подписки в той же области.
— функции широковещания / передачи не являются частью первоначального сквозного подхода, я придумал, чтобы сделать публикации немного легче с моей стороны. emit будет отправлять пакет сообщений всем, кто подписался на тему, кроме отправителя. Трансляция с другой стороны не исключает отправителя.

Я надеюсь, что эта информация немного поможет понять концепцию.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]