From 96a9e338ce50fd4c1fde56e352e5db87a8f3c20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 11 Apr 2022 12:53:26 +0200 Subject: [PATCH 1/2] Add API documentation --- README.md | 229 +++++++++++++++++++++++++++++++++++++++++++- examples/stream.php | 2 +- 2 files changed, 226 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3106b3b..4c6fbb6 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,16 @@ built on top of [ReactPHP](https://reactphp.org/). * [Quickstart example](#quickstart-example) * [Usage](#usage) * [EventSource](#eventsource) + * [message event](#message-event) + * [open event](#open-event) + * [error event](#error-event) + * [EventSource::$readyState](#eventsourcereadystate) + * [EventSource::$url](#eventsourceurl) + * [close()](#close) + * [MessageEvent](#messageevent) + * [MessageEvent::$data](#messageeventdata) + * [MessageEvent::$lastEventId](#messageeventlasteventid) + * [MessageEvent::$type](#messageeventtype) * [Install](#install) * [Tests](#tests) * [License](#license) @@ -22,16 +32,28 @@ built on top of [ReactPHP](https://reactphp.org/). Once [installed](#install), you can use the following code to stream messages from any Server-Sent Events (SSE) server endpoint: +``` +data: {"name":"Alice","message":"Hello everybody!"} + +data: {"name":"Bob","message":"Hey Alice!"} + +data: {"name":"Carol","message":"Nice to see you Alice!"} + +data: {"name":"Alice","message":"What a lovely chat!"} + +data: {"name":"Bob","message":"Yeah, all powered by ReactPHP, such an awesome piece of technology :)"} +``` + ```php $es = new Clue\React\EventSource\EventSource('https://example.com/stream.php'); $es->on('message', function (Clue\React\EventSource\MessageEvent $message) { - //$data = json_decode($message->data); - var_dump($message); + $json = json_decode($message->data); + echo $json->name . ': ' . $json->message . PHP_EOL; }); ``` -See the [examples](examples). +See the [examples](examples/). ## Usage @@ -77,6 +99,205 @@ here in order to use the [default loop](https://github.com/reactphp/event-loop#l This value SHOULD NOT be given unless you're sure you want to explicitly use a given event loop instance. +#### message event + +The `message` event will be emitted whenever an EventSource message is received. + +```php +$es->on('message', function (Clue\React\EventSource\MessageEvent $message) { + // $json = json_decode($message->data); + var_dump($message); +}); +``` + +The EventSource stream may emit any number of messages over its lifetime. Each +`message` event will receive a [`MessageEvent` object](#messageevent). + +The [`MessageEvent::$data` property](#messageeventdata) can be used to access +the message payload data. It is commonly used for transporting structured data +such as JSON: + +``` +data: {"name":"Alice","age":30} + +data: {"name":"Bob","age":50} +``` +```php +$es->on('message', function (Clue\React\EventSource\MessageEvent $message) { + $json = json_decode($message->data); + echo "{$json->name} is {$json->age} years old" . PHP_EOL; +}); +``` + +The EventSource stream may specify an event type for each incoming message. This +`event` field can be used to emit appropriate event types like this: + +``` +data: Alice +event: join + +data: Hello! +event: chat + +data: Bob +event: leave +``` +```php +$es->on('join', function (Clue\React\EventSource\MessageEvent $message) { + echo $message->data . ' joined' . PHP_EOL; +}); + +$es->on('chat', function (Clue\React\EventSource\MessageEvent $message) { + echo 'Message: ' . $message->data . PHP_EOL; +}); + +$es->on('leave', function (Clue\React\EventSource\MessageEvent $message) { + echo $message->data . ' left' . PHP_EOL; +}); +``` + +See also [`MessageEvent::$type` property](#messageeventtype) for more details. + +#### open event + +The `open` event will be emitted when the EventSource connection is successfully established. + +```php +$es->on('open', function () { + echo 'Connection opened' . PHP_EOL; +}); +``` + +Once the EventSource connection is open, it may emit any number of +[`message` events](#message-event). + +If the connection can not be opened successfully, it will emit an +[`error` event](#error-event) instead. + +#### error event + +The `error` event will be emitted when the EventSource connection fails. +The event receives a single `Exception` argument for the error instance. + +```php +$redis->on('error', function (Exception $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +}); +``` + +The EventSource connection will be retried automatically when it is temporarily +disconnected. If the server sends a non-successful HTTP status code or an +invalid `Content-Type` response header, the connection will fail permanently. + +```php +$es->on('error', function (Exception $e) use ($es) { + if ($es->readyState === Clue\React\EventSource\EventSource::CLOSED) { + echo 'Permanent error: ' . $e->getMessage() . PHP_EOL; + } else { + echo 'Temporary error: ' . $e->getMessage() . PHP_EOL; + } +}); +``` + +See also the [`EventSource::$readyState` property](#eventsourcereadystate). + +#### EventSource::$readyState + +The `int $readyState` property can be used to +check the current EventSource connection state. + +The state is read-only and can be in one of three states over its lifetime: + +* `EventSource::CONNECTING` +* `EventSource::OPEN` +* `EventSource::CLOSED` + +#### EventSource::$url + +The `readonly string $url` property can be used to +get the EventSource URL as given to the constructor. + +#### close() + +The `close(): void` method can be used to +forcefully close the EventSource connection. + +This will close any active connections or connection attempts and go into the +`EventSource::CLOSED` state. + +### MessageEvent + +The `MessageEvent` class represents an incoming EventSource message. + +#### MessageEvent::$data + +The `readonly string $data` property can be used to +access the message payload data. + +``` +data: hello +``` +```php +assert($message->data === 'hello'); +``` + +The `data` field may also span multiple lines. This is commonly used for +transporting structured data such as JSON: + +``` +data: { +data: "message": "hello" +data: } +``` +```php +$json = json_decode($message->data); +assert($json->message === 'hello'); +``` + +If the message does not contain a `data` field or the `data` field is empty, the +message will be discarded without emitting an event. + +#### MessageEvent::$lastEventId + +The `readonly string $lastEventId` property can be used to +access the last event ID. + +``` +data: hello +id: 1 +``` +```php +assert($message->data === 'hello'); +assert($message->lastEventId === '1'); +``` + +Internally, the `id` field will automatically be used as the `Last-Event-ID` HTTP +request header in case the connection is interrupted. + +If the message does not contain an `id` field, the `$lastEventId` property will +be the value of the last ID received. If no previous message contained an ID, it +will default to an empty string. + +#### MessageEvent::$type + +The `readonly string $type` property can be used to +access the message event type. + +``` +data: Alice +event: join +``` +```php +assert($message->data === 'Alice'); +assert($message->type === 'join'); +``` + +Internally, the `event` field will be used to emit the appropriate event type. +See also [`message` event](#message-event). + +If the message does not contain a `event` field or the `event` field is empty, +the `$type` property will default to `message`. + ## Install The recommended way to install this library is [through Composer](https://getcomposer.org/). @@ -105,7 +326,7 @@ $ composer install To run the test suite, go to the project root and run: ```bash -$ php vendor/bin/phpunit +$ vendor/bin/phpunit ``` ## License diff --git a/examples/stream.php b/examples/stream.php index 5b6a7cf..b0ae914 100644 --- a/examples/stream.php +++ b/examples/stream.php @@ -9,7 +9,7 @@ $es = new Clue\React\EventSource\EventSource($argv[1]); $es->on('message', function (Clue\React\EventSource\MessageEvent $message) { - //$data = json_decode($message->data); + // $json = json_decode($message->data); var_dump($message); }); From dbc1d159ddc6fa35a4aa17f108f34840babf3b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Mon, 11 Apr 2022 13:16:07 +0200 Subject: [PATCH 2/2] Improve documentation, reference ReactPHP and Framework X --- README.md | 15 +++++++++++++-- composer.json | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4c6fbb6..adce838 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ [![CI status](https://github.com/clue/reactphp-eventsource/actions/workflows/ci.yml/badge.svg)](https://github.com/clue/reactphp-eventsource/actions) [![installs on Packagist](https://img.shields.io/packagist/dt/clue/reactphp-eventsource?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/clue/reactphp-eventsource) -Event-driven EventSource client, receiving streaming messages from any HTML5 Server-Sent Events (SSE) server, -built on top of [ReactPHP](https://reactphp.org/). +Instant real-time updates. Lightweight EventSource client receiving live +messages via HTML5 Server-Sent Events (SSE). Fast stream processing built on top +of [ReactPHP](https://reactphp.org/)'s event-driven architecture. > Note: This project is in early alpha stage! Feel free to report any issues you encounter. @@ -26,6 +27,7 @@ built on top of [ReactPHP](https://reactphp.org/). * [Install](#install) * [Tests](#tests) * [License](#license) +* [More](#more) ## Quickstart example @@ -335,3 +337,12 @@ This project is released under the permissive [MIT license](LICENSE). > Did you know that I offer custom development services and issuing invoices for sponsorships of releases and for contributions? Contact me (@clue) for details. + +## More + +* If you want to learn more about processing streams of data, refer to the documentation of + the underlying [react/stream](https://github.com/reactphp/stream) component. + +* If you're looking to run the server side of your Server-Sent Events (SSE) + application, you may want to use the powerful server implementation provided + by [Framework X](https://framework-x.org/). diff --git a/composer.json b/composer.json index f34cdb4..4a4c713 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "clue/reactphp-eventsource", - "description": "Event-driven EventSource client, receiving streaming messages from any HTML5 Server-Sent Events (SSE) server, built on top of ReactPHP", + "description": "Instant real-time updates. Lightweight EventSource client receiving live messages via HTML5 Server-Sent Events (SSE). Fast stream processing built on top of ReactPHP's event-driven architecture.", "keywords": ["EventSource", "Server-Side Events", "SSE", "event-driven", "ReactPHP", "async"], "homepage": "https://github.com/clue/reactphp-eventsource", "license": "MIT",