Compare commits
2
Commits
43831d31f6
...
5af879bc2f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5af879bc2f | ||
|
|
8bb2836d7e |
+13
-8
@@ -38,12 +38,15 @@ const busy = ref(false)
|
|||||||
const connected = ref(false)
|
const connected = ref(false)
|
||||||
const socketError = ref('')
|
const socketError = ref('')
|
||||||
const socketFailures = ref(0)
|
const socketFailures = ref(0)
|
||||||
// After a few failed socket attempts (some mobile browsers/DPIs refuse wss://),
|
// Some mobile browsers (notably iOS Safari with an auth-gated page) abort the
|
||||||
// stop advertising "reconnecting" and rely on the 5s REST poll instead.
|
// 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)
|
const usePolling = computed(() => socketFailures.value >= 3)
|
||||||
|
|
||||||
let socket
|
let socket
|
||||||
let pollTimer
|
let pollTimer
|
||||||
|
let statusTimer
|
||||||
|
|
||||||
async function refreshAll() {
|
async function refreshAll() {
|
||||||
const [p, o, e, q] = await Promise.all([
|
const [p, o, e, q] = await Promise.all([
|
||||||
@@ -148,12 +151,15 @@ onMounted(async () => {
|
|||||||
else socketError.value = `socket closed (code ${code})`
|
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(() => {
|
onUnmounted(() => {
|
||||||
socket?.close()
|
socket?.close()
|
||||||
clearInterval(pollTimer)
|
clearInterval(pollTimer)
|
||||||
|
clearInterval(statusTimer)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -168,15 +174,14 @@ onUnmounted(() => {
|
|||||||
>
|
>
|
||||||
{{ status.mode }}
|
{{ status.mode }}
|
||||||
</span>
|
</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
|
<span
|
||||||
class="h-2 w-2 rounded-full"
|
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>
|
></span>
|
||||||
<template v-if="connected">live</template>
|
<template v-if="connected">live</template>
|
||||||
<template v-else-if="usePolling">polling (5s)</template>
|
<template v-else-if="usePolling">live (polling)</template>
|
||||||
<template v-else>reconnecting</template>
|
<template v-else>connecting…</template>
|
||||||
<span v-if="!connected && socketError" class="text-amber-300">· {{ socketError }}</span>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs text-slate-400">
|
<div class="text-xs text-slate-400">
|
||||||
|
|||||||
Reference in new issue
Block a user