Fix WebSocket reconnect: refused upgrades are 1006 not 1008, back off, prompt once
This commit is contained in:
parent
1f1544bab1
commit
821f0a0a8f
1 changed files with 21 additions and 5 deletions
|
|
@ -5,9 +5,17 @@ const { createApp, ref, computed, watch, onMounted, onUnmounted } = Vue;
|
||||||
const TOKEN_KEY = 'chart-token';
|
const TOKEN_KEY = 'chart-token';
|
||||||
let authToken = localStorage.getItem(TOKEN_KEY) || '';
|
let authToken = localStorage.getItem(TOKEN_KEY) || '';
|
||||||
|
|
||||||
|
// Reconnects and the status poll both hit 401s, so without this a visitor
|
||||||
|
// who cancels gets asked again every couple of seconds.
|
||||||
|
let promptDeclined = false;
|
||||||
|
|
||||||
function promptForToken() {
|
function promptForToken() {
|
||||||
|
if (promptDeclined) return false;
|
||||||
const entered = window.prompt('Access token for this chart', '');
|
const entered = window.prompt('Access token for this chart', '');
|
||||||
if (entered === null) return false;
|
if (entered === null) {
|
||||||
|
promptDeclined = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
authToken = entered.trim();
|
authToken = entered.trim();
|
||||||
localStorage.setItem(TOKEN_KEY, authToken);
|
localStorage.setItem(TOKEN_KEY, authToken);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -55,6 +63,7 @@ createApp({
|
||||||
const now = ref(Date.now());
|
const now = ref(Date.now());
|
||||||
let chartApi = null;
|
let chartApi = null;
|
||||||
let socket = null;
|
let socket = null;
|
||||||
|
let retryDelay = 2000;
|
||||||
let timer = null;
|
let timer = null;
|
||||||
|
|
||||||
const barAge = computed(() => {
|
const barAge = computed(() => {
|
||||||
|
|
@ -76,6 +85,7 @@ createApp({
|
||||||
const query = authToken ? `?token=${encodeURIComponent(authToken)}` : '';
|
const query = authToken ? `?token=${encodeURIComponent(authToken)}` : '';
|
||||||
socket = new WebSocket(`${protocol}://${location.host}/ws${query}`);
|
socket = new WebSocket(`${protocol}://${location.host}/ws${query}`);
|
||||||
socket.onopen = () => {
|
socket.onopen = () => {
|
||||||
|
retryDelay = 2000;
|
||||||
socket.send(JSON.stringify({ type: 'subscribe', tf: timeframe.value }));
|
socket.send(JSON.stringify({ type: 'subscribe', tf: timeframe.value }));
|
||||||
sendPrefs();
|
sendPrefs();
|
||||||
};
|
};
|
||||||
|
|
@ -102,11 +112,17 @@ createApp({
|
||||||
playAlert();
|
playAlert();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
socket.onclose = event => {
|
socket.onclose = async () => {
|
||||||
status.value.stream = 'disconnected';
|
status.value.stream = 'disconnected';
|
||||||
// 1008 is the server rejecting our token; ask once, then reconnect.
|
// A refused upgrade reaches the browser as 1006, not 1008: the server
|
||||||
if (event.code === 1008 && !promptForToken()) return;
|
// rejects the handshake with HTTP 403 before any close frame exists.
|
||||||
setTimeout(connect, 2000);
|
// So the close code cannot distinguish "bad token" from "server
|
||||||
|
// restarting". Re-check over HTTP instead — apiFetch prompts for a
|
||||||
|
// token when that is what is actually wrong — and back off so a
|
||||||
|
// visitor without one is not reconnecting twice a second forever.
|
||||||
|
await refreshStatus();
|
||||||
|
retryDelay = Math.min(retryDelay * 2, 30000);
|
||||||
|
setTimeout(connect, retryDelay);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue