fix(uptime): показывать реальные наблюдения и пропуски RTT на дашборде

This commit is contained in:
Denozordec committed 2026-10-03 23:42:45 +07:00
1 parent 8f65d1620d
commit 9d3129372b
18 files changed
+169 -203

No files matched your search

+14 -33
View File
@@ -3,44 +3,26 @@ import type { PingProbe, Server } from "@/lib/data"
/** Длина ряда на графике дашборда (ось времени). */
export const DASH_LATENCY_POINTS = 60
/** Растягивает/сэмплирует ряд до `targetLen` (линейная интерполяция по индексам). */
export function padSeriesToLength(values: number[], targetLen: number): number[] {
if (targetLen <= 0) return []
if (values.length === 0) return Array(targetLen).fill(0)
if (values.length === targetLen) return [...values]
if (values.length > targetLen) return values.slice(values.length - targetLen)
if (values.length === 1) return Array(targetLen).fill(values[0] ?? 0)
const out: number[] = []
for (let i = 0; i < targetLen; i++) {
const t = (i / (targetLen - 1)) * (values.length - 1)
const j = Math.floor(t)
const f = t - j
const a = values[j] ?? 0
const b = values[Math.min(j + 1, values.length - 1)] ?? a
out.push(Math.round(a + f * (b - a)))
}
return out
}
export interface DashboardLatencyChartInput {
series: Record<string, number[]>
series: Record<string, (number|null)[]>
labels: Record<string, string>
}
/**
* Средний RTT по всем включённым пробам с одного источника (srcServerId).
* Средний RTT по измеренным общим корзинам включённых проб одного источника.
* Не интерполируем и не подменяем отсутствующие измерения нулями.
* Ключ серии — стабильный id вида `src-<numericId>`; подпись — площадка или имя сервера.
* Ограничение числа линий — чтобы график оставался читаемым.
*/
export function buildLatencySeriesByProbeSource(
probes: PingProbe[],
probes: Array<Pick<PingProbe,"enabled"|"srcServerId">&{series:(number|null)[]}>,
servers: Server[],
opts?: { maxServers?: number; points?: number },
): DashboardLatencyChartInput {
const maxServers = opts?.maxServers ?? 8
const points = opts?.points ?? DASH_LATENCY_POINTS
const bySrv = new Map<string, PingProbe[]>()
const bySrv = new Map<string, Array<Pick<PingProbe,"enabled"|"srcServerId">&{series:(number|null)[]}>>()
for (const p of probes) {
if (!p.enabled || !p.series?.length) continue
const sid = p.srcServerId
@@ -54,7 +36,7 @@ export function buildLatencySeriesByProbeSource(
return na.localeCompare(nb, "ru")
}).slice(0, maxServers)
const series: Record<string, number[]> = {}
const series: Record<string, (number|null)[]> = {}
const labels: Record<string, string> = {}
for (const sid of sortedIds) {
@@ -62,16 +44,15 @@ export function buildLatencySeriesByProbeSource(
const innerLen = plist.reduce((m, p) => Math.max(m, p.series.length), 0)
if (innerLen === 0) continue
const averaged = Array.from({ length: innerLen }, (_, i) => {
const vals = plist
.map((p) => p.series[i])
.filter((v): v is number => typeof v === "number" && Number.isFinite(v))
if (!vals.length) return 0
return Math.round(vals.reduce((x, y) => x + y, 0) / vals.length)
const averaged = Array.from({ length: Math.min(innerLen,points) }, (_, i) => {
const vals=plist.map(p=>p.series[i])
if(vals.some(v=>typeof v!=="number"||!Number.isFinite(v)))return null
const mean=vals.reduce<number>((sum,v)=>sum+(v??0),0)/vals.length
return Number.isFinite(mean)?Math.round(mean):null
})
const key = `src-${sid}`
series[key] = padSeriesToLength(averaged, points)
if(!averaged.some(v=>v!==null))continue
const key = "src-"+sid
series[key] = averaged
const srv = servers.find((s) => s.id === sid)
const site = srv?.site?.trim()
labels[key] =