const BRIDGE_URL = "ws://localhost:9333"; const REFRESH_MS = 2000; const badgeBridge = document.getElementById("badge-bridge"); const badgeExtension = document.getElementById("badge-extension"); const badgeLogin = document.getElementById("badge-login"); const hintText = document.getElementById("hint-text"); const btnRefresh = document.getElementById("btn-refresh"); const btnOpenXhs = document.getElementById("btn-open-xhs"); let timerId = null; function setBadge(el, kind, text) { el.textContent = text; el.className = `badge ${kind}`; } function pingBridgeServer() { return new Promise((resolve) => { let settled = false; const finish = (value) => { if (settled) return; settled = true; resolve(value); }; let ws; try { ws = new WebSocket(BRIDGE_URL); } catch (err) { finish({ server: false, extension: false, error: String(err) }); return; } const timer = setTimeout(() => { try { ws.close(); } catch (_) { /* ignore */ } finish({ server: false, extension: false }); }, 2500); ws.onopen = () => { ws.send(JSON.stringify({ role: "cli", method: "ping_server" })); }; ws.onmessage = (event) => { clearTimeout(timer); try { const data = JSON.parse(event.data); finish({ server: true, extension: !!(data.result && data.result.extension_connected), }); } catch (_) { finish({ server: true, extension: false }); } try { ws.close(); } catch (_) { /* ignore */ } }; ws.onerror = () => { clearTimeout(timer); finish({ server: false, extension: false }); }; }); } async function getExtensionWsStatus() { try { return await chrome.runtime.sendMessage({ type: "monitor_bridge_ws" }); } catch (_) { return { extension_connected: false }; } } async function checkXhsLogin() { try { return await chrome.runtime.sendMessage({ type: "monitor_check_login" }); } catch (err) { return { logged_in: false, error: String(err) }; } } async function refreshStatus() { const now = new Date().toLocaleTimeString("zh-CN", { hour12: false }); hintText.textContent = `更新于 ${now}`; setBadge(badgeBridge, "idle", "检测中…"); setBadge(badgeExtension, "idle", "检测中…"); setBadge(badgeLogin, "idle", "检测中…"); const [bridge, wsStatus, login] = await Promise.all([ pingBridgeServer(), getExtensionWsStatus(), checkXhsLogin(), ]); if (bridge.server) { setBadge(badgeBridge, "ok", "运行中"); } else { setBadge(badgeBridge, "err", "未启动"); } const extOk = bridge.extension || wsStatus.extension_connected; if (extOk) { setBadge(badgeExtension, "ok", "已连接"); } else if (bridge.server) { setBadge(badgeExtension, "warn", "未连上"); } else { setBadge(badgeExtension, "err", "未连接"); } if (login.logged_in) { setBadge(badgeLogin, "ok", "已登录"); } else if (login.uncertain) { setBadge(badgeLogin, "warn", "不确定"); } else { setBadge(badgeLogin, "warn", "未登录"); } if (login.hint) { hintText.textContent = `${login.hint} · ${now}`; } } function startAutoRefresh() { if (timerId) clearInterval(timerId); timerId = setInterval(refreshStatus, REFRESH_MS); } btnRefresh.addEventListener("click", () => { refreshStatus(); }); btnOpenXhs.addEventListener("click", () => { chrome.tabs.create({ url: "https://www.xiaohongshu.com/" }); }); refreshStatus(); startAutoRefresh(); document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { refreshStatus(); } });