|
| 1 | +Server-Sent Events (SSE) is a web technology that enables a server to push real-time updates to `HttpCommand`. Unlike WebSockets, which provide full-duplex communication, SSE is unidirectional — data flows only from server to client. `HttpCommand` initiates the connection with a standard HTTP request, and the server responds with a text/event-stream content type, keeping the connection open and sending data as a stream of newline-delimited messages. Each message can include fields such as data, event, id, and retry. SSE is particularly well-suited for use cases like live feeds, log streaming, and AI chat completions, where the server needs to continuously deliver updates without the client repeatedly polling. |
| 2 | + |
| 3 | +## Basic steps to use SSE |
| 4 | + |
| 5 | +* Write a dyadic, non-result-returning function to process the event messages from the server. We'll call this function the "SSE handler". |
| 6 | + * The right argument is the event payload. |
| 7 | + * The left argument is a reference to the `HttpCommand` result namespace. |
| 8 | + * If you do not write an SSE handler, the event message will be displayed to the APL session. |
| 9 | +* Create an instance of `HttpCommand`. For example: `h←HttpCommand.New ''` |
| 10 | +* Set `URL` to the address of the host server. |
| 11 | +* Set `EnableSSE` to `1`. |
| 12 | +* Set `OnSSEfn` to the name of the function you wrote. |
| 13 | +* If you do **not** want `HttpCommand` to parse the event messages into a namespace format, set `ParseSSE` to `0`. |
| 14 | +* Run the `HttpCommand` instance, saving the reference to the result namespace. For example: `r←h.Run`<br/>This will start a listener on a separate thread. |
| 15 | +* Every time an event message is received, `HttpCommand` with pass either: |
| 16 | + * If `ParseSSE` is `0`, the unmodified event message is passed as the right argument to the SSE handler. |
| 17 | + * If `ParseSSE` is `1`, the a namespace containing the parsed event message is passed as the right argument to the SSE handler. |
| 18 | +* To stop the listener you can either hit interrupt or use the `Close` function in the result namespace. For example: `r.Close`. |
| 19 | +* You can also append the raw SSE event messages to a file by specifying [`OutFile`](operational-settings.md#outfile) and optionally [`MaxPayloadSize`](operational-settings.md#maxpayloadsize). If you specify `MaxPayloadSize`, the listener will quit when appending the current event message would exceed `MaxPayloadsize`. |
| 20 | + |
| 21 | +## Handling SSE Event Messages |
| 22 | +When the listener receives an SSE event message it will: |
| 23 | + |
| 24 | +* If `OutFile` is specified, append the raw event message to the file specified by `OutFile` |
| 25 | +* If `ParseSSE` is `1` (the default), the event message is parsed based on the [SSE specification](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation) into a namespace format that's more useful in an APL environment. The namespace contains: |
| 26 | + * `event` - the event name, or `'message'` if `event:` was not specified in the event message |
| 27 | + * `data` - a vector of character vectors, one per occurrence of `data:` in the event message |
| 28 | + * `id` - the `id:` of the event message or `''` if `id:` was not specified |
| 29 | + * `retry` - if specified in the event message, the reconnection time in milliseconds. Note that the current architecture is not able to do anything with `retry`. |
| 30 | +* If you have specified `OnSSEfn`, it is called passing: |
| 31 | + * a reference to the `HttpCommand` result namespace as its left argument |
| 32 | + * as its right argument - the namespace described above if `ParseSSE←1` or the raw event message if `ParseSSE←0` |
| 33 | +* If you have not specified `OnSSEfn` the event message is displayed in the session. |
| 34 | + |
| 35 | +To stop the listener you can either call `r.Close` or generate an interrupt. |
| 36 | + |
| 37 | +## `HttpCommand` Result Namespace Modifications |
| 38 | +If you're using SSE, the `HttpCommand` result namespace has some additional elements: |
| 39 | + |
| 40 | +* `SSEThread` is the thread on which the listener is running |
| 41 | +* `Close` is a function to terminate the listener |
| 42 | +* `CloseSSE` is a Boolean which the listener checks for whether to terminate or not. The `Close` function sets `CloseSSE←1` |
| 43 | +* Additionally, the display format of the result namespace is updated whenever `msg`, `rc`, `HttpStatus`, or `HttpMessage` are updated. |
| 44 | + |
| 45 | +## Example |
| 46 | +<pre><code> h←HttpCommand.New ( |
| 47 | + URL:'https://echo.websocket.org/.sse' |
| 48 | + ) |
| 49 | + h.Run |
| 50 | +[rc: ¯1 | msg: Server responded with SSE, but EnableSSE=0 | HTTP Status: 200 "OK" | ≢Data: 0] |
| 51 | +</code></pre> |
| 52 | +Duh! Need to set `EnableSSE←1` |
| 53 | +<pre><code>onSSE←{ |
| 54 | + ⍝ ⍺ - reference to HttpCommand result namespace |
| 55 | + ⍝ ⍵ - SSE payload |
| 56 | + '10'≡⍵.id: ⍺.Close ⍝ close listener when we get to id='10' |
| 57 | + ⍵.(event id) ⍝ otherwise display the event and id |
| 58 | + } |
| 59 | + |
| 60 | + h←HttpCommand.New ( |
| 61 | + URL:'https://echo.websocket.org/.sse' |
| 62 | + EnableSSE:1 |
| 63 | + OnSSEfn:'onSSE' |
| 64 | + ) |
| 65 | + r←h.Run |
| 66 | + server 1 |
| 67 | + request 2 |
| 68 | + time 3 |
| 69 | + time 4 |
| 70 | + time 5 |
| 71 | + time 6 |
| 72 | + time 7 |
| 73 | + time 8 |
| 74 | + time 9 |
| 75 | +</code></pre> |
0 commit comments