fix: use shell background + polling to get dashboard info reliably

Made-with: Cursor
This commit is contained in:
stswangzhiping
2026-03-15 14:29:03 +08:00
parent 64cd7432e1
commit f5ae8b0710

View File

@@ -16,47 +16,43 @@ const FRPC_CONFIG = path.join(CONFIG_DIR, 'frpc.toml');
const FRP_VERSION = '0.62.0'; const FRP_VERSION = '0.62.0';
/** /**
* 启动 openclaw dashboard若未运行),等待输出中出现 Dashboard URL * 启动 openclaw dashboard后台运行),轮询日志文件等待 Dashboard URL 出现
* 解析并返回 { dashboard_token, dashboard_port }。 * 解析并返回 { dashboard_token, dashboard_port }。
* 超时或命令不存在时返回 {}。 * 超时10s或命令不存在时返回 {}。
* dashboard 进程会持续运行(不会被 kill
*/ */
function getDashboardInfo() { function getDashboardInfo() {
return new Promise((resolve) => { return new Promise((resolve) => {
let done = false; const tmpLog = '/tmp/clawd-dashboard.log';
const finish = (result) => {
if (!done) { done = true; resolve(result); }
};
// 8 秒内未收到 URL 则放弃 // 后台启动 dashboard输出重定向到日志文件
const timer = setTimeout(() => finish({}), 8000);
let proc;
try { try {
proc = spawn('openclaw', ['dashboard'], { execSync(`openclaw dashboard > ${tmpLog} 2>&1 &`, { shell: true, timeout: 3000 });
stdio: ['ignore', 'pipe', 'pipe'],
});
} catch (e) { } catch (e) {
clearTimeout(timer); // 已在运行或命令不存在,继续轮询
return finish({});
} }
const handleLine = (line) => { // 每秒读一次日志文件,最多等 10 秒
const match = line.match(/Dashboard URL:.*:(\d+)\/#token=([a-f0-9]+)/); let attempts = 0;
const interval = setInterval(() => {
attempts++;
try {
const content = fs.readFileSync(tmpLog, 'utf8');
const match = content.match(/Dashboard URL:.*:(\d+)\/#token=([a-f0-9]+)/);
if (match) { if (match) {
clearTimeout(timer); clearInterval(interval);
const port = parseInt(match[1], 10); const port = parseInt(match[1], 10);
const token = match[2]; const token = match[2];
console.log(`[frpc] openclaw dashboard: port=${port}, token=${token.substring(0, 8)}...`); console.log(`[frpc] openclaw dashboard: port=${port}, token=${token.substring(0, 8)}...`);
// 进程继续运行dashboard 服务),不 kill resolve({ dashboard_port: port, dashboard_token: token });
finish({ dashboard_port: port, dashboard_token: token }); return;
} }
}; } catch (e) { /* 文件暂时不存在 */ }
proc.stdout.on('data', d => handleLine(d.toString())); if (attempts >= 10) {
proc.stderr.on('data', d => handleLine(d.toString())); clearInterval(interval);
proc.on('error', () => { clearTimeout(timer); finish({}); }); resolve({});
proc.on('exit', () => { clearTimeout(timer); finish({}); }); }
}, 1000);
}); });
} }