From cd6b41a13af403d32e08ff416e60982b5cb718dc Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Mon, 31 Aug 2026 22:27:42 +0200 Subject: Add SSE sink (socket.sse module) 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 --- samples/sse.lua | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 samples/sse.lua (limited to 'samples/sse.lua') 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 @@ +----------------------------------------------------------------------------- +-- Server-Sent Events (SSE) demo client +-- LuaSocket sample files +-- +-- Usage: lua sse.lua [] [] +-- Both arguments are positional and optional; with none given, connects to +-- a public live test feed and stops after 5 events. +----------------------------------------------------------------------------- +local http = require("socket.http") +local sse = require("socket.sse") + +-- default target: Wikimedia's public, continuously-streaming recent-changes +-- feed -- a real, live text/event-stream endpoint, handy for trying out +-- socket.sse without standing up a server of your own +local DEFAULT_URL = "https://stream.wikimedia.org/v2/stream/recentchange" +local DEFAULT_LIMIT = 5 + +-- shortens a long data payload for readable terminal output +local function preview(text, limit) + limit = limit or 100 + if #text > limit then return string.sub(text, 1, limit) .. "..." end + return text +end + +-- builds a message callback that prints each received Message, then stops +-- the stream once "limit" of them have been printed. This module parses a +-- single request/response and never reconnects on its own (see +-- docs/adr/0001-sse-single-shot-no-auto-reconnect.md), so a caller who wants +-- to stop early just does what we do here: return an error from the +-- callback, which ends the request the same way any sink error would +local function makeprinter(limit) + local count = 0 + return function(message) + count = count + 1 + io.write(string.format("[%d] event=%s id=%s\n data=%s\n", + count, message.event, tostring(message.id), preview(message.data))) + if count >= limit then + return nil, string.format("stopped after %d events", limit) + end + return 1 + end +end + +-- main program +arg = arg or {} +local url = arg[1] or DEFAULT_URL +local limit = tonumber(arg[2]) or DEFAULT_LIMIT + +io.write("connecting to ", url, " (stopping after ", limit, " events)\n") +local ok, code = http.request{ + url = url, + headers_callback = sse.responseheaders(makeprinter(limit)) +} + +if ok then + -- the server closed the connection on its own before we hit our limit + io.write("connection closed by server, code=", tostring(code), "\n") +else + -- once the callback above returns an error, http.request reports it the + -- same way it reports any failure: (nil, message) -- so "code" here is + -- really our own "stopped after N events" message, not a real error + io.write(code, "\n") +end -- cgit v1.2.3-55-g6feb