You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

75 lines
2.6 KiB

// 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);
}