66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import type { PingProbe, Server } from "@/lib/data"
|
|
|
|
/** Длина ряда на графике дашборда (ось времени). */
|
|
export const DASH_LATENCY_POINTS = 60
|
|
|
|
export interface DashboardLatencyChartInput {
|
|
series: Record<string, (number|null)[]>
|
|
labels: Record<string, string>
|
|
}
|
|
|
|
/**
|
|
* Средний RTT по измеренным общим корзинам включённых проб одного источника.
|
|
* Не интерполируем и не подменяем отсутствующие измерения нулями.
|
|
* Ключ серии — стабильный id вида `src-<numericId>`; подпись — площадка или имя сервера.
|
|
* Ограничение числа линий — чтобы график оставался читаемым.
|
|
*/
|
|
export function buildLatencySeriesByProbeSource(
|
|
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, Array<Pick<PingProbe,"enabled"|"srcServerId">&{series:(number|null)[]}>>()
|
|
for (const p of probes) {
|
|
if (!p.enabled || !p.series?.length) continue
|
|
const sid = p.srcServerId
|
|
if (!bySrv.has(sid)) bySrv.set(sid, [])
|
|
bySrv.get(sid)!.push(p)
|
|
}
|
|
|
|
const sortedIds = [...bySrv.keys()].sort((a, b) => {
|
|
const na = servers.find((s) => s.id === a)?.name ?? a
|
|
const nb = servers.find((s) => s.id === b)?.name ?? b
|
|
return na.localeCompare(nb, "ru")
|
|
}).slice(0, maxServers)
|
|
|
|
const series: Record<string, (number|null)[]> = {}
|
|
const labels: Record<string, string> = {}
|
|
|
|
for (const sid of sortedIds) {
|
|
const plist = bySrv.get(sid)!
|
|
const innerLen = plist.reduce((m, p) => Math.max(m, p.series.length), 0)
|
|
if (innerLen === 0) continue
|
|
|
|
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
|
|
})
|
|
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] =
|
|
site && site !== "—"
|
|
? site.slice(0, 16)
|
|
: (srv?.name ?? `#${sid}`).slice(0, 16)
|
|
}
|
|
|
|
return { series, labels }
|
|
}
|