fix(ui): снимать статус live при отсутствии обновлений

This commit is contained in:
Denozordec committed 2026-09-28 11:35:29 +07:00
1 parent 5734340db2
commit f50a29f116
8 files changed
+103 -5

No files matched your search

+13 -1
View File
@@ -37,7 +37,10 @@ export function useFlowLive(opts: {
useEffect(() => {
if (!opts.enabled) return
const ac = new AbortController()
let sampleTimer: ReturnType<typeof setTimeout> | undefined
const stopTimer = () => clearTimeout(sampleTimer)
const setError = (error: string) => {
stopTimer()
if (!ac.signal.aborted) setResult(previous => ({ key, sample: previous?.key === key ? previous.sample : null, receivedAt: previous?.key === key ? previous.receivedAt : null, error }))
}
const path = `/api/traffic/flow/live${flowQuery({
@@ -50,6 +53,12 @@ export function useFlowLive(opts: {
excludeOverlay: opts.excludeOverlay,
})}`
const url = resolveApiUrl(opts.backendUrl, path)
// Backend ticks every 1.5–2s; tolerate several missed samples. Heartbeats do not reset this timer.
const awaitSample = () => {
stopTimer()
sampleTimer = setTimeout(() => setError("Нет обновлений live более 15 секунд"), 15_000)
}
awaitSample()
let buf = ""
@@ -82,6 +91,7 @@ export function useFlowLive(opts: {
if (!isValidFlowLiveSample(parsed)) {
throw new Error("Некорректные данные live-потока")
}
awaitSample()
setResult({ key, sample: parsed, receivedAt: Date.now(), error: parsed.degraded ? "Коллектор перегружен: упрощённая аналитика" : null })
} else if (ev.event === "error" && ev.data) {
const parsed: unknown = JSON.parse(ev.data)
@@ -93,10 +103,12 @@ export function useFlowLive(opts: {
if (ac.signal.aborted) return
setError(e instanceof Error ? e.message : "Ошибка live-потока")
ac.abort()
} finally {
stopTimer()
}
})()
return () => ac.abort()
return () => { stopTimer(); ac.abort() }
}, [opts.enabled, opts.backendUrl, opts.range, opts.serverId, opts.userId, opts.iface, opts.dedup, opts.excludeMesh, opts.excludeOverlay, key])
return result?.key === key ? { sample: result.sample, error: result.error, receivedAt: result.receivedAt } : { sample: null, error: null, receivedAt: null }