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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/service/worker.js +76 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.37",
3
+ "version": "0.0.38",
4
4
  "description": "虾说静态服务",
5
5
  "main": "cli.js",
6
6
  "bin": {
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
- const connected = await rongcloudClient.connect(messageHandler);
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