Skip to content

Commit a874ba8

Browse files
authored
SSE Support and Minor Cleanups (#66)
* Initial commit of SSE support * SSE documentation * minor fixes after review * sse documentation * Update version to 5.11.0
1 parent 758976c commit a874ba8

5 files changed

Lines changed: 256 additions & 13 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
*.dlf
22
*.rng*
3-
site/
3+
site/
4+
.claude/
5+
.devcontainer/

docs/sse-settings.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
SSE settings control whether an `HttpCommand` instance will accept Server-Sent Events (SSEs).
2+
3+
## Instance settings
4+
5+
### `EnableSSE`
6+
7+
|--|--|
8+
|Description|A Boolean that enables `HttpCommand` to process Server-Sent events.<ul><li>`1` = process SSEs</li><li>`0` = do not process SSEs</li></ul>|
9+
|Default|`0`|
10+
|Example(s)|`h.EnableSSE←1`|
11+
|Details|If `EnableSSE` is `0` and `HttpCommand` receives an SSE response from the host, indicated by a `content-type` header of `text/event-stream`, `HttpCommand` will terminate with `msg` of "Server responded with SSE, but EnableSSE=0"|
12+
13+
### `ParseSSE`
14+
15+
|--|--|
16+
|Description|A Boolean the indicates whether to process received SSE event messages into a more convenient namespace format. Valid values are:<ul><li>`1` (the default) - parse into a namespace See [Handling SSE Event Messages](sse.md#handling-sse-event-messages).</li><li>`0` - do not parse, just return the raw event message</li></ul>|
17+
|Default|`1`|
18+
|Example(s)|`h.ParseSSE←0 ⍝ don't parse, just use raw event message`|
19+
|Details|If using `ParseSSE←0`, see [Parsing an event stream](https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream).|
20+
21+
### `OnSSEfn`
22+
23+
|--|--|
24+
|Description|`OnSSEfn` is the name of the function that you write that will be called when `HttpCommand` receives an SSE event message. The function should be dyadic and not return a result. The left argument is a reference to the `HttpCommand` result namespace. The right argument is either the raw SSE event message (if `ParseSSE←0`) or a namespace containing the parsed SSE event message (if `ParseSSE←1').
25+
|Default|`''`|
26+
|Example(s)|The following assumes that `ParseSSE←1`.<br/><pre style="font-family:APL;">onSSE←{'done'≡⍵.event: ⍺.Close ⍝ close the listener on a "done" event<br/> ⎕←⍵.(event id) ⍝ otherwise display the event name and id}<br/>r.OnSSEfn←'onSSE'</pre>|
27+
|Details|If `OnSSEfn` is not specified, `HttpCommand` will display the SSE event message to the session.|

docs/sse.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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>

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ nav:
1616
- 'Operational Settings': 'operational-settings.md' # complete
1717
- 'Conga-related Settings': 'conga-settings.md' # complete
1818
- 'Proxy-related Settings': 'proxy-settings.md' # complete
19+
- 'SSE-related Settings': 'sse-settings.md'
1920
- 'Shared Methods':
2021
- 'Shortcut Methods': 'shortcut-methods.md' # complete
2122
- 'Encode/Decode Methods': 'encode-methods.md' # complete
@@ -30,6 +31,7 @@ nav:
3031
- 'Request Content Types' : 'content-types.md'
3132
- 'HttpCommand and Conga' : 'conga.md' # complete
3233
- 'Secure Communications' : 'secure.md' # complete
34+
- 'Using Server-Sent Events (SSE)' : 'sse.md' # complete
3335
- 'Using a Proxy Server': 'proxy.md'
3436
- 'Integrating HttpCommand' : 'integrating.md' # complete
3537
- About:

0 commit comments

Comments
 (0)