Present REST polling as a normal live state
CI/CD / backend (push) Successful in 5m23s
CI/CD / frontend (push) Successful in 4m55s
CI/CD / build (push) Successful in 13s
CI/CD / cleanup (push) Successful in 5s
CI/CD / deploy (push) Successful in 24s

This commit is contained in:
matitos committed 2026-09-20 14:01:38 +00:00
commit 5af879bc2f
1 file changed
+13 -8
+13 -8
View File
@@ -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">