phasync
Swerve / publishRaw

Method

Swerve::publishRaw

Send $bytes unchanged to every subscriber of $topic, in every worker process of this swerve, this one included.

Description#

public static Swerve::publishRaw(
    string $topic,
    string $bytes
): void

For messages Swerve::publish cannot carry: bytes that are not valid UTF-8, such as a binary WebSocket frame, which publish() would fail to encode as JSON. A subscriber gets exactly $bytes, as a plain string, never decoded. The same delivery guarantees as publish() apply (order, at-most-once, never suspends the caller, and the rest); see its docblock. A topic may mix publish() and publishRaw() messages: each subscriber gets each one in its own shape.

Parameters#

$topic string
1 to 255 bytes
$bytes string
Any bytes, including none; at most 128 KiB

Errors / Exceptions#

ExceptionWhen
InvalidArgumentExceptionFor a topic or message outside those sizes, or a topic starting with "\0"
LogicExceptionDirectly in swerve.php, which the worker serves after: a coroutine started there waits instead

Examples#

Example 1A WebSocket handler forwards binary frames to the other workers
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\Swerve;
use Swerve\WebSocket;

// Binary WebSocket frames, forwarded to every worker's subscribers: publish() would fail to
// encode them as JSON, since a binary frame is not valid UTF-8.
$app = new RequestHandler(function (ClientRequest $request) {
    WebSocket::from($request, function (WebSocket $ws) {
        $ws->onMessage->listen(function (string $data, bool $binary) {
            if ($binary) {
                Swerve::publishRaw('frames', $data);      // to this and every other worker
            }
        });
        foreach (Swerve::subscribe('frames') as $frame) { // what this and every other connection sent
            $ws->sendBinary($frame);
        }
    });
});

if (debug_backtrace()) {
    return $app;   // swerve loads this file: it is the application's swerve.php
}

// Run directly: serve the application, send one binary frame, and print what comes back
require __DIR__ . '/../serve.php';
[$swerve, $addr] = swerve_start(__FILE__);
try {
    $connection = stream_socket_client("tcp://$addr", $errno, $error, 5);
    fwrite($connection, "GET /frames HTTP/1.1\r\nHost: example\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n"
        . "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n");
    $head = '';
    while (!str_contains($head, "\r\n\r\n")) {
        $head .= fread($connection, 1);
    }
    $mask    = "\1\2\3\4";
    $payload = pack('nN', 1, 42);                         // any bytes, not valid UTF-8
    fwrite($connection, "\x82" . chr(0x80 | strlen($payload)) . $mask . ($payload ^ str_repeat($mask, 32)));
    $head   = fread($connection, 2);
    $length = ord($head[1]) & 0x7F;
    echo 'sent ', bin2hex($payload), ', got back ', bin2hex((string) fread($connection, $length)), "\n";
    fclose($connection);
} finally {
    swerve_stop($swerve, false);
}
Output
sent 00010000002a, got back 00010000002a
Example 2
Swerve::publishRaw('frames', $binaryWebSocketFrame);

See also#