Native WebSocket library for ReactPHP
Go to file
2024-02-22 16:24:49 +01:00
doc Renamed events in GroupManager 2024-02-22 02:01:12 +01:00
examples Fixed errors in examples 2024-02-21 21:40:29 +01:00
src Added method to access request from connection 2024-02-22 16:24:49 +01:00
tests Test cases for ConnectionGroup 2024-02-22 01:46:40 +01:00
.gitignore Moved frame logic to WebSocketCodec 2024-02-21 21:23:24 +01:00
composer.json Code cleanup, added phpstan 2024-02-21 23:48:13 +01:00
LICENSE Initial commit 2024-02-21 03:03:08 +01:00
phpstan.neon Code cleanup, added phpstan 2024-02-21 23:48:13 +01:00
phpunit.xml Moved frame logic to WebSocketCodec 2024-02-21 21:23:24 +01:00
README.md Updated readme 2024-02-22 02:06:09 +01:00

ReactPHP WebSockets

Installing

Install using composer:

$ composer require noccylabs/react-websocket

Why not Ratchet?

Ratchet is great! I've used Ratchet in the past, and it is a fantastic piece of code. It is however more application-centered, which means it doesn't do events and all that beautiful magic we've come to love ReactPHP for.

TL;DR - If you need to build an application with neatly wrapped classes without caring to much about the internals, go with Ratchet. If you want to work with websockets in the same way you work with sockets in ReactPHP, go with this library.

Missing Features

The following features are missing, or work in progress:

  • Idle timeout and ping timeout
  • Protocol errors should close with error codes
  • Exceptions

Server

The WebSocket handler is built as a HttpServer middleware. This makes sense as WebSocket as a protocol is running over HTTP. Connections are set up by the middleware and exposed via the connect event.

Data is written and read as with any DuplexStream, use the write() method to send data to the client, and listen for the text and binary events on the connection.

Note that the write() method sends text frames, if you want to send a binary frame use writeBinary().

Example

// This is the middleware that will intercept WebSocket handshakes
$websocket = new NoccyLabs\React\WebSocket\WebSocketMiddleware();

// Connect event handler, receives a WebSocketInterface.
// Ratchet handles security for you, this library does not. You should
// check everything important in the connect handler and reject anything
// that does not smell right. Here we just echo everything.
$websocket->on('connection', function (NoccyLabs\React\WebSocket\WebSocketInterface $connection) {
    $websocket->on('text', function ($text) use ($websocket) {
        $websocket->write($text);
    });
});

// The HTTP router that will handle other requests
$router = function (Psr\Http\Message\ServerRequestInterface $request) {
    return React\Http\Message\Response::plaintext("This is a websocket server");
};

// Create a HttpServer and insert the middleware
$http = new React\Http\HttpServer(
    $websocket,
    $router
);

// Create a socket and listen as you're used to
$socket = new React\Socket\SocketServer('0.0.0.0:8000');
$http->listen($socket); 

WebSocketMiddleware Events

connection

function (WebSocketInterface $member)

This event is emitted when a new WebSocket request has been accepted. The WebSocketConnection is passed as the first argument.

WebSocketConnection events

ping

function (string $payload)

This event will be emitted upon receiving a frame with a ping opcode. The pong response has already been sent automatically, unless 'no_auto_pong' is set in the context.

pong

function (string $payload)

This event will be emitted upon receiving a frame with a pong opcode.

text

function (string $payload)

This event will be emitted when a text data frame have been received and decoded.

binary

function (string $payload)

This event will be emitted when a binary data frame have been received and decoded.

close

function ()

error

function (?string $reason, ?int $code)

GroupManager events

create

function (ConnectionGroup $group)

destroy

function (ConnectionGroup $group)

ConnectionGroup events

join

function (WebSocketInterface $member)

leave

function (WebSocketInterface $member)