This commit is contained in:
Mateusz Gruszczyński
2026-09-17 12:55:29 +02:00
parent 4bdcf1b8dd
commit cd8d3fab95
42 changed files with 286 additions and 842 deletions
+44 -3
View File
@@ -131,17 +131,58 @@ async function handleWebSocketMessage(event) {
} catch (_) { }
}
const WEBSOCKET_RECONNECT_DELAY_MS = 3000;
const WEBSOCKET_ERROR_DELAY_MS = 15000;
function clearWebSocketOutage() {
app.wsOutageStartedAt = 0;
clearTimeout(app.wsErrorTimer);
app.wsErrorTimer = null;
}
function markWebSocketOutage() {
if (!app.wsOutageStartedAt) app.wsOutageStartedAt = Date.now();
const elapsed = Date.now() - app.wsOutageStartedAt;
if (elapsed >= WEBSOCKET_ERROR_DELAY_MS) {
updateConnectionIndicator('connectionError');
return;
}
updateConnectionIndicator('reconnecting');
if (app.wsErrorTimer) return;
app.wsErrorTimer = setTimeout(() => {
app.wsErrorTimer = null;
if (app.ws?.readyState === WebSocket.OPEN || !app.wsOutageStartedAt) return;
updateConnectionIndicator('connectionError');
}, WEBSOCKET_ERROR_DELAY_MS - elapsed);
}
function connectWebSocket() {
if (app.ws && [WebSocket.OPEN, WebSocket.CONNECTING].includes(app.ws.readyState)) return;
clearTimeout(app.wsTimer);
app.wsTimer = null;
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const query = app.token ? `?token=${encodeURIComponent(app.token)}` : '';
const ws = new WebSocket(`${protocol}//${location.host}${withBase('/ws')}${query}`); app.ws = ws;
ws.onopen = () => updateConnectionIndicator('connected');
ws.onclose = () => { app.controlPlanPushReady = false; updateConnectionIndicator('disconnected'); scheduleControlPlanLoad(0); app.wsTimer = setTimeout(connectWebSocket, 3000); };
ws.onerror = () => updateConnectionIndicator('connectionError');
ws.onopen = () => {
if (app.ws !== ws) return;
clearWebSocketOutage();
updateConnectionIndicator('connected');
};
ws.onclose = () => {
if (app.ws !== ws) return;
app.controlPlanPushReady = false;
markWebSocketOutage();
scheduleControlPlanLoad(0);
app.wsTimer = setTimeout(connectWebSocket, WEBSOCKET_RECONNECT_DELAY_MS);
};
// Browser WebSocket errors are transport-level signals and are normally followed by `close`.
// Let `close` drive reconnect state so a transient error does not look like an application failure.
ws.onerror = () => {
if (app.ws === ws) console.warn('WebSocket transport error; waiting for close/reconnect');
};
let messageQueue = Promise.resolve();
ws.onmessage = event => {
if (app.ws !== ws) return;
messageQueue = messageQueue.then(() => handleWebSocketMessage(event)).catch(() => { });
};
}