const SERVER_STORAGE_KEY = "llm_monitor_servers"; const ACTIVE_SERVER_KEY = "llm_monitor_active_server"; const DATA_REFRESH_INTERVAL_MS = 30000; function normalizeHost(host) { if (!host) { return ""; } const trimmed = host.trim(); if (!trimmed) { return ""; } return trimmed.replace(/\/+$/, ""); } function loadServers() { const raw = localStorage.getItem(SERVER_STORAGE_KEY); if (!raw) { return []; } try { const parsed = JSON.parse(raw); if (!Array.isArray(parsed)) { return []; } return parsed .map((item) => ({ id: String(item.id || ""), name: String(item.name || "").trim(), host: normalizeHost(item.host || "") })) .filter((item) => item.id && item.name && item.host); } catch { return []; } } function saveServers(servers) { localStorage.setItem(SERVER_STORAGE_KEY, JSON.stringify(servers)); } function generateServerId() { return `srv_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`; } function getActiveServerId() { return localStorage.getItem(ACTIVE_SERVER_KEY); } function setActiveServerId(serverId) { localStorage.setItem(ACTIVE_SERVER_KEY, serverId); } function getServerById(serverId) { return loadServers().find((server) => server.id === serverId) || null; } function getServerIdFromQuery() { const params = new URLSearchParams(window.location.search); return params.get("server") || ""; } function getActiveServer() { const queryServerId = getServerIdFromQuery(); if (queryServerId) { const fromQuery = getServerById(queryServerId); if (fromQuery) { setActiveServerId(fromQuery.id); return fromQuery; } } const activeServerId = getActiveServerId(); if (activeServerId) { const activeServer = getServerById(activeServerId); if (activeServer) { return activeServer; } } const servers = loadServers(); if (servers.length > 0) { setActiveServerId(servers[0].id); return servers[0]; } return null; } function buildServerUrl(path, serverId) { const url = new URL(path, window.location.origin); if (serverId) { url.searchParams.set("server", serverId); } return `${url.pathname}${url.search}`; } function getServerStorageKey(serverId, suffix) { return `llm_monitor_${suffix}_${serverId}`; } function readServerCache(serverId, suffix) { if (!serverId) { return null; } const raw = localStorage.getItem(getServerStorageKey(serverId, suffix)); if (!raw) { return null; } try { return JSON.parse(raw); } catch { return null; } } function writeServerCache(serverId, suffix, value) { if (!serverId) { return; } localStorage.setItem(getServerStorageKey(serverId, suffix), JSON.stringify(value)); } function getCacheTimestamp(cacheValue) { if (!cacheValue || !cacheValue.timestamp) { return 0; } const parsed = Date.parse(cacheValue.timestamp); return Number.isNaN(parsed) ? 0 : parsed; } function getLatestServerCacheTimestamp(serverId, suffixes) { return suffixes.reduce((latest, suffix) => { const value = readServerCache(serverId, suffix); return Math.max(latest, getCacheTimestamp(value)); }, 0); } function isCacheStale(timestamp, maxAgeMs = DATA_REFRESH_INTERVAL_MS) { if (!timestamp) { return true; } return (Date.now() - timestamp) >= maxAgeMs; }