Skip to content

Commit 594d233

Browse files
committed
zstd suppoer in Hunchentoot
1 parent 1b9ff00 commit 594d233

4 files changed

Lines changed: 72 additions & 13 deletions

File tree

clack.lisp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
(let ((headers '(:content-type "text/event-stream; charset=utf-8"
3333
:cache-control "no-cache"
3434
:connection "keep-alive")))
35+
;; FIXME
36+
(setf (compressed-stream generator) nil)
3537
(setf (response generator)
3638
(lack/util/writer-stream:make-writer-stream
3739
(funcall responder `(200 ,headers))))))

datastar-cl.asd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
#:flexi-streams
1515
#:hunchentoot
1616
#:clack
17-
#:lack-util-writer-stream)
17+
#:lack-util-writer-stream
18+
#:zstd
19+
#:gzip-stream
20+
#:salza2)
1821
:components ((:file "package")
1922
(:file "datastar-cl")
2023
(:file "conditions")

datastar-cl.lisp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@
102102
(response :initarg :response
103103
:accessor response
104104
:documentation "The response stream.")
105+
(compressed-stream :initarg :compressed-stream
106+
:accessor compressed-stream
107+
:documentation "The compressed stream (depending on the algorithm)")
105108
(lock :initform (bt:make-lock)
106109
:reader lock
107110
:documentation "Thread safety lock for stream operations."))
@@ -154,14 +157,35 @@
154157
(declare (ignore event-type data-lines event-id retry-duration))
155158
(ensure-connection-open generator))
156159

160+
;; (defmethod send-event ((generator sse-generator) event-type data-lines
161+
;; &key event-id retry-duration)
162+
;; "Send an SSE event with thread safety.
163+
164+
;; Signals: STREAM-ERROR if the response stream is closed or writing fails.
165+
;; This is standard CL behavior - no wrapping is performed."
166+
;; (bt:with-lock-held ((lock generator))
167+
;; (let ((stream (response generator)))
168+
;; (format stream "event: ~a~%" (string-downcase (string event-type)))
169+
;; (when event-id
170+
;; (format stream "id: ~a~%" event-id))
171+
;; (when retry-duration
172+
;; (format stream "retry: ~a~%" retry-duration))
173+
;; (dolist (line data-lines)
174+
;; (format stream "data: ~a~%" line))
175+
;; (format stream "~%")
176+
;; ;; flush immediately
177+
;; (force-output stream))))
178+
179+
157180
(defmethod send-event ((generator sse-generator) event-type data-lines
158181
&key event-id retry-duration)
159182
"Send an SSE event with thread safety.
160183
161184
Signals: STREAM-ERROR if the response stream is closed or writing fails.
162185
This is standard CL behavior - no wrapping is performed."
163186
(bt:with-lock-held ((lock generator))
164-
(let ((stream (response generator)))
187+
(let ((stream (response generator))
188+
(compressed-stream (compressed-stream generator)))
165189
(format stream "event: ~a~%" (string-downcase (string event-type)))
166190
(when event-id
167191
(format stream "id: ~a~%" event-id))
@@ -171,6 +195,8 @@
171195
(format stream "data: ~a~%" line))
172196
(format stream "~%")
173197
;; flush immediately
198+
(when compressed-stream
199+
(finish-output (compressed-stream generator)))
174200
(force-output stream))))
175201

176202
(defmethod patch-elements ((generator sse-generator) (elements string)

hunchentoot.lisp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,46 @@
1111
(:documentation "Hunchentoot-specific SSE generator implementation."))
1212

1313

14-
(defmethod initialize-instance :after ((generator hunchentoot-sse-generator) &key request &allow-other-keys)
15-
"Set up SSE headers and response stream for Hunchentoot."
14+
;; (defmethod initialize-instance :after ((generator hunchentoot-sse-generator) &key request &allow-other-keys)
15+
;; "Set up SSE headers and response stream for Hunchentoot."
16+
;; ;; Set headers using Hunchentoot API
17+
;; (setf (hunchentoot:content-type*) "text/event-stream; charset=utf-8"
18+
;; (hunchentoot:header-out "Cache-Control") "no-cache")
19+
;; ;; HTTP/1.1 specific headers
20+
;; (when (string= (hunchentoot:server-protocol request) "HTTP/1.1")
21+
;; (setf (hunchentoot:header-out "Connection") "keep-alive"))
22+
;; ;; Initialize response stream
23+
;; (let ((raw-stream (hunchentoot:send-headers)))
24+
;; (setf (response generator)
25+
;; (flex:make-flexi-stream raw-stream :external-format :utf-8))))
26+
27+
28+
(defmethod initialize-instance :after ((generator hunchentoot-sse-generator) &key request &allow-other-keys)
29+
"Set up SSE headers and response stream for Hunchentoot. Use compression if available"
1630
;; Set headers using Hunchentoot API
17-
(setf (hunchentoot:content-type*) "text/event-stream; charset=utf-8"
18-
(hunchentoot:header-out "Cache-Control") "no-cache")
19-
;; HTTP/1.1 specific headers
20-
(when (string= (hunchentoot:server-protocol request) "HTTP/1.1")
21-
(setf (hunchentoot:header-out "Connection") "keep-alive"))
22-
;; Initialize response stream
23-
(let ((raw-stream (hunchentoot:send-headers)))
24-
(setf (response generator)
25-
(flex:make-flexi-stream raw-stream :external-format :utf-8))))
31+
(let ((accepts-zstd (search "zstd" (hunchentoot:header-in* :accept-encoding request)
32+
:test #'string-equal)))
33+
(setf (hunchentoot:content-type*) "text/event-stream; charset=utf-8"
34+
(hunchentoot:header-out "Cache-Control") "no-cache")
35+
;; HTTP/1.1 specific headers
36+
37+
(when (string= (hunchentoot:server-protocol request) "HTTP/1.1")
38+
(setf (hunchentoot:header-out "Connection") "keep-alive"))
39+
(when accepts-zstd
40+
(setf (hunchentoot:header-out "Content-Encoding") "zstd"
41+
(hunchentoot:header-out "Vary") "Accept-Encoding"))
42+
(let* ((raw-stream (hunchentoot:send-headers))
43+
(compressed-stream (when accepts-zstd
44+
(zstd:make-compressing-stream raw-stream :level 3)))
45+
(utf8-stream (if compressed-stream
46+
(flex:make-flexi-stream compressed-stream :external-format :utf-8)
47+
(flex:make-flexi-stream raw-stream :external-format :utf-8)
48+
)))
49+
50+
(setf (response generator) utf8-stream)
51+
(setf (compressed-stream generator) compressed-stream))))
52+
53+
2654

2755
(defmethod read-signals ((request hunchentoot:request)
2856
&key (catch-errors *catch-errors-p*))

0 commit comments

Comments
 (0)