feat: connect 消息上报 local_ip 和 external_ip
Made-with: Cursor
This commit is contained in:
@@ -8,7 +8,7 @@ const { getBoxId } = require('./fingerprint');
|
|||||||
const { collect } = require('./metrics');
|
const { collect } = require('./metrics');
|
||||||
const { getDashboardInfo, startTtyd, FrpcManager } = require('./frpc'); // getDashboardInfo 也用于心跳中定期刷新
|
const { getDashboardInfo, startTtyd, FrpcManager } = require('./frpc'); // getDashboardInfo 也用于心跳中定期刷新
|
||||||
const { ProvisionManager } = require('./provisioning');
|
const { ProvisionManager } = require('./provisioning');
|
||||||
const { hasInternet } = require('./network');
|
const { hasInternet, getLocalIps } = require('./network');
|
||||||
const led = require('./led');
|
const led = require('./led');
|
||||||
|
|
||||||
const MAX_BACKOFF_MS = 60_000;
|
const MAX_BACKOFF_MS = 60_000;
|
||||||
@@ -35,6 +35,7 @@ class ClawClient {
|
|||||||
this._frpc = new FrpcManager();
|
this._frpc = new FrpcManager();
|
||||||
this._dashInfo = {};
|
this._dashInfo = {};
|
||||||
this._hbCount = 0; // 心跳计数器,用于定期刷新 dashboard 信息
|
this._hbCount = 0; // 心跳计数器,用于定期刷新 dashboard 信息
|
||||||
|
this._externalIp = null; // 外网 IP(连接时查询一次,用于服务端地理位置解析)
|
||||||
|
|
||||||
// WS 层活性检测
|
// WS 层活性检测
|
||||||
this._pingTimer = null;
|
this._pingTimer = null;
|
||||||
@@ -111,6 +112,27 @@ class ClawClient {
|
|||||||
startTtyd().catch(e => log.warn('ttyd', '启动失败:', e.message)),
|
startTtyd().catch(e => log.warn('ttyd', '启动失败:', e.message)),
|
||||||
]);
|
]);
|
||||||
this._dashInfo = dashInfo || {};
|
this._dashInfo = dashInfo || {};
|
||||||
|
|
||||||
|
// 查询外网 IP(用于服务端地理位置解析),失败不阻断连接
|
||||||
|
try {
|
||||||
|
const https = require('https');
|
||||||
|
this._externalIp = await new Promise((resolve) => {
|
||||||
|
const req = https.get('https://api.ipify.org?format=json', { timeout: 5000 }, (res) => {
|
||||||
|
let body = '';
|
||||||
|
res.on('data', d => { body += d; });
|
||||||
|
res.on('end', () => {
|
||||||
|
try { resolve(JSON.parse(body).ip || null); } catch { resolve(null); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
req.on('error', () => resolve(null));
|
||||||
|
req.on('timeout', () => { req.destroy(); resolve(null); });
|
||||||
|
});
|
||||||
|
if (this._externalIp) log.info('clawd', `外网 IP: ${this._externalIp}`);
|
||||||
|
} catch (e) {
|
||||||
|
log.warn('clawd', '外网 IP 查询失败:', e.message);
|
||||||
|
this._externalIp = null;
|
||||||
|
}
|
||||||
|
|
||||||
this._connect();
|
this._connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,6 +288,8 @@ 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,
|
||||||
|
local_ip: getLocalIps(),
|
||||||
|
external_ip: this._externalIp ?? null,
|
||||||
...this._dashInfo,
|
...this._dashInfo,
|
||||||
};
|
};
|
||||||
this._send(msg);
|
this._send(msg);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require('child_process');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
const log = require('./logger');
|
const log = require('./logger');
|
||||||
|
|
||||||
const AP_SSID_PREFIX = 'ClawBox-';
|
const AP_SSID_PREFIX = 'ClawBox-';
|
||||||
@@ -223,6 +224,29 @@ function isWifiStaConnected() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取本机所有非回环 IPv4 地址,逗号拼接返回
|
||||||
|
* 例:'192.168.1.100' 或 '192.168.1.100,10.0.0.5'
|
||||||
|
*/
|
||||||
|
function getLocalIps() {
|
||||||
|
try {
|
||||||
|
const ifaces = os.networkInterfaces();
|
||||||
|
const ips = [];
|
||||||
|
for (const [name, addrs] of Object.entries(ifaces)) {
|
||||||
|
if (!addrs) continue;
|
||||||
|
for (const addr of addrs) {
|
||||||
|
if (addr.family === 'IPv4' && !addr.internal) {
|
||||||
|
ips.push(addr.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ips.length > 0 ? ips.join(',') : null;
|
||||||
|
} catch (e) {
|
||||||
|
log.warn('network', '获取本机 IP 失败:', e.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
hasInternet,
|
hasInternet,
|
||||||
hasWiredCarrier,
|
hasWiredCarrier,
|
||||||
@@ -234,4 +258,5 @@ module.exports = {
|
|||||||
startAP,
|
startAP,
|
||||||
stopAP,
|
stopAP,
|
||||||
AP_IP,
|
AP_IP,
|
||||||
|
getLocalIps,
|
||||||
};
|
};
|
||||||
|
|||||||
148
package-lock.json
generated
Normal file
148
package-lock.json
generated
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
{
|
||||||
|
"name": "clawd",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "clawd",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ssh2": "^1.17.0",
|
||||||
|
"systeminformation": "^5.25.0",
|
||||||
|
"ws": "^8.18.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"clawd": "bin/clawd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/asn1": {
|
||||||
|
"version": "0.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
||||||
|
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": "~2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bcrypt-pbkdf": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"tweetnacl": "^0.14.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buildcheck": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz",
|
||||||
|
"integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cpu-features": {
|
||||||
|
"version": "0.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",
|
||||||
|
"integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"buildcheck": "~0.0.6",
|
||||||
|
"nan": "^2.19.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nan": {
|
||||||
|
"version": "2.26.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.26.1.tgz",
|
||||||
|
"integrity": "sha512-vodKprLlmaKmraa9E/TxHQwpH4eKYTJbLdeQE49pb9GOmrLs68zESjJu0LQOz1W6JwJmftOWD5Ls4dpd/elQtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"node_modules/safer-buffer": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ssh2": {
|
||||||
|
"version": "1.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.17.0.tgz",
|
||||||
|
"integrity": "sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"asn1": "^0.2.6",
|
||||||
|
"bcrypt-pbkdf": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.16.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"cpu-features": "~0.0.10",
|
||||||
|
"nan": "^2.23.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/systeminformation": {
|
||||||
|
"version": "5.31.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.4.tgz",
|
||||||
|
"integrity": "sha512-lZppDyQx91VdS5zJvAyGkmwe+Mq6xY978BDUG2wRkWE+jkmUF5ti8cvOovFQoN5bvSFKCXVkyKEaU5ec3SJiRg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"os": [
|
||||||
|
"darwin",
|
||||||
|
"linux",
|
||||||
|
"win32",
|
||||||
|
"freebsd",
|
||||||
|
"openbsd",
|
||||||
|
"netbsd",
|
||||||
|
"sunos",
|
||||||
|
"android"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"systeminformation": "lib/cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "Buy me a coffee",
|
||||||
|
"url": "https://www.buymeacoffee.com/systeminfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tweetnacl": {
|
||||||
|
"version": "0.14.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||||
|
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
||||||
|
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
package.json
12
package.json
@@ -9,14 +9,20 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node bin/clawd.js"
|
"start": "node bin/clawd.js"
|
||||||
},
|
},
|
||||||
"keywords": ["claw", "iot", "websocket", "daemon"],
|
"keywords": [
|
||||||
|
"claw",
|
||||||
|
"iot",
|
||||||
|
"websocket",
|
||||||
|
"daemon"
|
||||||
|
],
|
||||||
"author": "stswangzhiping",
|
"author": "stswangzhiping",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ws": "^8.18.0",
|
"ssh2": "^1.17.0",
|
||||||
"systeminformation": "^5.25.0"
|
"systeminformation": "^5.25.0",
|
||||||
|
"ws": "^8.18.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user