export const DIAGNOSTIC_ROLES = ["main", "split", "pit_entry", "pit_exit"]; export function createDecoderDiagnostics(now = Date.now) { const channels = new Map(); function channel(role) { const key = DIAGNOSTIC_ROLES.includes(role) ? role : "main"; if (!channels.has(key)) channels.set(key, { role: key, status: "disconnected", url: "", connectedAt: null, lastReceivedAt: null, frames: 0, messages: 0, passings: 0, handled: 0, ignored: 0, invalid: 0, parseErrors: 0, lastFrame: "", log: [] }); return channels.get(key); } function log(entry, reason, sample = "") { entry.log.push({ at: now(), reason, sample: String(sample).slice(0, 512) }); if (entry.log.length > 50) entry.log.splice(0, entry.log.length - 50); } return { socket(role, status, url = "") { const entry = channel(role); entry.status = status; if (url) entry.url = String(url); if (status === "connected") entry.connectedAt = now(); log(entry, status); }, frame(role, data) { const entry = channel(role); entry.frames++; entry.lastReceivedAt = now(); entry.lastFrame = String(data).slice(0, 512); }, parseError(role) { const entry = channel(role); entry.parseErrors++; log(entry, "invalid_json", entry.lastFrame); }, message(role, msg, reason, outcome = "ignored") { const entry = channel(role); entry.messages++; if (String(msg?.msg || msg?.type || "").toUpperCase() === "PASSING") entry.passings++; if (["handled", "ignored", "invalid"].includes(outcome)) entry[outcome]++; let sample = ""; try { sample = JSON.stringify({ type: msg?.msg || msg?.type, transponder: msg?.transponder ?? msg?.tran_code, rtc_time: msg?.rtc_time }); } catch {} log(entry, reason, sample); }, snapshot() { return DIAGNOSTIC_ROLES.map(role => { const entry = channel(role); return { ...entry, log: entry.log.map(item => ({ ...item })) }; }); }, clear(role) { const entry = channel(role); for (const key of ["frames", "messages", "passings", "handled", "ignored", "invalid", "parseErrors"]) entry[key] = 0; entry.lastFrame = ""; entry.log = []; }, }; } export const decoderDiagnostics = createDecoderDiagnostics();