33[ ![ CI status] ( https://github.com/clue/reactphp-eventsource/actions/workflows/ci.yml/badge.svg )] ( https://github.com/clue/reactphp-eventsource/actions )
44[ ![ 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 )
55
6- Event-driven EventSource client, receiving streaming messages from any HTML5 Server-Sent Events (SSE) server,
7- built on top of [ ReactPHP] ( https://reactphp.org/ ) .
6+ Instant real-time updates. Lightweight EventSource client receiving live
7+ messages via HTML5 Server-Sent Events (SSE). Fast stream processing built on top
8+ of [ ReactPHP] ( https://reactphp.org/ ) 's event-driven architecture.
89
910> Note: This project is in early alpha stage! Feel free to report any issues you encounter.
1011
@@ -13,25 +14,48 @@ built on top of [ReactPHP](https://reactphp.org/).
1314* [ Quickstart example] ( #quickstart-example )
1415* [ Usage] ( #usage )
1516 * [ EventSource] ( #eventsource )
17+ * [ message event] ( #message-event )
18+ * [ open event] ( #open-event )
19+ * [ error event] ( #error-event )
20+ * [ EventSource::$readyState] ( #eventsourcereadystate )
21+ * [ EventSource::$url] ( #eventsourceurl )
22+ * [ close()] ( #close )
23+ * [ MessageEvent] ( #messageevent )
24+ * [ MessageEvent::$data] ( #messageeventdata )
25+ * [ MessageEvent::$lastEventId] ( #messageeventlasteventid )
26+ * [ MessageEvent::$type] ( #messageeventtype )
1627* [ Install] ( #install )
1728* [ Tests] ( #tests )
1829* [ License] ( #license )
30+ * [ More] ( #more )
1931
2032## Quickstart example
2133
2234Once [ installed] ( #install ) , you can use the following code to stream messages
2335from any Server-Sent Events (SSE) server endpoint:
2436
37+ ```
38+ data: {"name":"Alice","message":"Hello everybody!"}
39+
40+ data: {"name":"Bob","message":"Hey Alice!"}
41+
42+ data: {"name":"Carol","message":"Nice to see you Alice!"}
43+
44+ data: {"name":"Alice","message":"What a lovely chat!"}
45+
46+ data: {"name":"Bob","message":"Yeah, all powered by ReactPHP, such an awesome piece of technology :)"}
47+ ```
48+
2549``` php
2650$es = new Clue\React\EventSource\EventSource('https://example.com/stream.php');
2751
2852$es->on('message', function (Clue\React\EventSource\MessageEvent $message) {
29- //$data = json_decode($message->data);
30- var_dump($ message) ;
53+ $json = json_decode($message->data);
54+ echo $json->name . ': ' . $json-> message . PHP_EOL ;
3155});
3256```
3357
34- See the [ examples] ( examples ) .
58+ See the [ examples] ( examples/ ) .
3559
3660## Usage
3761
@@ -77,6 +101,205 @@ here in order to use the [default loop](https://github.com/reactphp/event-loop#l
77101This value SHOULD NOT be given unless you're sure you want to explicitly use a
78102given event loop instance.
79103
104+ #### message event
105+
106+ The ` message ` event will be emitted whenever an EventSource message is received.
107+
108+ ``` php
109+ $es->on('message', function (Clue\React\EventSource\MessageEvent $message) {
110+ // $json = json_decode($message->data);
111+ var_dump($message);
112+ });
113+ ```
114+
115+ The EventSource stream may emit any number of messages over its lifetime. Each
116+ ` message ` event will receive a [ ` MessageEvent ` object] ( #messageevent ) .
117+
118+ The [ ` MessageEvent::$data ` property] ( #messageeventdata ) can be used to access
119+ the message payload data. It is commonly used for transporting structured data
120+ such as JSON:
121+
122+ ```
123+ data: {"name":"Alice","age":30}
124+
125+ data: {"name":"Bob","age":50}
126+ ```
127+ ``` php
128+ $es->on('message', function (Clue\React\EventSource\MessageEvent $message) {
129+ $json = json_decode($message->data);
130+ echo "{$json->name} is {$json->age} years old" . PHP_EOL;
131+ });
132+ ```
133+
134+ The EventSource stream may specify an event type for each incoming message. This
135+ ` event ` field can be used to emit appropriate event types like this:
136+
137+ ```
138+ data: Alice
139+ event: join
140+
141+ data: Hello!
142+ event: chat
143+
144+ data: Bob
145+ event: leave
146+ ```
147+ ``` php
148+ $es->on('join', function (Clue\React\EventSource\MessageEvent $message) {
149+ echo $message->data . ' joined' . PHP_EOL;
150+ });
151+
152+ $es->on('chat', function (Clue\React\EventSource\MessageEvent $message) {
153+ echo 'Message: ' . $message->data . PHP_EOL;
154+ });
155+
156+ $es->on('leave', function (Clue\React\EventSource\MessageEvent $message) {
157+ echo $message->data . ' left' . PHP_EOL;
158+ });
159+ ```
160+
161+ See also [ ` MessageEvent::$type ` property] ( #messageeventtype ) for more details.
162+
163+ #### open event
164+
165+ The ` open ` event will be emitted when the EventSource connection is successfully established.
166+
167+ ``` php
168+ $es->on('open', function () {
169+ echo 'Connection opened' . PHP_EOL;
170+ });
171+ ```
172+
173+ Once the EventSource connection is open, it may emit any number of
174+ [ ` message ` events] ( #message-event ) .
175+
176+ If the connection can not be opened successfully, it will emit an
177+ [ ` error ` event] ( #error-event ) instead.
178+
179+ #### error event
180+
181+ The ` error ` event will be emitted when the EventSource connection fails.
182+ The event receives a single ` Exception ` argument for the error instance.
183+
184+ ``` php
185+ $redis->on('error', function (Exception $e) {
186+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
187+ });
188+ ```
189+
190+ The EventSource connection will be retried automatically when it is temporarily
191+ disconnected. If the server sends a non-successful HTTP status code or an
192+ invalid ` Content-Type ` response header, the connection will fail permanently.
193+
194+ ``` php
195+ $es->on('error', function (Exception $e) use ($es) {
196+ if ($es->readyState === Clue\React\EventSource\EventSource::CLOSED) {
197+ echo 'Permanent error: ' . $e->getMessage() . PHP_EOL;
198+ } else {
199+ echo 'Temporary error: ' . $e->getMessage() . PHP_EOL;
200+ }
201+ });
202+ ```
203+
204+ See also the [ ` EventSource::$readyState ` property] ( #eventsourcereadystate ) .
205+
206+ #### EventSource::$readyState
207+
208+ The ` int $readyState ` property can be used to
209+ check the current EventSource connection state.
210+
211+ The state is read-only and can be in one of three states over its lifetime:
212+
213+ * ` EventSource::CONNECTING `
214+ * ` EventSource::OPEN `
215+ * ` EventSource::CLOSED `
216+
217+ #### EventSource::$url
218+
219+ The ` readonly string $url ` property can be used to
220+ get the EventSource URL as given to the constructor.
221+
222+ #### close()
223+
224+ The ` close(): void ` method can be used to
225+ forcefully close the EventSource connection.
226+
227+ This will close any active connections or connection attempts and go into the
228+ ` EventSource::CLOSED ` state.
229+
230+ ### MessageEvent
231+
232+ The ` MessageEvent ` class represents an incoming EventSource message.
233+
234+ #### MessageEvent::$data
235+
236+ The ` readonly string $data ` property can be used to
237+ access the message payload data.
238+
239+ ```
240+ data: hello
241+ ```
242+ ``` php
243+ assert($message->data === 'hello');
244+ ```
245+
246+ The ` data ` field may also span multiple lines. This is commonly used for
247+ transporting structured data such as JSON:
248+
249+ ```
250+ data: {
251+ data: "message": "hello"
252+ data: }
253+ ```
254+ ``` php
255+ $json = json_decode($message->data);
256+ assert($json->message === 'hello');
257+ ```
258+
259+ If the message does not contain a ` data ` field or the ` data ` field is empty, the
260+ message will be discarded without emitting an event.
261+
262+ #### MessageEvent::$lastEventId
263+
264+ The ` readonly string $lastEventId ` property can be used to
265+ access the last event ID.
266+
267+ ```
268+ data: hello
269+ id: 1
270+ ```
271+ ``` php
272+ assert($message->data === 'hello');
273+ assert($message->lastEventId === '1');
274+ ```
275+
276+ Internally, the ` id ` field will automatically be used as the ` Last-Event-ID ` HTTP
277+ request header in case the connection is interrupted.
278+
279+ If the message does not contain an ` id ` field, the ` $lastEventId ` property will
280+ be the value of the last ID received. If no previous message contained an ID, it
281+ will default to an empty string.
282+
283+ #### MessageEvent::$type
284+
285+ The ` readonly string $type ` property can be used to
286+ access the message event type.
287+
288+ ```
289+ data: Alice
290+ event: join
291+ ```
292+ ``` php
293+ assert($message->data === 'Alice');
294+ assert($message->type === 'join');
295+ ```
296+
297+ Internally, the ` event ` field will be used to emit the appropriate event type.
298+ See also [ ` message ` event] ( #message-event ) .
299+
300+ If the message does not contain a ` event ` field or the ` event ` field is empty,
301+ the ` $type ` property will default to ` message ` .
302+
80303## Install
81304
82305The recommended way to install this library is [ through Composer] ( https://getcomposer.org/ ) .
@@ -105,7 +328,7 @@ $ composer install
105328To run the test suite, go to the project root and run:
106329
107330``` bash
108- $ php vendor/bin/phpunit
331+ $ vendor/bin/phpunit
109332```
110333
111334## License
@@ -114,3 +337,12 @@ This project is released under the permissive [MIT license](LICENSE).
114337
115338> Did you know that I offer custom development services and issuing invoices for
116339 sponsorships of releases and for contributions? Contact me (@clue ) for details.
340+
341+ ## More
342+
343+ * If you want to learn more about processing streams of data, refer to the documentation of
344+ the underlying [ react/stream] ( https://github.com/reactphp/stream ) component.
345+
346+ * If you're looking to run the server side of your Server-Sent Events (SSE)
347+ application, you may want to use the powerful server implementation provided
348+ by [ Framework X] ( https://framework-x.org/ ) .
0 commit comments