// Firefox does randomized exponential backoff for failed websocket requests // This means we can't have [1. long downtime] and [2. fast reconnect] at the sime time // // We abuse the fact that HTTP requests are NOT backoffed, and use those to monitor // the server. When we see that the server is up - we attempt an actual websocket connection // // Details best described here: https://github.com/kee-org/KeeFox/issues/189 async function ws_connect(state, context, first_connect = false) { const session_id = localStorage.getItem('sessionId') || '0'; const desk_id = state.desk_id; try { const resp = await fetch(config.ping_url); if (resp.ok) { const text = await resp.text(); if (text === 'pong') { ws = new WebSocket(`${config.ws_url}?deskId=${desk_id}&sessionId=${session_id}`); ws.addEventListener('open', () => on_open(state)); ws.addEventListener('message', (e) => on_message(state, context, e)); ws.addEventListener('error', () => on_error(state, context)); ws.addEventListener('close', () => on_close(state, context)); return; } } } catch (e) { console.log('Could not ping the server:', e); } state.timers.offline_toast = setTimeout(() => ws_connect(state, context, first_connect), config.ws_reconnect_timeout); } function on_open(state) { clearTimeout(state.timers.offline_toast); ui_online(); if (config.debug_print) console.debug('open') } async function on_message(state, context, event) { const data = event.data; let message_data = null; if ('arrayBuffer' in data) { message_data = await data.arrayBuffer(); const view = new DataView(message_data); const d = deserializer_create(message_data, view); await handle_message(state, context, d); } else { /* For all my Safari < 14 bros out there */ const reader = new FileReader(); reader.onload = async (e) => { message_data = e.target.result; const view = new DataView(message_data); const d = deserializer_create(message_data, view); await handle_message(state, context, d); }; reader.readAsArrayBuffer(data); } } function on_close(state, context) { state.timers.offline_toast = setTimeout(() => ui_offline(), config.initial_offline_timeout); ws = null; if (config.debug_print) console.debug('close'); ws_connect(state, context, false); } function on_error(state, context) { ws.close(state, context); }