claw-subagent-service 0.0.37 → 0.0.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/service/worker.js +76 -16
package/package.json
CHANGED
package/service/worker.js
CHANGED
|
@@ -3,6 +3,7 @@ const fs = require('fs');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const os = require('os');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
|
+
const axios = require('axios');
|
|
6
7
|
const { createLogger } = require('./logger');
|
|
7
8
|
const { RongCloudClient, MessageHandler, ensurePluginsAllow } = require('./rongcloud');
|
|
8
9
|
const { RongyunMessageHandler } = require('./modules/rongyun-message-handler');
|
|
@@ -198,6 +199,53 @@ rongcloudConfig = loadRongCloudConfig();
|
|
|
198
199
|
let rongcloudClient = null;
|
|
199
200
|
let messageHandler = null;
|
|
200
201
|
|
|
202
|
+
/**
|
|
203
|
+
* 向服务端刷新融云 token
|
|
204
|
+
*/
|
|
205
|
+
async function refreshRongCloudToken() {
|
|
206
|
+
const nodeId = rongcloudConfig?.accountId;
|
|
207
|
+
if (!nodeId) {
|
|
208
|
+
log.error('[WORKER] 无法刷新 token: 缺少 nodeId');
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const serverUrl = process.env.DM_SERVER_URL || 'https://newsradar.dreamdt.cn/im';
|
|
213
|
+
try {
|
|
214
|
+
log.info(`[WORKER] 正在向服务端刷新 token, nodeId=${nodeId}`);
|
|
215
|
+
const resp = await axios.get(`${serverUrl}/api/claw/token/${nodeId}`, { timeout: 15000 });
|
|
216
|
+
if (resp.data?.code === 200) {
|
|
217
|
+
const newToken = resp.data.data?.token || resp.data.token || '';
|
|
218
|
+
if (!newToken) {
|
|
219
|
+
log.error('[WORKER] 服务端返回了空 token');
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
log.info('[WORKER] token 刷新成功');
|
|
223
|
+
|
|
224
|
+
// 更新内存配置
|
|
225
|
+
rongcloudConfig.token = newToken;
|
|
226
|
+
|
|
227
|
+
// 保存到 config.json
|
|
228
|
+
try {
|
|
229
|
+
if (fs.existsSync(clawBridgeConfigPath)) {
|
|
230
|
+
const clawConfig = JSON.parse(fs.readFileSync(clawBridgeConfigPath, 'utf8'));
|
|
231
|
+
clawConfig.token = newToken;
|
|
232
|
+
clawConfig.expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1000; // 7天
|
|
233
|
+
fs.writeFileSync(clawBridgeConfigPath, JSON.stringify(clawConfig, null, 2));
|
|
234
|
+
log.info('[WORKER] 新 token 已保存到 config.json');
|
|
235
|
+
}
|
|
236
|
+
} catch (err) {
|
|
237
|
+
log.error(`[WORKER] 保存新 token 失败: ${err.message}`);
|
|
238
|
+
}
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
log.error(`[WORKER] 刷新 token 失败: ${resp.data?.message || '未知错误'}`);
|
|
242
|
+
return false;
|
|
243
|
+
} catch (err) {
|
|
244
|
+
log.error(`[WORKER] 刷新 token 异常: ${err.message}`);
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
201
249
|
async function initRongCloud() {
|
|
202
250
|
if (!rongcloudConfig) return;
|
|
203
251
|
|
|
@@ -233,22 +281,22 @@ async function initRongCloud() {
|
|
|
233
281
|
|
|
234
282
|
// 包装 MessageHandler.handleMessage 以处理结构化消息
|
|
235
283
|
const originalHandleMessage = messageHandler.handleMessage.bind(messageHandler);
|
|
236
|
-
|
|
284
|
+
|
|
237
285
|
messageHandler.handleMessage = async (msg) => {
|
|
238
286
|
// 检查是否是结构化消息
|
|
239
287
|
if (msg.content && typeof msg.content === 'string') {
|
|
240
288
|
try {
|
|
241
289
|
const parsed = JSON.parse(msg.content);
|
|
242
|
-
|
|
290
|
+
|
|
243
291
|
if (parsed.msg_type) {
|
|
244
292
|
// 这是结构化消息,使用 RongyunMessageHandler 处理
|
|
245
293
|
log.info(`[WORKER] 收到结构化消息: type=${parsed.msg_type}, from=${parsed.source_im_id || msg.senderUserId}`);
|
|
246
|
-
|
|
294
|
+
|
|
247
295
|
// 忽略自己发送的消息
|
|
248
296
|
if (parsed.source_im_id === rongcloudConfig.accountId) {
|
|
249
297
|
return;
|
|
250
298
|
}
|
|
251
|
-
|
|
299
|
+
|
|
252
300
|
// Timestamp 校验(5分钟有效期)
|
|
253
301
|
const msgTimestamp = parsed.timestamp;
|
|
254
302
|
if (msgTimestamp) {
|
|
@@ -262,7 +310,7 @@ async function initRongCloud() {
|
|
|
262
310
|
return;
|
|
263
311
|
}
|
|
264
312
|
}
|
|
265
|
-
|
|
313
|
+
|
|
266
314
|
// 解析 content 字段(它本身可能是 JSON 字符串)
|
|
267
315
|
let innerContent = parsed.content;
|
|
268
316
|
if (typeof innerContent === 'string') {
|
|
@@ -272,7 +320,7 @@ async function initRongCloud() {
|
|
|
272
320
|
// 保持字符串
|
|
273
321
|
}
|
|
274
322
|
}
|
|
275
|
-
|
|
323
|
+
|
|
276
324
|
// 构建消息数据
|
|
277
325
|
// 注意:后端发送的 command 消息中,command/command_id/request_id 在 content 字段内
|
|
278
326
|
// 保留原始 content(用户消息内容),同时展开其他字段
|
|
@@ -284,7 +332,7 @@ async function initRongCloud() {
|
|
|
284
332
|
targetId: msg.targetId,
|
|
285
333
|
conversationType: msg.conversationType,
|
|
286
334
|
};
|
|
287
|
-
|
|
335
|
+
|
|
288
336
|
// 使用 RongyunMessageHandler 处理
|
|
289
337
|
try {
|
|
290
338
|
await rongyunMessageHandler.handle(messageData);
|
|
@@ -297,18 +345,30 @@ async function initRongCloud() {
|
|
|
297
345
|
// 不是 JSON,是普通消息,继续传给原始 handler
|
|
298
346
|
}
|
|
299
347
|
}
|
|
300
|
-
|
|
348
|
+
|
|
301
349
|
// 调用原始的 handleMessage(处理普通消息)
|
|
302
350
|
return originalHandleMessage(msg);
|
|
303
351
|
};
|
|
304
|
-
|
|
352
|
+
|
|
305
353
|
// 添加调试日志:确认替换后的方法
|
|
306
354
|
log.info('[WORKER-DEBUG] 替换后 messageHandler.handleMessage 类型: ' + typeof messageHandler.handleMessage);
|
|
307
355
|
|
|
308
|
-
|
|
356
|
+
let connected = await rongcloudClient.connect(messageHandler);
|
|
357
|
+
|
|
358
|
+
// 连接失败时尝试刷新 token 并重试一次
|
|
359
|
+
if (!connected) {
|
|
360
|
+
log.warn('[WORKER] 首次融云连接失败,尝试刷新 token...');
|
|
361
|
+
const refreshed = await refreshRongCloudToken();
|
|
362
|
+
if (refreshed) {
|
|
363
|
+
// 使用新 token 重新创建客户端并连接
|
|
364
|
+
rongcloudClient = new RongCloudClient(rongcloudConfig, log);
|
|
365
|
+
connected = await rongcloudClient.connect(messageHandler);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
309
369
|
if (connected) {
|
|
310
370
|
log.info('[WORKER] 融云连接成功');
|
|
311
|
-
|
|
371
|
+
|
|
312
372
|
// 发送 CLIENT_CONNECTED
|
|
313
373
|
try {
|
|
314
374
|
await messageSender.sendClientConnected();
|
|
@@ -316,21 +376,21 @@ async function initRongCloud() {
|
|
|
316
376
|
} catch (err) {
|
|
317
377
|
log.error(`[WORKER] 发送 CLIENT_CONNECTED 失败: ${err.message}`);
|
|
318
378
|
}
|
|
319
|
-
|
|
379
|
+
|
|
320
380
|
// 启动心跳管理器
|
|
321
381
|
const heartbeatManager = new HeartbeatManager(rongcloudClient, rongcloudConfig, log);
|
|
322
382
|
heartbeatManager.start(getMacAddress, getOpenClawStatus);
|
|
323
|
-
|
|
383
|
+
|
|
324
384
|
// 启动仪表盘上报
|
|
325
385
|
const dashboardReporter = new DashboardReporter(rongcloudClient, rongcloudConfig, log);
|
|
326
386
|
dashboardReporter.start(getMacAddress);
|
|
327
|
-
|
|
387
|
+
|
|
328
388
|
// 保存引用以便关闭时停止
|
|
329
389
|
global.heartbeatManager = heartbeatManager;
|
|
330
390
|
global.dashboardReporter = dashboardReporter;
|
|
331
|
-
|
|
391
|
+
|
|
332
392
|
} else {
|
|
333
|
-
log.error('[WORKER]
|
|
393
|
+
log.error('[WORKER] 融云连接失败,token 刷新后仍无法连接');
|
|
334
394
|
}
|
|
335
395
|
}
|
|
336
396
|
|