Thruway управлять подписками - PullRequest
0 голосов
/ 07 мая 2018

Я пытаюсь настроить сервер веб-сокетов через 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 Ответ

0 голосов
/ 07 мая 2018

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

На стороне клиента с автобаном (последняя версия), когда вы подписываетесь на тему, а затем публикуете в этой теме, 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 будет отправлять сообщения всем, кто подписался на тему, кроме отправителя. Трансляция с другой стороны не исключает отправителя.

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

...