Skip to content

Commit d0d51c0

Browse files
committed
fix(realtime): 内置 WCDB sidecar 并切换项目内 DLL
- 桌面端启动时自动拉起 WCDB sidecar,并向后端注入连接参数 - 打包附带 sidecar 脚本与 koffi 运行时 - 改为通过项目内置 WeFlow DLL 处理 realtime 调用,规避宿主校验失败和连接超时
1 parent 0a639f7 commit d0d51c0

10 files changed

Lines changed: 1876 additions & 41 deletions

File tree

desktop/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@
5757
{
5858
"from": "resources/backend",
5959
"to": "backend"
60+
},
61+
{
62+
"from": "src/wcdb-sidecar.cjs",
63+
"to": "wcdb-sidecar.cjs"
64+
},
65+
{
66+
"from": "vendor/koffi",
67+
"to": "koffi"
6068
}
6169
],
6270
"win": {

desktop/src/main.cjs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ try {
1717
autoUpdaterLoadError = err;
1818
}
1919
const { spawn, spawnSync } = require("child_process");
20+
const crypto = require("crypto");
2021
const fs = require("fs");
2122
const http = require("http");
2223
const net = require("net");
@@ -33,6 +34,10 @@ const DEFAULT_BACKEND_HOST = String(process.env.WECHAT_TOOL_HOST || "127.0.0.1")
3334
const DEFAULT_BACKEND_PORT = parsePort(process.env.WECHAT_TOOL_PORT) ?? 10392;
3435

3536
let backendProc = null;
37+
let wcdbSidecarProc = null;
38+
let wcdbSidecarPort = null;
39+
let wcdbSidecarUrl = "";
40+
let wcdbSidecarToken = "";
3641
let resolvedDataDir = null;
3742
let mainWindow = null;
3843
let tray = null;
@@ -1452,8 +1457,159 @@ function getPackagedWcdbDllPath() {
14521457
return path.join(process.resourcesPath, "backend", "native", "wcdb_api.dll");
14531458
}
14541459

1460+
function getDevWcdbDllPath() {
1461+
return path.join(repoRoot(), "src", "wechat_decrypt_tool", "native", "wcdb_api.dll");
1462+
}
1463+
1464+
function getWcdbDllPath() {
1465+
return app.isPackaged ? getPackagedWcdbDllPath() : getDevWcdbDllPath();
1466+
}
1467+
1468+
function getWcdbDllDir() {
1469+
return path.dirname(getWcdbDllPath());
1470+
}
1471+
1472+
function getWcdbSidecarScriptPath() {
1473+
return app.isPackaged
1474+
? path.join(process.resourcesPath, "wcdb-sidecar.cjs")
1475+
: path.join(__dirname, "wcdb-sidecar.cjs");
1476+
}
1477+
1478+
function getKoffiDir() {
1479+
return app.isPackaged ? path.join(process.resourcesPath, "koffi") : path.join(repoRoot(), "desktop", "vendor", "koffi");
1480+
}
1481+
1482+
function getWcdbSidecarStdioLogPath(dataDir) {
1483+
return path.join(dataDir, "wcdb-sidecar-stdio.log");
1484+
}
1485+
1486+
function getWcdbSidecarPort() {
1487+
if (parsePort(wcdbSidecarPort) != null) return wcdbSidecarPort;
1488+
const envPort = parsePort(process.env.WECHAT_TOOL_WCDB_SIDECAR_PORT);
1489+
wcdbSidecarPort = envPort ?? Math.min(65535, getBackendPort() + 101);
1490+
return wcdbSidecarPort;
1491+
}
1492+
1493+
async function prepareWcdbSidecarPort() {
1494+
if (parsePort(wcdbSidecarPort) != null) return wcdbSidecarPort;
1495+
const envPort = parsePort(process.env.WECHAT_TOOL_WCDB_SIDECAR_PORT);
1496+
if (envPort != null) {
1497+
wcdbSidecarPort = envPort;
1498+
return wcdbSidecarPort;
1499+
}
1500+
const preferred = Math.min(65535, getBackendPort() + 101);
1501+
wcdbSidecarPort = await chooseAvailablePort(preferred, "127.0.0.1");
1502+
if (wcdbSidecarPort == null) wcdbSidecarPort = preferred;
1503+
return wcdbSidecarPort;
1504+
}
1505+
1506+
function getWcdbResourcePaths() {
1507+
const out = [];
1508+
const seen = new Set();
1509+
1510+
const add = (value) => {
1511+
const raw = String(value || "").trim();
1512+
if (!raw) return;
1513+
const resolved = path.resolve(raw);
1514+
const key = resolved.toLowerCase();
1515+
if (seen.has(key)) return;
1516+
seen.add(key);
1517+
out.push(resolved);
1518+
};
1519+
1520+
const dllDir = getWcdbDllDir();
1521+
add(dllDir);
1522+
add(path.dirname(dllDir));
1523+
add(repoRoot());
1524+
add(path.join(repoRoot(), "resources"));
1525+
const dataDir = resolveDataDir();
1526+
if (dataDir) {
1527+
add(dataDir);
1528+
add(path.join(dataDir, "resources"));
1529+
}
1530+
return out;
1531+
}
1532+
1533+
function ensureWcdbSidecarEnv(env) {
1534+
if (!wcdbSidecarUrl || !wcdbSidecarToken) return env;
1535+
env.WECHAT_TOOL_WCDB_SIDECAR_URL = wcdbSidecarUrl;
1536+
env.WECHAT_TOOL_WCDB_SIDECAR_TOKEN = wcdbSidecarToken;
1537+
return env;
1538+
}
1539+
1540+
function startWcdbSidecar() {
1541+
if (process.env.WECHAT_TOOL_WCDB_SIDECAR === "0") return null;
1542+
if (wcdbSidecarProc && wcdbSidecarProc.exitCode == null) return wcdbSidecarProc;
1543+
if (process.platform !== "win32") return null;
1544+
1545+
const dllPath = getWcdbDllPath();
1546+
const sidecarScript = getWcdbSidecarScriptPath();
1547+
const koffiDir = getKoffiDir();
1548+
if (!fs.existsSync(dllPath)) {
1549+
logMain(`[wcdb-sidecar] skip: missing wcdb_api.dll ${dllPath}`);
1550+
return null;
1551+
}
1552+
if (!fs.existsSync(sidecarScript)) {
1553+
logMain(`[wcdb-sidecar] skip: missing sidecar script ${sidecarScript}`);
1554+
return null;
1555+
}
1556+
if (!fs.existsSync(koffiDir)) {
1557+
logMain(`[wcdb-sidecar] skip: missing koffi runtime ${koffiDir}`);
1558+
return null;
1559+
}
1560+
1561+
const port = getWcdbSidecarPort();
1562+
const host = "127.0.0.1";
1563+
wcdbSidecarUrl = `http://${host}:${port}`;
1564+
wcdbSidecarToken = wcdbSidecarToken || crypto.randomBytes(24).toString("hex");
1565+
1566+
const env = {
1567+
...process.env,
1568+
ELECTRON_RUN_AS_NODE: "1",
1569+
WECHAT_TOOL_WCDB_SIDECAR_HOST: host,
1570+
WECHAT_TOOL_WCDB_SIDECAR_PORT: String(port),
1571+
WECHAT_TOOL_WCDB_SIDECAR_TOKEN: wcdbSidecarToken,
1572+
WECHAT_TOOL_WCDB_API_DLL_PATH: dllPath,
1573+
WECHAT_TOOL_WCDB_DLL_DIR: getWcdbDllDir(),
1574+
WECHAT_TOOL_WCDB_RESOURCE_PATHS: JSON.stringify(getWcdbResourcePaths()),
1575+
WECHAT_TOOL_KOFFI_DIR: koffiDir,
1576+
};
1577+
1578+
logMain(`[wcdb-sidecar] starting url=${wcdbSidecarUrl} dll=${dllPath}`);
1579+
wcdbSidecarProc = spawn(process.execPath, [sidecarScript], {
1580+
cwd: path.dirname(sidecarScript),
1581+
env,
1582+
stdio: ["ignore", "pipe", "pipe"],
1583+
windowsHide: true,
1584+
});
1585+
1586+
const dataDir = resolveDataDir() || getUserDataDir() || repoRoot();
1587+
attachBackendStdio(wcdbSidecarProc, getWcdbSidecarStdioLogPath(dataDir));
1588+
1589+
const proc = wcdbSidecarProc;
1590+
proc.on("exit", (code, signal) => {
1591+
if (wcdbSidecarProc === proc) wcdbSidecarProc = null;
1592+
logMain(`[wcdb-sidecar] exited code=${code} signal=${signal}`);
1593+
});
1594+
1595+
process.env.WECHAT_TOOL_WCDB_SIDECAR_URL = wcdbSidecarUrl;
1596+
process.env.WECHAT_TOOL_WCDB_SIDECAR_TOKEN = wcdbSidecarToken;
1597+
return wcdbSidecarProc;
1598+
}
1599+
1600+
function stopWcdbSidecar() {
1601+
if (!wcdbSidecarProc) return;
1602+
const pid = wcdbSidecarProc.pid;
1603+
logMain(`[wcdb-sidecar] stop pid=${pid || "?"}`);
1604+
try {
1605+
wcdbSidecarProc.kill();
1606+
} catch {}
1607+
wcdbSidecarProc = null;
1608+
}
1609+
14551610
function startBackend() {
14561611
if (backendProc) return backendProc;
1612+
startWcdbSidecar();
14571613

14581614
const env = {
14591615
...process.env,
@@ -1462,6 +1618,7 @@ function startBackend() {
14621618
// Make sure Python prints UTF-8 to stdout/stderr.
14631619
PYTHONIOENCODING: process.env.PYTHONIOENCODING || "utf-8",
14641620
};
1621+
ensureWcdbSidecarEnv(env);
14651622

14661623
// In packaged mode we expect to provide the generated Nuxt output dir via env.
14671624
if (app.isPackaged && !env.WECHAT_TOOL_UI_DIR) {
@@ -2135,6 +2292,7 @@ async function main() {
21352292
await applyPendingOutputDirOnStartup();
21362293
ensureOutputLink();
21372294
await ensureBackendPortAvailableOnStartup();
2295+
await prepareWcdbSidecarPort();
21382296

21392297
logMain(`[main] app.isPackaged=${app.isPackaged} argv=${JSON.stringify(process.argv)}`);
21402298

@@ -2190,6 +2348,7 @@ async function main() {
21902348

21912349
app.on("window-all-closed", () => {
21922350
stopBackend();
2351+
stopWcdbSidecar();
21932352
if (process.platform !== "darwin") app.quit();
21942353
});
21952354

@@ -2203,6 +2362,7 @@ app.on("before-quit", () => {
22032362
isQuitting = true;
22042363
destroyTray();
22052364
stopBackend();
2365+
stopWcdbSidecar();
22062366
});
22072367

22082368
if (gotSingleInstanceLock) {
@@ -2211,6 +2371,7 @@ if (gotSingleInstanceLock) {
22112371
console.error(err);
22122372
logMain(`[main] fatal: ${err?.stack || String(err)}`);
22132373
stopBackend();
2374+
stopWcdbSidecar();
22142375
try {
22152376
const dir = getUserDataDir();
22162377
const outputDir = resolveOutputDir();

0 commit comments

Comments
 (0)