Files
deploy-test/pc-sdk-probe.sh
2026-04-14 15:20:00 +07:00

282 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
cat <<'EOF'
在 Chrome DevTools Console 粘贴执行:
(() => {
const stamp = () => new Date().toISOString();
const counts = {};
if (!window.__deployTestWorkerWrapped) {
const NativeWorker = window.Worker;
window.Worker = function (url, options) {
console.log(`[probe ${stamp()}] new Worker`, { url: String(url), options });
const worker = new NativeWorker(url, options);
worker.addEventListener("error", (event) => {
console.error("[probe worker error]", {
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
});
});
worker.addEventListener("messageerror", (event) => {
console.error("[probe worker messageerror]", event);
});
const originalPostMessage = worker.postMessage.bind(worker);
worker.postMessage = (...args) => {
console.log(`[probe ${stamp()}] worker.postMessage`, { url: String(url), args });
return originalPostMessage(...args);
};
return worker;
};
window.Worker.prototype = NativeWorker.prototype;
window.__deployTestWorkerWrapped = true;
console.log("[probe] Worker: wrapped; reload page after installing this probe to catch SDK worker creation");
}
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", "initDB", "setSqlWasmPath"].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,
initDB: typeof window.initDB,
setSqlWasmPath: typeof window.setSqlWasmPath,
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.__deployTestAuthState = async () => {
const state = {
href: window.location.href,
hash: window.location.hash,
userID: await window.__deployTestReadLocalForage("IM_USERID"),
hasIMToken: Boolean(await window.__deployTestReadLocalForage("IM_TOKEN")),
hasChatToken: Boolean(await window.__deployTestReadLocalForage("IM_CHAT_TOKEN")),
counts: { ...counts },
};
console.log("[probe] auth state", state);
return state;
};
if (!window.__deployTestXHRWrapped) {
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url, ...args) {
this.__deployTestRequest = { method, url, startedAt: Date.now() };
return originalOpen.call(this, method, url, ...args);
};
XMLHttpRequest.prototype.send = function (...args) {
const req = this.__deployTestRequest;
if (req) {
this.addEventListener("loadend", () => {
if (String(req.url).includes("/account/login") || String(req.url).includes("/auth/get_user_token")) {
console.log("[probe xhr]", {
method: req.method,
url: req.url,
status: this.status,
ms: Date.now() - req.startedAt,
response: String(this.responseText || "").slice(0, 500),
});
}
});
}
return originalSend.apply(this, args);
};
window.__deployTestXHRWrapped = true;
console.log("[probe] XMLHttpRequest: wrapped");
}
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 gatewayOrigin = window.location.protocol === "https:" ? window.location.origin : "http://54.116.29.247";
const config = {
platformID: 5,
apiAddr: apiAddr || `${gatewayOrigin}/api/im`,
wsAddr: wsAddr || `${gatewayOrigin.replace(/^http/, "ws")}/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;
};
window.__deployTestManualInitDB = async (userID) => {
userID = userID || await window.__deployTestReadLocalForage("IM_USERID") || "6087132211";
console.log(`[probe ${stamp()}] manual setSqlWasmPath`, "/sql-wasm.wasm");
if (typeof window.setSqlWasmPath === "function") {
try {
const setPathTimeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error("manual window.setSqlWasmPath timeout after 5000ms")), 5000);
});
await Promise.race([window.setSqlWasmPath("/sql-wasm.wasm"), setPathTimeout]);
console.log(`[probe ${stamp()}] manual setSqlWasmPath done`);
} catch (err) {
console.error(`[probe ${stamp()}] manual setSqlWasmPath failed`, err);
}
}
console.log(`[probe ${stamp()}] manual initDB start`, { userID, dataDir: "./" });
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error("manual window.initDB timeout after 15000ms")), 15000);
});
const result = await Promise.race([window.initDB(String(userID), "./"), timeout]);
console.log(`[probe ${stamp()}] manual initDB result`, result);
return result;
};
clearInterval(window.__deployTestProbeTimer);
window.__deployTestProbeTimer = setInterval(() => {
console.log(`[probe ${stamp()}] counts`, { ...counts });
}, 5000);
})();
然后退出登录/刷新页面重新登录一次,观察是否打印:
- new Worker / worker.postMessage / worker error
- initSDK / login / initDB / setSqlWasmPath 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()
也可以单独测试 initDB
await window.__deployTestManualInitDB()
清理后按这个顺序重测:
1. 关闭其它 http://54.116.29.247:5173 / https://54.116.29.247 标签页
2. 打开 https://54.116.29.247/ 并刷新页面(首次访问需接受自签名证书)
3. 重新粘贴本脚本输出的整段 JS刷新会清掉已安装的 probe
4. 再登录
5. 观察 counts 是否从 0 变 1以及 /var/log/nginx/openim-pc-proxy-access.log 是否出现 /msg_gateway
如果 counts 仍为 0查看业务登录链路状态
await window.__deployTestAuthState()
EOF