Как использовать объект Ratchet\Server\IoServer после запуска?

Я хочу запустить функцию, которая перебирает класс генератора. Функции генератора будут работать до тех пор, пока существует соединение Ratchet. Все, что мне нужно сделать, это сделать так, чтобы это произошло после выполнения метода run:

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;

require dirname(__DIR__) . '/xxx/vendor/autoload.php';

 $server = IoServer::factory(

    new HttpServer(
        new WsServer(
            new Chat()
        )
    ),

    8180,
    '0.0.0.0'

);

$server->run();

Это метод, который мне нужно запустить на сервере после его запуска:

function generatorFunction()
{

$products = r\table("tableOne")->changes()->run($conn);
 foreach ($products as $product) {
   yield $product['new_val'];
 }

}

Раньше я вызывал функцию перед $server->run() следующим образом:

for ( $gen = generatorFunction(); $gen->valid(); $gen->next()) {
 var_dump($gen->current());
}
$server->run();

Но это не позволяет клиенту установить соединение с сервером Ratchet. Я подозреваю, что это никогда не доходит до $server->run(), поскольку класс генератора повторяется.

Итак, теперь я хочу сначала запустить сервер, а затем вызвать этот метод генератора, чтобы он мог продолжать прослушивать изменения в rethinkdb.

Как я могу это сделать?


person 112233    schedule 17.03.2018    source источник


Ответы (1)


Начнем с примера:

<?php

require 'vendor/autoload.php';

class Chat implements \Ratchet\MessageComponentInterface {
    function onOpen(\Ratchet\ConnectionInterface $conn) { echo "connected.\n"; }
    function onClose(\Ratchet\ConnectionInterface $conn) {}
    function onError(\Ratchet\ConnectionInterface $conn, \Exception $e) {}
    function onMessage(\Ratchet\ConnectionInterface $from, $msg) {}
}

$loop = \React\EventLoop\Factory::create(); // create EventLoop best for given environment
$socket = new \React\Socket\Server('0.0.0.0:8180', $loop); // make a new socket to listen to (don't forget to change 'address:port' string)
$server = new \Ratchet\Server\IoServer(
    /* same things that go into IoServer::factory */
    new \Ratchet\Http\HttpServer(
        new \Ratchet\WebSocket\WsServer(
            new Chat() // dummy chat to test things out
        )
    ), 
    /* our socket and loop objects */
    $socket, 
    $loop
);

$loop->addPeriodicTimer(1, function (\React\EventLoop\Timer\Timer $timer) {
    echo "echo from timer!\n";
});

$server->run();

Чтобы достичь того, что вам нужно, вам не нужно запускать цикл до или после $server->run(), но его нужно запускать одновременно.

Для этого вам нужно зайти глубже Ratchet — в ReactPHP и его EventLoop. Если у вас есть доступ к интерфейсу цикла, добавление таймера (который выполняется один раз) или периодический таймер (каждую n-ю секунду) — проще простого.

person Michal Bieda    schedule 26.03.2018
comment
Я уже использую цикл событий, который извлекает данные каждую секунду. Но я хочу избежать этого и использовать метод changes(), найденный в rethinkdb, или, другими словами, функцию генератора, которая остановит другой процесс. Поэтому для этого, я думаю, мне нужно запустить сервер, а затем подключить его в фоновом режиме. - person 112233; 28.03.2018
comment
Клиентская библиотека php-rql остановит все на r\Cursor::requestMoreIfNecessary() и будет опрашивать базу данных, пока не появятся новые данные. Так что да, вам осталось запустить отдельный процесс в фоновом режиме и использовать IPC для вернуть данные. Или используйте среду параллелизма, например Amphp, и напишите собственный неблокирующий драйвер для rethinkdb. - person Michal Bieda; 28.03.2018
comment
@MichalBieda В этом случае, как я могу отправлять сообщения по таймеру для пользователей чата? Например: $chat = new Chat(); $loop = \React\EventLoop\Factory::create(); $socket = new \React\Socket\Server('0.0.0.0:8080', $loop); $server = new \Ratchet\Server\IoServer(new \Ratchet\Http\HttpServer(new \Ratchet\WebSocket\WsServer($chat)),$socket, $loop); $loop->addPeriodicTimer(1, function (\React\EventLoop\Timer\Timer $timer) { if (!isset($chat)) return; $msg = "echo from timer!"; $chat->broadcast($msg); }); - person MCunha98; 28.01.2020
comment
@MCunha98 в addPeriodicTimer, когда вы объявляете функцию, вы должны добавить use ($chat) - так что это выглядит так: function (\ReactEventLoop\Timer\Timer $timer) use ($chat) { .... Без этого переменная $chat внутри тела функции всегда будет неопределенной/нулевой. - person Michal Bieda; 29.01.2020
comment
Спасибо @MichalBieda, я следую примеру подписки Ratchet с ZeroMQ, и это сработало (после большой борьбы с установками dll в Windows). - person MCunha98; 29.01.2020