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