diff options
| author | Thijs Schreijer <thijs@thijsschreijer.nl> | 2026-08-31 22:27:42 +0200 |
|---|---|---|
| committer | Thijs Schreijer <thijs@thijsschreijer.nl> | 2026-09-01 07:59:54 +0200 |
| commit | cd6b41a13af403d32e08ff416e60982b5cb718dc (patch) | |
| tree | 3865d91753fd636a866d4711f50ab27613e58634 /samples | |
| parent | c5f169ec303a70707bc48fbece9b52cc90a48de0 (diff) | |
| download | luasocket-feat/sse.tar.gz luasocket-feat/sse.tar.bz2 luasocket-feat/sse.zip | |
Add SSE sink (socket.sse module)feat/sse
Implements SSE by using the replacement body sink. Replaces
the sink with an SSE parser if the response is a text stream.
Example application included
Diffstat (limited to 'samples')
| -rw-r--r-- | samples/README | 9 | ||||
| -rw-r--r-- | samples/sse.lua | 63 |
2 files changed, 72 insertions, 0 deletions
diff --git a/samples/README b/samples/README index 4ee06b6..5fff925 100644 --- a/samples/README +++ b/samples/README | |||
| @@ -104,6 +104,15 @@ Unix machines. It uses the lp.lua implementation, in the | |||
| 104 | samples directory. Just run 'lua lpr.lua <filename> | 104 | samples directory. Just run 'lua lpr.lua <filename> |
| 105 | queue=<printername>' and the file will print! | 105 | queue=<printername>' and the file will print! |
| 106 | 106 | ||
| 107 | sse.lua -- Server-Sent Events (SSE) client | ||
| 108 | |||
| 109 | This little program uses socket.sse to connect to a text/event-stream | ||
| 110 | URL and print each event received, stopping after a fixed number of | ||
| 111 | them (5 by default). With no arguments it connects to a public live | ||
| 112 | test feed, so you can try it with no setup at all. Just run | ||
| 113 | |||
| 114 | lua sse.lua [<url>] [<event-count>] | ||
| 115 | |||
| 107 | cddb.lua -- CDDB client | 116 | cddb.lua -- CDDB client |
| 108 | 117 | ||
| 109 | This is the first try on a simple CDDB client. Not really | 118 | This is the first try on a simple CDDB client. Not really |
diff --git a/samples/sse.lua b/samples/sse.lua new file mode 100644 index 0000000..16eece9 --- /dev/null +++ b/samples/sse.lua | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | ----------------------------------------------------------------------------- | ||
| 2 | -- Server-Sent Events (SSE) demo client | ||
| 3 | -- LuaSocket sample files | ||
| 4 | -- | ||
| 5 | -- Usage: lua sse.lua [<url>] [<event-count>] | ||
| 6 | -- Both arguments are positional and optional; with none given, connects to | ||
| 7 | -- a public live test feed and stops after 5 events. | ||
| 8 | ----------------------------------------------------------------------------- | ||
| 9 | local http = require("socket.http") | ||
| 10 | local sse = require("socket.sse") | ||
| 11 | |||
| 12 | -- default target: Wikimedia's public, continuously-streaming recent-changes | ||
| 13 | -- feed -- a real, live text/event-stream endpoint, handy for trying out | ||
| 14 | -- socket.sse without standing up a server of your own | ||
| 15 | local DEFAULT_URL = "https://stream.wikimedia.org/v2/stream/recentchange" | ||
| 16 | local DEFAULT_LIMIT = 5 | ||
| 17 | |||
| 18 | -- shortens a long data payload for readable terminal output | ||
| 19 | local function preview(text, limit) | ||
| 20 | limit = limit or 100 | ||
| 21 | if #text > limit then return string.sub(text, 1, limit) .. "..." end | ||
| 22 | return text | ||
| 23 | end | ||
| 24 | |||
| 25 | -- builds a message callback that prints each received Message, then stops | ||
| 26 | -- the stream once "limit" of them have been printed. This module parses a | ||
| 27 | -- single request/response and never reconnects on its own (see | ||
| 28 | -- docs/adr/0001-sse-single-shot-no-auto-reconnect.md), so a caller who wants | ||
| 29 | -- to stop early just does what we do here: return an error from the | ||
| 30 | -- callback, which ends the request the same way any sink error would | ||
| 31 | local function makeprinter(limit) | ||
| 32 | local count = 0 | ||
| 33 | return function(message) | ||
| 34 | count = count + 1 | ||
| 35 | io.write(string.format("[%d] event=%s id=%s\n data=%s\n", | ||
| 36 | count, message.event, tostring(message.id), preview(message.data))) | ||
| 37 | if count >= limit then | ||
| 38 | return nil, string.format("stopped after %d events", limit) | ||
| 39 | end | ||
| 40 | return 1 | ||
| 41 | end | ||
| 42 | end | ||
| 43 | |||
| 44 | -- main program | ||
| 45 | arg = arg or {} | ||
| 46 | local url = arg[1] or DEFAULT_URL | ||
| 47 | local limit = tonumber(arg[2]) or DEFAULT_LIMIT | ||
| 48 | |||
| 49 | io.write("connecting to ", url, " (stopping after ", limit, " events)\n") | ||
| 50 | local ok, code = http.request{ | ||
| 51 | url = url, | ||
| 52 | headers_callback = sse.responseheaders(makeprinter(limit)) | ||
| 53 | } | ||
| 54 | |||
| 55 | if ok then | ||
| 56 | -- the server closed the connection on its own before we hit our limit | ||
| 57 | io.write("connection closed by server, code=", tostring(code), "\n") | ||
| 58 | else | ||
| 59 | -- once the callback above returns an error, http.request reports it the | ||
| 60 | -- same way it reports any failure: (nil, message) -- so "code" here is | ||
| 61 | -- really our own "stopped after N events" message, not a real error | ||
| 62 | io.write(code, "\n") | ||
| 63 | end | ||
