aboutsummaryrefslogtreecommitdiff
path: root/samples/sse.lua
diff options
context:
space:
mode:
authorThijs Schreijer <thijs@thijsschreijer.nl>2026-08-31 22:27:42 +0200
committerThijs Schreijer <thijs@thijsschreijer.nl>2026-09-01 07:59:54 +0200
commitcd6b41a13af403d32e08ff416e60982b5cb718dc (patch)
tree3865d91753fd636a866d4711f50ab27613e58634 /samples/sse.lua
parentc5f169ec303a70707bc48fbece9b52cc90a48de0 (diff)
downloadluasocket-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 '')
-rw-r--r--samples/sse.lua63
1 files changed, 63 insertions, 0 deletions
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-----------------------------------------------------------------------------
9local http = require("socket.http")
10local 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
15local DEFAULT_URL = "https://stream.wikimedia.org/v2/stream/recentchange"
16local DEFAULT_LIMIT = 5
17
18-- shortens a long data payload for readable terminal output
19local function preview(text, limit)
20 limit = limit or 100
21 if #text > limit then return string.sub(text, 1, limit) .. "..." end
22 return text
23end
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
31local 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
42end
43
44-- main program
45arg = arg or {}
46local url = arg[1] or DEFAULT_URL
47local limit = tonumber(arg[2]) or DEFAULT_LIMIT
48
49io.write("connecting to ", url, " (stopping after ", limit, " events)\n")
50local ok, code = http.request{
51 url = url,
52 headers_callback = sse.responseheaders(makeprinter(limit))
53}
54
55if 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")
58else
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")
63end