Skip to content

Instantly share code, notes, and snippets.

@svetlyak40wt
Created June 26, 2025 22:22
Show Gist options
  • Save svetlyak40wt/963b6fc35a998f80b7d2aa0087d29c84 to your computer and use it in GitHub Desktop.
Save svetlyak40wt/963b6fc35a998f80b7d2aa0087d29c84 to your computer and use it in GitHub Desktop.
Clack server sent events example
(uiop:define-package #:clack-sse-demo
(:use #:cl)
(:import-from #:lack)
(:import-from #:clack)
(:import-from #:log)
(:import-from #:lack/util/writer-stream)
(:nicknames #:clack-sse-demo/app))
(in-package #:clack-sse-demo)
(defparameter *index-page*
"<!DOCTYPE html>
<html>
<head>
<meta charset=\"utf-8\" />
<meta name=\"viewport\" content=\"width=device-width, height=device-height\" />
<title>Server-Sent Events Demo</title>
<style type=\"text/css\">
body {
font-family: 'Open Sans', sans-serif;
}
</style>
</head>
<body>
<h1>Server-Sent Events Demo</h1>
<ul></ul>
<script>
(function() { \"use strict\";
var ul = document.querySelector('ul');
var es = new EventSource('/events');
function li(text) {
var li = document.createElement('li');
li.innerText = text;
ul.appendChild(li);
}
es.addEventListener('open', function() {
li('Server connected :)');
});
es.addEventListener('my-custom-event', function(event) {
li(event.data);
});
es.addEventListener('error', function() {
li('Server unavailable :(');
});
})();
</script>
</body>
</html>
")
(defun server-sent-events (env)
(declare (ignore env))
(flet ((async-handler (responder)
(log:info "Serving events stream")
(let* ((writer (funcall responder
(list 200
(list :content-type "text/event-stream"
:cache-control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"))))
(output-stream (lack/util/writer-stream:make-writer-stream writer))
(counter 0))
(loop repeat 100
do
(sleep 2)
;; Without sse-server module
;;(format output-stream "event:my-custom-event~%data:Hello World! ~d~%~%" (incf counter))
;; With sse-server module
(sse-server:send-event! output-stream
"my-custom-event"
(format nil "Hello World! ~d" (incf counter)))
(finish-output output-stream)))))
(values #'async-handler)))
(defun index-page (env)
(declare (ignore env))
(log:info "Serving index")
(list 200
(list :content-type "text/html")
(list *index-page*)))
(defun start-server (&key (port 8080))
(let ((app (lack:builder
:session
(:static :path "/public/"
:root #P"/static-files/")
(:mount "/events"
'server-sent-events)
'index-page)))
(clack:clackup app
:port port
:use-thread nil)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment