fix: getDashboardInfo uses spawn+Promise to handle long-running process
Made-with: Cursor
This commit is contained in:
@@ -20,10 +20,9 @@ class ClawClient {
|
|||||||
this._dashInfo = {}; // { dashboard_token, dashboard_port }
|
this._dashInfo = {}; // { dashboard_token, dashboard_port }
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
async start() {
|
||||||
console.log(`[clawd] 启动中... 服务器 = ${this._cfg.server}`);
|
console.log(`[clawd] 启动中... 服务器 = ${this._cfg.server}`);
|
||||||
// 启动前提取 openclaw dashboard 信息(耗时操作放后台,不阻塞连接)
|
this._dashInfo = await getDashboardInfo();
|
||||||
this._dashInfo = getDashboardInfo();
|
|
||||||
this._connect();
|
this._connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
56
lib/frpc.js
56
lib/frpc.js
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { execSync, spawn, execFileSync } = require('child_process');
|
const { execSync, spawn } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
@@ -16,28 +16,48 @@ const FRPC_CONFIG = path.join(CONFIG_DIR, 'frpc.toml');
|
|||||||
const FRP_VERSION = '0.62.0';
|
const FRP_VERSION = '0.62.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取 openclaw dashboard 的访问 token 和端口。
|
* 启动 openclaw dashboard(若未运行),等待输出中出现 Dashboard URL,
|
||||||
* 执行 `openclaw dashboard`,从输出中解析 Dashboard URL。
|
* 解析并返回 { dashboard_token, dashboard_port }。
|
||||||
* 返回 { dashboard_token, dashboard_port } 或 {}(命令不存在/失败时)。
|
* 超时或命令不存在时返回 {}。
|
||||||
|
* dashboard 进程会持续运行(不会被 kill)。
|
||||||
*/
|
*/
|
||||||
function getDashboardInfo() {
|
function getDashboardInfo() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let done = false;
|
||||||
|
const finish = (result) => {
|
||||||
|
if (!done) { done = true; resolve(result); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 8 秒内未收到 URL 则放弃
|
||||||
|
const timer = setTimeout(() => finish({}), 8000);
|
||||||
|
|
||||||
|
let proc;
|
||||||
try {
|
try {
|
||||||
const out = execSync(
|
proc = spawn('openclaw', ['dashboard'], {
|
||||||
`openclaw dashboard 2>&1 | grep 'Dashboard URL' | sed -E 's|.*:([0-9]+)/.*#token=([a-f0-9]+).*|\\1 \\2|'`,
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
{ timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'] }
|
});
|
||||||
).toString().trim();
|
|
||||||
|
|
||||||
if (!out) return {};
|
|
||||||
const [portStr, token] = out.split(' ');
|
|
||||||
const port = parseInt(portStr, 10);
|
|
||||||
if (!token || isNaN(port)) return {};
|
|
||||||
|
|
||||||
console.log(`[frpc] openclaw dashboard: port=${port}, token=${token.substring(0, 8)}...`);
|
|
||||||
return { dashboard_port: port, dashboard_token: token };
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// openclaw 未安装或命令失败,跳过
|
clearTimeout(timer);
|
||||||
return {};
|
return finish({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleLine = (line) => {
|
||||||
|
const match = line.match(/Dashboard URL:.*:(\d+)\/#token=([a-f0-9]+)/);
|
||||||
|
if (match) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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({}); });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user