mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-31 20:58:04 +00:00
feat(notifications): replace polling with WebSocket push
Eliminates the 5-second setInterval polling loop for notifications in EditorLayout. A persistent /ws/notifications WebSocket connection is opened on mount; the backend pushes each alert the instant dispatchAlert fires, with 5s auto-reconnect on close. Key changes: - NotificationService: injectable broadcaster callback (setBroadcaster) - DatabaseService.addNotificationHistory: returns full NotificationHistory record (with id/is_read) instead of void - index.ts: notificationSubscribers Set + /ws/notifications upgrade handler (JWT-verified, placed before remote proxy path) - EditorLayout: polling removed, WS connect/reconnect replaces it
This commit is contained in:
@@ -418,6 +418,17 @@ const wss = new WebSocket.Server({ noServer: true });
|
||||
|
||||
let terminalWs: WebSocket | null = null;
|
||||
|
||||
// Notification push — set of authenticated browser clients subscribed to real-time alerts
|
||||
const notificationSubscribers = new Set<WebSocket>();
|
||||
NotificationService.getInstance().setBroadcaster((notification) => {
|
||||
const msg = JSON.stringify({ type: 'notification', payload: notification });
|
||||
for (const ws of notificationSubscribers) {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle WebSocket upgrade with JWT authentication
|
||||
server.on('upgrade', async (req, socket, head) => {
|
||||
// Parse cookies from the upgrade request
|
||||
@@ -450,6 +461,18 @@ server.on('upgrade', async (req, socket, head) => {
|
||||
const parsedUrl = new URL(url, `http://${req.headers.host || 'localhost'}`);
|
||||
const pathname = parsedUrl.pathname;
|
||||
|
||||
// Notification push channel — always local, never proxied to remote nodes
|
||||
if (pathname === '/ws/notifications') {
|
||||
const notifWss = new WebSocket.Server({ noServer: true });
|
||||
notifWss.handleUpgrade(req, socket, head, (ws) => {
|
||||
notifWss.close();
|
||||
notificationSubscribers.add(ws);
|
||||
ws.on('close', () => notificationSubscribers.delete(ws));
|
||||
ws.on('error', () => { notificationSubscribers.delete(ws); ws.terminate(); });
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Resolve node context from query param
|
||||
const nodeIdParam = parsedUrl.searchParams.get('nodeId');
|
||||
const nodeId = nodeIdParam ? parseInt(nodeIdParam, 10) : NodeRegistry.getInstance().getDefaultNodeId();
|
||||
|
||||
Reference in New Issue
Block a user