import { getRpcBaseUrl } from '@/services/rpc-client'; import type { GetCableHealthResponse, CableHealthRecord as ProtoCableHealthRecord } from '@/generated/client/worldmonitor/infrastructure/v1/service_client'; import type { CableHealthRecord, CableHealthResponse, CableHealthStatus } from '@/types'; import { createCircuitBreaker } from '@/utils'; import { InfrastructureServiceClient } from '@/services/generated-rpc-clients'; const client = new InfrastructureServiceClient(getRpcBaseUrl(), { fetch: (...args) => globalThis.fetch(...args) }); const breaker = createCircuitBreaker({ name: 'Cable Health', cacheTtlMs: 10 * 60 * 1000, persistCache: true }); const emptyFallback: GetCableHealthResponse = { generatedAt: 0, cables: {} }; // ---- Proto enum -> frontend string adapter ---- const STATUS_REVERSE: Record = { CABLE_HEALTH_STATUS_FAULT: 'fault', CABLE_HEALTH_STATUS_DEGRADED: 'degraded', CABLE_HEALTH_STATUS_OK: 'ok', CABLE_HEALTH_STATUS_UNSPECIFIED: 'unknown', }; function toRecord(proto: ProtoCableHealthRecord): CableHealthRecord { return { status: STATUS_REVERSE[proto.status] || 'unknown', score: proto.score, confidence: proto.confidence, lastUpdated: proto.lastUpdated ? new Date(proto.lastUpdated).toISOString() : new Date().toISOString(), evidence: proto.evidence.map((e) => ({ source: e.source, summary: e.summary, ts: e.ts ? new Date(e.ts).toISOString() : new Date().toISOString(), })), }; } // ---- Local cache (1 minute) ---- let cachedResponse: CableHealthResponse | null = null; let cacheExpiry = 0; const LOCAL_CACHE_MS = 60_000; // ---- Public API ---- export async function fetchCableHealth(): Promise { const now = Date.now(); if (cachedResponse && now < cacheExpiry) return cachedResponse; const resp = await breaker.execute(async () => { return client.getCableHealth({}); }, emptyFallback, { shouldCache: (r) => Object.keys(r.cables).length > 0 }); const cables: Record = {}; for (const [id, proto] of Object.entries(resp.cables)) { cables[id] = toRecord(proto); } const result: CableHealthResponse = { generatedAt: resp.generatedAt ? new Date(resp.generatedAt).toISOString() : new Date().toISOString(), cables, }; cachedResponse = result; cacheExpiry = now + LOCAL_CACHE_MS; return result; } export function getCableHealthRecord(cableId: string): CableHealthRecord | undefined { return cachedResponse?.cables[cableId]; } export function getCableHealthMap(): Record { return cachedResponse?.cables ?? {}; }