/** * Снимок прогона планировщика (JSON из `scheduler_runs.result_json`). * Дублирует контракт `backend/src/types/scheduler-run-snapshot.ts` для UI. */ export interface ServerRestPingSnapshot { serverId: number name: string host: string ok: boolean latencyMs?: number | null error?: string } export interface ServersRestPingRunSnapshot { v: number job: "servers_rest_ping" sampledAt: string skipped?: boolean fatalError?: string servers: ServerRestPingSnapshot[] } export type AlertEngineRuleDiagSnapshot = { ruleId: string inGroup: boolean evalHit: boolean hitTransition?: "problem" | "recovery" | "neutral" hitMessage?: string stabilityOk: boolean cooldownOk: boolean telegramOk: boolean blocked?: | "no_hit" | "stability" | "cooldown" | "no_telegram" | "dedupe_positive" | "in_group" } /** Сводка прогона движка оповещений (JSON из `scheduler_runs` для job `alert_engine`). */ export interface AlertEngineRunSnapshot { v: number job: "alert_engine" sampledAt: string rulesChecked: number standaloneFires: number groupFires: number skippedNoTelegram: boolean errors?: string[] ruleDiag?: AlertEngineRuleDiagSnapshot[] } export interface GreBgpSnapshotRunSnapshot { v: number job: "gre_bgp" sampledAt: string skipped?: boolean fatalError?: string greWritten: number bgpWritten: number errors?: string[] } export interface InternetPathRunSnapshot { v: number job: "internet_path" sampledAt: string homes: number snapshotSaved: boolean fatalError?: string } export interface CertificatesRenewRunSnapshot { v: number job: "certificates_renew" sampledAt: string skipped?: boolean fatalError?: string checked: number renewed: number skippedTargets: number errors: string[] } export interface BackupsRunSnapshot { v: number job: "backups" sampledAt: string skipped?: boolean due: boolean created: number failures: number pruned: number errors?: string[] fatalError?: string } export type SchedulerRunSnapshot = | TrafficRunSnapshot | ResourcesRunSnapshot | PingRunSnapshot | SpeedScheduledRunSnapshot | ServersRestPingRunSnapshot | GreBgpSnapshotRunSnapshot | InternetPathRunSnapshot | CertificatesRenewRunSnapshot | BackupsRunSnapshot | AlertEngineRunSnapshot export interface TrafficServerSnapshot { serverId: number name: string host: string ok: boolean error?: string interfaces?: number sumRxMbps?: number sumTxMbps?: number } export interface TrafficRunSnapshot { v: number job: "traffic" sampledAt: string skipped?: boolean fatalError?: string servers: TrafficServerSnapshot[] } export interface ResourceServerSnapshot { serverId: number name: string host: string status: "online" | "offline" error?: string cpuLoadPct?: number memUsedMb?: number memTotalMb?: number memUsedPct?: number diskFreeMb?: number diskTotalMb?: number uptimeSeconds?: number boardName?: string rosVersion?: string } export interface ResourcesRunSnapshot { v: number job: "uptime_resources" sampledAt: string skipped?: boolean fatalError?: string servers: ResourceServerSnapshot[] } export interface PingProbeSnapshot { probeId: string name: string target: string srcServerId: number srcServerName: string srcInterface: string ok: boolean rttMs: number | null lossPct: number status: "up" | "warn" | "down" error?: string } export interface PingRunSnapshot { v: number job: "uptime_ping" sampledAt: string skipped?: boolean fatalError?: string probes: PingProbeSnapshot[] skippedByInterval?: number } export interface SpeedRunSnapshot { probeId: string srcServerId: number srcServerName: string dstServerId: number dstServerName: string srcInterface: string dstInterface: string protocol: string direction: string durationSec: number ok: boolean txAvgMbps?: number | null rxAvgMbps?: number | null pingRttMs?: number | null pingLossPct?: number | null pingError?: string | null error?: string } export interface SpeedScheduledRunSnapshot { v: number job: "uptime_speed" sampledAt: string runs: SpeedRunSnapshot[] } export function parseSchedulerRunSnapshot(raw: string | null | undefined): SchedulerRunSnapshot | null { if (raw == null || raw.trim() === "") return null try { const o = JSON.parse(raw) as { v?: unknown; job?: string } if (o?.v !== 1 || typeof o.job !== "string") return null return o as SchedulerRunSnapshot } catch { return null } }