I am currently implementing server sent events (SSE) in an web application using Clojure, Pedestal and Jetty.
When I print the message in the backend the channel is open and when I invoke io.pedestal.http.sse/send-event
it returns true, however in the frontend I get no console.log() prints in Javascript in the browser console. as if there is no data received. I tested the SSE connection in Postman and it is successful but the response is (empty)
.
Backend:
(def SSE-REGISTRY (atom {}))
(defn get-user-channel [token]
(get @SSE-REGISTRY token))
(defn test-print [channel]
(println "channel:" channel) ;; channel:#object[clojure.core.async.impl.chan...]
(println "channel opened:" (not (chan/closed? channel))) ;; channel opened: true
(println "sent-event:"
(sse/send-event channel "status"
(json/write-str {:id 1
:workflowId 3
:status :GOOD}) ;; sent-event: true
(defn send-sse-msg [name data id]
(when-let [sse-channels (vals @SSE-REGISTRY)]
(doseq [channel sse-channels]
(when-not (chan/closed? channel)
(test-print channel)
(sse/send-event channel name data id)))))
(def sse-route ["/rest/sse" :get
(sse/start-event-stream send-sse-msg 10 100)
:route-name :sse])
(defn create-sse-channel []
(async/chan (async/sliding-buffer 100)))
Frontend:
const protocol = window.location.protocol;
const host = window.location.port;
const sseUrl = protocol + '//'+ host + '/rest/sse';
const RUN_BUTTON_STATUS_TIME = 2000;
const sseInitOptionsMap = {
headers: {
'Content-Type': 'text/event-stream; charset=utf-8',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache'
},
withCredentials: true,
https: {rejectUnauthorized: true}
};
export const eventSource = new EventSource(sseUrl, sseInitOptionsMap);
eventSource.addEventListener('integrationStatus', sendStatusHandler);
eventSource.addEventListener('stopAction', sendStopActionHandler);
eventSource.onopen = (e) => {
console.log("SSE connection opened:" + e);
};
eventSource.onerror = (e) => {
console.log("error:" + e);
if (e.readyState == EventSource.CLOSED) {
console.log("connection closed:" + e);
} else {
eventSource.close();
console.log("SSE connection closed:" + e);
}
};
export function sendStatusHandler(event) {
const data = JSON.parse(event.data);
console.log("data:" + data);
let id = data.id;
let workflowId = data.workflowId;
let status = data.status;
cljsDisp("set-global-operation-status", id, workflowId, status);
configurtorActionRunButtonStatus(id, workflowId, status);
setTimeout(cljsDisp("get-last-run-action-data", id, workflowId, status),
300);
}
function configurtorActionRunButtonStatus (id, workflowId, status) {
if (status === "GOOD") {
showStatus(id, workflowId, true);
} else if (status === "BAD") {
showStatus(id, workflowId, true);
cljsDisp("configurator-error-message-show", id, workflowId, true);
} else {
cljsDisp("configurator-action-run-button-status-visible?", id, workflowId, false);
}
}
export function sendStopWorkflowHandler(event) {
const data = JSON.parse(event.data);
console.log("data:" + data); // prints nothing
let workflowId = data.workflowId;
cljsDisp("stop-action-by-sse-msg", workflowId);
}
function showStatus(integrationId, operationId, showStatus) {
setTimeout(cljsDisp("configurator-action-run-button-status-visible?",
integrationId, operationId, showStatus),
RUN_BUTTON_STATUS_TIME);
}
export function closeSse() {
if (eventSource.readyState != eventSource.CLOSED) {
eventSource.close();
}
}
It seems I am missing something. Can you help. The problem is that there are not much examples of Clojure with Pedestal implementation of SSE. Most are in JavaScript and other languages.