Search code examples
phprethinkdbratchet

How do I use a Ratchet\Server\IoServer object after run executed?


I want to run a function that iterates through a generator class. The generator functions would run as long as the Ratchet connection is alive. All I need to do is to make this happen after the run method is executed:

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();

This is the method I need to run in the server after it is started:

function generatorFunction()
{

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

}

Previously I was calling the function before $server->run() like this:

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

But this doesn't allow the client to establish a connection to the Ratchet server. I suspect it never comes to $server->run() as the generator class is being iterated.

So now, I want to start the server first, then call this generator method so that it can keep listening to changes in rethinkdb.

How do I do that?


Solution

  • Let's start by example:

    <?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();
    

    To achieve what you need you don't have to run the loop before or after the $server->run() but it needs to be run simultaneously.

    For that you need to get deeper than Ratchet - to ReactPHP and its EventLoop. If you have access to the loop interface then adding a timer (that executes once) or a periodic timer (every nth second) is a piece of cake.