Present REST polling as a normal live state
Some browsers (notably iOS Safari on an auth-gated page) abort the wss:// upgrade even though the server accepts it. Rather than showing a perpetual "reconnecting", stop retrying after three failures, poll every 3s, and label the badge "live (polling)" in green. The socket error is kept as a tooltip.
This commit is contained in:
1 parent
43831d31f6
commit
8bb2836d7e
1 file changed
+13
-8
+13
-8
@@ -38,12 +38,15 @@ const busy = ref(false)
|
||||
const connected = ref(false)
|
||||
const socketError = ref('')
|
||||
const socketFailures = ref(0)
|
||||
// After a few failed socket attempts (some mobile browsers/DPIs refuse wss://),
|
||||
// stop advertising "reconnecting" and rely on the 5s REST poll instead.
|
||||
// Some mobile browsers (notably iOS Safari with an auth-gated page) abort the
|
||||
// wss:// upgrade even when the server accepts it. After a few failures we stop
|
||||
// retrying, rely on the REST poll, and present it as a normal live state rather
|
||||
// than a degraded "reconnecting".
|
||||
const usePolling = computed(() => socketFailures.value >= 3)
|
||||
|
||||
let socket
|
||||
let pollTimer
|
||||
let statusTimer
|
||||
|
||||
async function refreshAll() {
|
||||
const [p, o, e, q] = await Promise.all([
|
||||
@@ -148,12 +151,15 @@ onMounted(async () => {
|
||||
else socketError.value = `socket closed (code ${code})`
|
||||
},
|
||||
})
|
||||
pollTimer = setInterval(refreshAll, 5000)
|
||||
// Poll fast enough that the UI feels live even when it is the only channel.
|
||||
pollTimer = setInterval(refreshAll, 3000)
|
||||
statusTimer = setInterval(() => api.getStatus().then((s) => (status.value = s)), 3000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
socket?.close()
|
||||
clearInterval(pollTimer)
|
||||
clearInterval(statusTimer)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -168,15 +174,14 @@ onUnmounted(() => {
|
||||
>
|
||||
{{ status.mode }}
|
||||
</span>
|
||||
<span class="flex items-center gap-1.5 text-xs text-slate-400">
|
||||
<span class="flex items-center gap-1.5 text-xs text-slate-400" :title="socketError || ''">
|
||||
<span
|
||||
class="h-2 w-2 rounded-full"
|
||||
:class="connected ? 'bg-emerald-400' : usePolling ? 'bg-sky-400' : 'bg-slate-500'"
|
||||
:class="connected || usePolling ? 'bg-emerald-400' : 'bg-slate-500'"
|
||||
></span>
|
||||
<template v-if="connected">live</template>
|
||||
<template v-else-if="usePolling">polling (5s)</template>
|
||||
<template v-else>reconnecting</template>
|
||||
<span v-if="!connected && socketError" class="text-amber-300">· {{ socketError }}</span>
|
||||
<template v-else-if="usePolling">live (polling)</template>
|
||||
<template v-else>connecting…</template>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-xs text-slate-400">
|
||||
|
||||
Reference in new issue
Block a user