feat: report version, handle remote upgrade via update-clawd.sh
Made-with: Cursor
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
const { getNotifySocket } = require('./systemd-env');
|
const { getNotifySocket } = require('./systemd-env');
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const { execFileSync, exec } = require('child_process');
|
const { execFileSync, exec } = require('child_process');
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
|
|
||||||
|
const CLAWD_VERSION = require(path.join(__dirname, '..', 'package.json')).version;
|
||||||
const log = require('./logger');
|
const log = require('./logger');
|
||||||
const { getBoxId } = require('./fingerprint');
|
const { getBoxId } = require('./fingerprint');
|
||||||
const { collect } = require('./metrics');
|
const { collect } = require('./metrics');
|
||||||
@@ -371,6 +374,7 @@ class ClawClient {
|
|||||||
box_id: this._boxId,
|
box_id: this._boxId,
|
||||||
claw_id: this._cfg.claw_id ?? null,
|
claw_id: this._cfg.claw_id ?? null,
|
||||||
token: this._cfg.token ?? null,
|
token: this._cfg.token ?? null,
|
||||||
|
version: CLAWD_VERSION,
|
||||||
local_ip: getLocalIps(),
|
local_ip: getLocalIps(),
|
||||||
local_networks: getLocalNetworks(),
|
local_networks: getLocalNetworks(),
|
||||||
external_ip: this._externalIp ?? null,
|
external_ip: this._externalIp ?? null,
|
||||||
@@ -392,6 +396,9 @@ class ClawClient {
|
|||||||
case 'status_update':
|
case 'status_update':
|
||||||
this._applyStatus(msg);
|
this._applyStatus(msg);
|
||||||
break;
|
break;
|
||||||
|
case 'upgrade':
|
||||||
|
this._handleUpgrade(msg);
|
||||||
|
break;
|
||||||
case 'error':
|
case 'error':
|
||||||
log.error('clawd', `服务器错误: ${msg.msg}`);
|
log.error('clawd', `服务器错误: ${msg.msg}`);
|
||||||
if (msg.msg === 'hardware_mismatch') {
|
if (msg.msg === 'hardware_mismatch') {
|
||||||
@@ -598,6 +605,7 @@ class ClawClient {
|
|||||||
type: 'heartbeat',
|
type: 'heartbeat',
|
||||||
claw_id: this._cfg.claw_id,
|
claw_id: this._cfg.claw_id,
|
||||||
token: this._cfg.token,
|
token: this._cfg.token,
|
||||||
|
version: CLAWD_VERSION,
|
||||||
local_ip: getLocalIps(),
|
local_ip: getLocalIps(),
|
||||||
local_networks: getLocalNetworks(),
|
local_networks: getLocalNetworks(),
|
||||||
...this._dashInfo,
|
...this._dashInfo,
|
||||||
@@ -618,6 +626,80 @@ class ClawClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 升级 ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
_sendUpgradeProgress(progress, step, failed = false, errorMsg = null) {
|
||||||
|
const msg = {
|
||||||
|
type: 'upgrade_progress',
|
||||||
|
claw_id: this._cfg.claw_id,
|
||||||
|
token: this._cfg.token,
|
||||||
|
progress,
|
||||||
|
step,
|
||||||
|
failed,
|
||||||
|
};
|
||||||
|
if (errorMsg) msg.error = errorMsg;
|
||||||
|
this._send(msg);
|
||||||
|
log.info('upgrade', `进度 ${progress}% - ${step}${failed ? ` [失败: ${errorMsg}]` : ''}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _handleUpgrade(msg) {
|
||||||
|
const targetVersion = msg.version;
|
||||||
|
const installDir = path.dirname(__dirname); // /opt/clawd 或同等安装目录
|
||||||
|
const scriptPath = path.join(installDir, 'tools', 'update-clawd.sh');
|
||||||
|
|
||||||
|
log.info('upgrade', `收到升级命令: ${CLAWD_VERSION} → ${targetVersion}`);
|
||||||
|
this._sendUpgradeProgress(5, 'starting');
|
||||||
|
|
||||||
|
// 检查脚本是否存在
|
||||||
|
if (!fs.existsSync(scriptPath)) {
|
||||||
|
const err = `升级脚本不存在: ${scriptPath}`;
|
||||||
|
log.error('upgrade', err);
|
||||||
|
this._sendUpgradeProgress(0, 'failed', true, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const child = exec(`bash "${scriptPath}" --no-restart`, { timeout: 300_000 });
|
||||||
|
|
||||||
|
child.stdout.on('data', (data) => {
|
||||||
|
const line = data.toString().trim();
|
||||||
|
log.info('upgrade', line);
|
||||||
|
|
||||||
|
// 根据脚本输出关键字上报进度
|
||||||
|
if (line.includes('Fetching latest')) this._sendUpgradeProgress(20, '拉取更新中');
|
||||||
|
else if (line.includes('Already up to date')) this._sendUpgradeProgress(100, 'already_up_to_date');
|
||||||
|
else if (line.includes('Updating working tree')) this._sendUpgradeProgress(50, '更新文件中');
|
||||||
|
else if (line.includes('npm install')) this._sendUpgradeProgress(70, '安装依赖中');
|
||||||
|
else if (line.includes('No dependency')) this._sendUpgradeProgress(80, '无需安装依赖');
|
||||||
|
else if (line.includes('Current commit')) this._sendUpgradeProgress(90, '即将重启');
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stderr.on('data', (data) => {
|
||||||
|
log.warn('upgrade', data.toString().trim());
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('close', (code) => {
|
||||||
|
if (code === 0) resolve();
|
||||||
|
else reject(new Error(`脚本退出码: ${code}`));
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('error', reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 脚本执行成功,通知服务端完成,然后退出让 systemd 重启
|
||||||
|
this._sendUpgradeProgress(100, 'done');
|
||||||
|
log.info('upgrade', `升级至 v${targetVersion} 完成,即将重启...`);
|
||||||
|
|
||||||
|
// 延迟 1.5 秒确保进度消息送达,再退出
|
||||||
|
setTimeout(() => process.exit(0), 1500);
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
log.error('upgrade', `升级失败: ${e.message}`);
|
||||||
|
this._sendUpgradeProgress(0, 'failed', true, e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── 工具 ────────────────────────────────────────────────────────────────────
|
// ── 工具 ────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
_send(obj) {
|
_send(obj) {
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ REPO_DIR="/opt/clawd"
|
|||||||
REMOTE="origin"
|
REMOTE="origin"
|
||||||
BRANCH="main"
|
BRANCH="main"
|
||||||
SERVICE="clawd.service"
|
SERVICE="clawd.service"
|
||||||
|
NO_RESTART=false
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--no-restart) NO_RESTART=true ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
echo "==> clawd update start"
|
echo "==> clawd update start"
|
||||||
date
|
date
|
||||||
@@ -41,13 +48,18 @@ else
|
|||||||
echo "==> No dependency changes, skip npm install"
|
echo "==> No dependency changes, skip npm install"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "==> Current commit:"
|
||||||
|
git log --oneline -1
|
||||||
|
|
||||||
|
if [ "$NO_RESTART" = true ]; then
|
||||||
|
echo "==> --no-restart: skip systemctl restart (caller handles restart)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
echo "==> Restarting service: $SERVICE"
|
echo "==> Restarting service: $SERVICE"
|
||||||
systemctl restart "$SERVICE"
|
systemctl restart "$SERVICE"
|
||||||
|
|
||||||
echo "==> Service status:"
|
echo "==> Service status:"
|
||||||
systemctl status "$SERVICE" --no-pager -l || true
|
systemctl status "$SERVICE" --no-pager -l || true
|
||||||
|
|
||||||
echo "==> Current commit:"
|
|
||||||
git log --oneline -1
|
|
||||||
|
|
||||||
echo "==> clawd update done"
|
echo "==> clawd update done"
|
||||||
Reference in New Issue
Block a user