Commite83a7801Recorded4 Jul 2026Repositorysigil-http

http-response/sse-broadcast: default handler to identity

Message

Make the transform handler an optional leading positional defaulting to identity, so a hub that already carries pre-formatted SSE strings (the common case) needs no handler: (http-response/sse-broadcast hub on-connect: ...). Kept it positional (not a keyword) so existing positional-handler callers (vigil, sigil-web dev, sigil-web-demo) keep working unchanged.

Changed
 src/sigil/http/response.sgl | 43 +++++++++++++++++++++++++++++++------------
 1 file changed, 31 insertions(+), 12 deletions(-)
Diff
src/sigil/http/response.sglmodified
@@ -531,29 +531,48 @@
531
;; close function
532
close))))
533
+534
;; Look up a keyword's value in a flat keyword/value plist, else default.
+535
(define (sse-broadcast-kw-ref plist key default)
+536
(let loop ((p plist))
+537
(cond
+538
((or (null? p) (null? (cdr p))) default)
+539
((eq? (car p) key) (car (cdr p)))
+540
(else (loop (cdr (cdr p)))))))
+541
542
;;; Create an SSE response that broadcasts from a channel.
543
;;;
544
;;; Subscribes to a broadcast channel and sends events for each message.
537
;;; The handler transforms messages into SSE event strings.
+545
;;; The handler transforms messages into SSE event strings; it is
+546
;;; optional and defaults to the identity function, so a hub that already
+547
;;; carries pre-formatted SSE strings (the common case) needs no handler.
548
;;;
549
;;; Parameters:
550
;;; broadcast: The broadcast channel to subscribe to
541
;;; handler: (lambda (msg) ...) -> string or #f
542
;;; Returns SSE event string to send, or #f to skip
+551
;;; handler: Optional (lambda (msg) ...) -> string or #f.
+552
;;; Returns SSE event string to send, or #f to skip.
+553
;;; Defaults to identity (send each message as-is).
554
;;; buffer-size: Subscriber buffer size (default: 32)
544
;;; on-connect: Optional (lambda () ...) called on connect
545
;;; Returns initial event string or #f
+555
;;; on-connect: Optional (lambda () ...) called on connect.
+556
;;; Returns initial event string or #f.
557
;;;
558
;;; Example:
559
;;; ```scheme
+560
;;; ;; Hub carries pre-formatted event strings — no handler needed:
+561
;;; (http-response/sse-broadcast hub on-connect: (lambda () (snapshot)))
+562
;;;
+563
;;; ;; Transform raw messages into SSE strings:
564
;;; (http-response/sse-broadcast chat-broadcast
550
;;; (lambda (msg)
551
;;; (sse-event "message" (json-encode msg))))
+565
;;; (lambda (msg) (sse-event "message" (json-encode msg))))
566
;;; ```
553
(define (http-response/sse-broadcast broadcast handler
554
(keys: (buffer-size 32)
555
(on-connect #f)))
556
(: any? procedure? (buffer-size: integer?) (on-connect: (maybe procedure?)) -> http-response?)
+567
(define (http-response/sse-broadcast broadcast . opts)
+568
;; `handler` is an optional leading positional (a procedure); anything
+569
;; after it (or all of `opts`, if the first isn't a procedure) is treated
+570
;; as buffer-size:/on-connect: keyword arguments.
+571
(let* ((has-handler (and (pair? opts) (procedure? (car opts))))
+572
(handler (if has-handler (car opts) (lambda (msg) msg)))
+573
(kwargs (if has-handler (cdr opts) opts))
+574
(buffer-size (sse-broadcast-kw-ref kwargs buffer-size: 32))
+575
(on-connect (sse-broadcast-kw-ref kwargs on-connect: #f)))
576
(http-response
577
status: HTTP-OK
578
headers: (dict
@@ -591,7 +610,7 @@
610
;; Write failed, clean up
611
(broadcast-unsubscribe broadcast sub)
612
;; Handler returned #f, skip and continue
594
(loop))))))))))))
+613
(loop)))))))))))))
614
615
;;; Format a Server-Sent Event with event type and data.
616
;;;