#!/usr/bin/env bash set -euo pipefail cat <<'EOF' 在 Chrome DevTools Console 粘贴执行: (() => { const stamp = () => new Date().toISOString(); const counts = {}; const wrap = (name) => { const original = window[name]; if (typeof original !== "function") { console.log(`[probe] ${name}:`, typeof original); return; } counts[name] = 0; const wrapped = function (...args) { counts[name] += 1; console.log(`[probe ${stamp()}] ${name} called`, args); try { const ret = original.apply(this, args); console.log(`[probe ${stamp()}] ${name} returned`, ret); return ret; } catch (err) { console.error(`[probe ${stamp()}] ${name} threw`, err); throw err; } }; wrapped.__deployTestProbe = true; wrapped.__deployTestOriginal = original; window[name] = wrapped; console.log(`[probe] ${name}: wrapped`); }; ["initSDK", "login", "commonEventFunc"].forEach(wrap); window.addEventListener("error", (event) => { console.error("[probe window error]", event.message, event.filename, event.lineno, event.error); }); window.addEventListener("unhandledrejection", (event) => { console.error("[probe unhandledrejection]", event.reason); }); console.log("[probe ready]", { electronAPI: Boolean(window.electronAPI), Go: typeof Go, initSDK: typeof window.initSDK, login: typeof window.login, commonEventFunc: typeof window.commonEventFunc, openIMRenderApi: typeof window.openIMRenderApi, }); window.__deployTestProbeCounts = counts; window.__deployTestReadLocalForage = async (key) => { const tryRead = (dbName, storeName) => new Promise((resolve, reject) => { const req = indexedDB.open(dbName); req.onerror = () => reject(req.error); req.onsuccess = () => { const db = req.result; if (!Array.from(db.objectStoreNames || []).includes(storeName)) { db.close(); resolve(undefined); return; } const tx = db.transaction(storeName, "readonly"); const store = tx.objectStore(storeName); const getReq = store.get(key); getReq.onerror = () => reject(getReq.error); getReq.onsuccess = () => { db.close(); resolve(getReq.result); }; }; }); for (const dbName of ["localforage", "OpenCorp-Base"]) { for (const storeName of ["keyvaluepairs", "local-forage-detect-blob-support"]) { try { const value = await tryRead(dbName, storeName); if (value) return value; } catch (err) { console.warn(`[probe] read ${dbName}/${storeName}/${key} failed`, err); } } } return undefined; }; window.__deployTestListBrowserDBs = async () => { const dbs = indexedDB.databases ? await indexedDB.databases() : []; console.log("[probe] indexedDB databases", dbs); if (window.caches?.keys) { console.log("[probe] cache keys", await caches.keys()); } return dbs; }; window.__deployTestResetBrowserStorage = async () => { console.warn("[probe] 清理当前站点浏览器存储:localStorage / CacheStorage / IndexedDB"); localStorage.clear(); if (window.caches?.keys) { for (const key of await caches.keys()) { console.warn("[probe] delete cache", key, await caches.delete(key)); } } if (indexedDB.databases) { for (const db of await indexedDB.databases()) { if (!db.name) continue; await new Promise((resolve) => { const req = indexedDB.deleteDatabase(db.name); req.onsuccess = () => { console.warn("[probe] deleted indexedDB", db.name); resolve(); }; req.onerror = () => { console.warn("[probe] delete indexedDB failed", db.name, req.error); resolve(); }; req.onblocked = () => { console.warn("[probe] delete indexedDB blocked, close other tabs then retry", db.name); resolve(); }; }); } } else { console.warn("[probe] indexedDB.databases() 不可用,请在 DevTools Application 面板手动清理 IndexedDB"); } console.warn("[probe] 清理完成,请关闭其它同源标签页后刷新页面并重新登录"); }; window.__deployTestManualLogin = async ({ userID, token, apiAddr, wsAddr } = {}) => { userID = userID || await window.__deployTestReadLocalForage("IM_USERID"); token = token || await window.__deployTestReadLocalForage("IM_TOKEN"); const operationID = `deploy-test-${Date.now()}`; const config = { platformID: 5, apiAddr: apiAddr || "http://54.116.29.247/api/im", wsAddr: wsAddr || "ws://54.116.29.247/msg_gateway", dataDir: "./", logLevel: 5, isLogStandardOutput: true, logFilePath: "./", isExternalExtensions: false, }; console.log(`[probe ${stamp()}] manual initSDK`, { operationID, config }); window.initSDK(operationID, JSON.stringify(config)); console.log(`[probe ${stamp()}] manual login start`, { operationID, userID, hasToken: Boolean(token) }); const timeout = new Promise((_, reject) => { setTimeout(() => reject(new Error("manual window.login timeout after 15000ms")), 15000); }); const result = await Promise.race([window.login(operationID, String(userID || ""), String(token || "")), timeout]); console.log(`[probe ${stamp()}] manual login result`, result); return result; }; clearInterval(window.__deployTestProbeTimer); window.__deployTestProbeTimer = setInterval(() => { console.log(`[probe ${stamp()}] counts`, { ...counts }); }, 5000); })(); 然后退出登录/刷新页面重新登录一次,观察是否打印: - initSDK called / returned - login called / returned - window error / unhandledrejection - counts 里的 initSDK/login 是否从 0 变成 1 如果点登录后 counts 仍为 0,可用当前登录 token 手动测: window.__deployTestManualLogin() 如果自动读取 token 失败,再手动传入: window.__deployTestManualLogin({ userID: "6087132211", token: "把 console 里 SDK login args 的 token 粘到这里" }) 若报 10006 init database invoke javascript timeout,先查看并清理当前站点浏览器数据库: await window.__deployTestListBrowserDBs() await window.__deployTestResetBrowserStorage() 清理后按这个顺序重测: 1. 关闭其它 http://54.116.29.247:5173 标签页 2. 刷新页面 3. 重新粘贴本脚本输出的整段 JS(刷新会清掉已安装的 probe) 4. 再登录 5. 观察 counts 是否从 0 变 1,以及 /var/log/nginx/openim-pc-proxy-access.log 是否出现 /msg_gateway EOF