phpwebsocketphpwebsocketamphp

Get websocket pings from an open stream connection using Amp\Websocket?


I am using the readme example here:

https://github.com/amphp/websocket-client/blob/master/README.md

use Amp\Websocket;
use Amp\Delayed;
use Amp\Websocket\Connection;
use Amp\Websocket\Handshake;
use Amp\Websocket\Message;
use function Amp\Websocket\connect;

\Amp\Loop::run(function () use ($fn)
{
    try 
    {
        $connection = yield connect('wss://....');

        yield $connection->send('{
            "action":"authenticate",
            "data":{
                ...
            }
        }');
                
        while ($message = yield $connection->receive()) 
        {
            $payload = yield $message->buffer();

            // print the payload
            $this->info($payload);  

            // custom function to parse the payload
            $r = $fn($payload);

            if ($r == false) {
                $this->warn('Connection closed.');
                $connection->close();
                break;
            }
        }
    }
    catch (\Throwable $e) {
        $this->isError($e->getMessage(),true);
    }
    catch (\Exception $e) {
        $this->isError($e->getMessage(),true);
    }
});

Issue: The while loop will only run when a message is sent through the stream, no message, nothing ever can happen since it's in idle mode waiting.

Solution: How can I receive the ping or have the while loop run on the ping, and still collect the messages?

For instance, I would like to have control on checking some information, (such as the socket should remain open) however, it can only check that when a message is coming through the stream, this limits the script as it would only ever execute when there's an activity, thus waiting forever if no information is ever sent.

Pings are standard in web sockets based on the RFC: https://www.rfc-editor.org/rfc/rfc6455

in the Rfc6455Connection connection class, there are pings, but there is no documentation on how to access this or use this directly.

It would be cool to run the while loop on the ping and check if there is a message at the same time, is this possible?


Solution

  • amphp/websocket-client handles pings automatically and responds to them, so receiving messages is the only concern an API user should have.

    With Amp you can spawn multiple coroutines at any time using Amp\call / Amp\asyncCall, so you can e.g. close the connection after some idle time.

    Loop::run(function () {
        try {
          $connection = yield connect($uri);
    
          asyncCall(function () use ($connection) {
            while (true) {
              if (!$this->isActive()) {
                $connection->close();
                break;
              }
    
              yield Amp\delay(1000);
            }
          });
    
          yield $connection->send('...');
    
          while ($message = yield $connection->receive()) {
              $payload = yield $message->buffer();
    
              $r = $fn($payload);
    
              if ($r == false) {
                  $this->warn('Connection closed.');
                  $connection->close();
                  break;
              }
          }
      } catch (\Exception $e) {
          $this->isError($e->getMessage(),false);
      }
    });