nidus-sync/static/js/events.js
Eli Ribble 31947c848a
Move static outside HTML. Start work on TypeScript bundle
It's not strictly HTML, so that's just correct.

This is just worth doing while building the new TypeScript bundle
2026-03-21 03:06:59 +00:00

127 lines
2.8 KiB
JavaScript

// sse-manager.js - Include this in your common template
window.SSEManager = (function () {
let eventSource = null;
let subscribers = new Map();
let isConnected = false;
let connectionPromise = null;
function subscribe(eventType, handler) {
if (!subscribers.has(eventType)) {
subscribers.set(eventType, []);
}
subscribers.get(eventType).push(handler);
// If already connected, attach the listener immediately
if (isConnected && eventSource) {
eventSource.addEventListener(eventType, handler);
}
}
function unsubscribe(eventType, handler) {
if (subscribers.has(eventType)) {
const handlers = subscribers.get(eventType);
const index = handlers.indexOf(handler);
if (index > -1) {
handlers.splice(index, 1);
}
}
if (eventSource) {
eventSource.removeEventListener(eventType, handler);
}
}
function connect(url) {
if (connectionPromise) {
return connectionPromise;
}
connectionPromise = new Promise((resolve, reject) => {
eventSource = new EventSource(url);
eventSource.onopen = function () {
isConnected = true;
// Attach all pre-registered handlers
subscribers.forEach((handlers, eventType) => {
handlers.forEach((handler) => {
eventSource.addEventListener("message", (message) => {
const data = JSON.parse(message.data);
if (eventType == "*" || eventType == data.type) {
handler(data);
}
});
});
});
console.log("SSE connected");
resolve(eventSource);
};
eventSource.onerror = function (err) {
console.error("SSE error:", err);
isConnected = false;
// Close old connection
if (eventSource) {
eventSource.close();
}
// Reconnect after delay
setTimeout(() => {
connectionPromise = null;
connect(url);
}, 5000);
if (!isConnected) {
reject(err);
}
};
});
return connectionPromise;
}
function disconnect() {
if (eventSource) {
eventSource.close();
eventSource = null;
isConnected = false;
connectionPromise = null;
}
}
function ready(callback) {
if (connectionPromise) {
connectionPromise.then(callback);
} else {
// If connect hasn't been called yet, queue it
const checkInterval = setInterval(() => {
if (connectionPromise) {
clearInterval(checkInterval);
connectionPromise.then(callback);
}
}, 50);
}
}
return {
connect,
disconnect,
subscribe,
unsubscribe,
ready,
};
})();
// Initialize SSE for navigation notifications
document.addEventListener("DOMContentLoaded", function () {
SSEManager.connect("/api/events");
});
function updateNotificationBadge(data) {
const badge = document.querySelector(".notification-badge");
if (badge) {
badge.textContent = data.count;
badge.style.display = data.count > 0 ? "block" : "none";
}
}