SSE
(require SSE) | package: SSE |
1 Example of use
Let us start by defining a function that serves a website with a text area that is filled with messages coming from server sent events on port 8122.
#lang racket (require web-server/http/xexpr web-server/web-server web-server/servlet-dispatch SSE) ;; Page that connects to the server-sent events (define (start-page req) (response/xexpr `(html (head (meta ([http-equiv "content-type"] [content "text/html; charset=utf-8"] )) (meta ([name "viewport"] [content "width=device-width"] )) (title "Events test")) (body (h1 "Welcome to the Events test") (textarea ([readonly ""])) (script " var evtSource = new EventSource(\"//localhost:8122\"); var textArea = document.getElementsByTagName(\"textarea\")[0]; evtSource.onmessage = function(e){ textArea.value = e.data + \"\\n\" + textArea.value ; console.log(e.data); } ")))))
Now we define the server sent events, serve them on port 8122 and run the servlet for the function above on port 8080.
(define a-sse (make-sse)) (sse-serve a-sse #:port 8122) (serve #:dispatch (dispatch/servlet start-page) #:port 8080)
Note that we are not using the function serve/servlet for serving the website. serve does not block the racket REPL. Now open a browser and visit http://localhost:8080. You are going to see a welcome message and an empty textarea. In order to add some text send a data only event as follows:
(sse-send-event a-sse #:data "Hello World!")
At this point the text "Hello World!" appears in the text area.
Now open a new tab or window of your browser and go again to localhost:8080. Note that the message "Hello World!" does not appear in this window. This is because we used #:id with value #f (it is the default value). Let us now send one with #:id equal to #t.
(sse-send-event a-sse #:data "Hello World! (again)" #:id #t)
At this point the two windows that you have open will show the message "Hello World! (again)". This would be the case even with #:id equal to #f. What makes the difference is that if you open now a new tab and connect to localhost:8080, that window will also show this message.
2 HTTP responses
Server Sent Events (SSE) connections start with an http request for connection. The SSE standard allows 4 possible responses. The library has a way to represent each of them as shown in the following table.
HTTP Status Code |
| Library Representation |
200 Accept |
| 'accept |
204 No Content |
| 'no-content |
301 Moved Permanently |
| '(moved-permanently "http://new-location.com") |
307 Temporary Redirect |
| '(temporary-redirect "http://new-location.com") |
For the two hundred codes, the representation is simply a symbol. For the three hundred codes, it is a list with a symbol and string with the url of the redirection. A predicate to check if something is a proper representation of one of the http responses above.
procedure
(sse-http-response? x) → boolean?
x : any/c
3 Provided functions
Racket servlets use functions that take an HTTP request and return an HTTP response. Similarly, the function make-sse takes a parameter called the initial request servlet, which takes a request and returns one of the four http responses allowed for SSE. If the response is 'accept, a connection for the event stream is established.
procedure
initial-request-servlet : (-> request? sse-http-response?) = (lambda (req) 'accept)
Once a sse variable has been created it can be served on a specific port with the sse-serve function and messages can be sent using sse-send-event.
procedure
a-sse : sse? port : listen-port-number?
procedure
(sse-send-event a-sse [ #:data data #:event event #:id id #:retry retry]) → void? a-sse : sse? data : (or/c string? null?) = empty event : (or/c string? null?) = empty id : boolean? = #f retry : (or/c positive-integer? null?) = empty
procedure
(sse-dispatcher x) → dispatcher/c
x : sse?
procedure
(sse-restart-messages a-sse) → void?
a-sse : sse?