wechaty-web-panel 1.6.118 → 1.6.120

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.
@@ -9,7 +9,8 @@ import { getPuppetEol, isWindowsPlatform } from "../const/puppet-type.js";
9
9
  import dayjs from "dayjs";
10
10
  import { addHistory } from "../db/chatHistory.js";
11
11
  import { getPuppetInfo } from "../db/puppetDb.js";
12
- import * as URL from 'url';
12
+ import url from 'url';
13
+ import path from 'path';
13
14
  async function formatContent(text) {
14
15
  text = text.replaceAll('\\n', '\n');
15
16
  const isWin = await isWindowsPlatform();
@@ -229,6 +230,7 @@ function getFileNameFromUrl(fileUrl) {
229
230
  return decodeURIComponent(path.basename(urlObj.pathname));
230
231
  }
231
232
  catch (err) {
233
+ console.error('获取文件名失败', err);
232
234
  return null;
233
235
  }
234
236
  }
@@ -269,7 +271,7 @@ async function roomSay(room, contact, msg, noNeedAt = false) {
269
271
  else if (msg.type === 2 && msg.url) {
270
272
  // url文件
271
273
  const name = getFileNameFromUrl(msg.url);
272
- let obj = FileBox.fromUrl(msg.url, name);
274
+ let obj = FileBox.fromUrl(encodeURI(msg.url), name);
273
275
  if (obj.mediaType === 'image/webp') {
274
276
  obj = FileBox.fromUrl(`${AIBOTK_OUTAPI}/convert?url=${msg.url}`);
275
277
  }
@@ -363,7 +365,7 @@ async function contactSay(contact, msg, isRoom = false) {
363
365
  else if (msg.type === 2 && msg.url) {
364
366
  // url文件
365
367
  const name = getFileNameFromUrl(msg.url);
366
- let obj = FileBox.fromUrl(msg.url, name);
368
+ let obj = FileBox.fromUrl(encodeURI(msg.url), name);
367
369
  await obj.ready();
368
370
  if (obj.mediaType === 'image/webp') {
369
371
  obj = FileBox.fromUrl(`${AIBOTK_OUTAPI}/convert?url=${msg.url}`, getFileNameFromUrl(msg.url));
@@ -18,6 +18,7 @@ async function onRecordMessage(msg) {
18
18
  const room = msg.room(); // 是否为群消息
19
19
  const roomName = room ? await room.topic() : '';
20
20
  const msgSelf = msg.self(); // 是否自己发给自己的消息
21
+ const msgId = msg.id;
21
22
  const type = msg.type();
22
23
  const timestamp = msg.timestamp || dayjs().unix();
23
24
  const robotInfo = this.currentUser;
@@ -75,7 +76,7 @@ async function onRecordMessage(msg) {
75
76
  baseMsg.type = '自定义表情';
76
77
  const emoticonFileBox = await msg.toFileBox();
77
78
  const emoticonBuffer = await emoticonFileBox.toBuffer();
78
- const emoticonUrl = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${emoticonFileBox.name}`, emoticonBuffer);
79
+ const emoticonUrl = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${msgId}_${dayjs().valueOf()}_${emoticonFileBox.name}`, emoticonBuffer);
79
80
  baseMsg.url = emoticonUrl;
80
81
  break;
81
82
  case this.Message.Type.Text:
@@ -114,14 +115,14 @@ async function onRecordMessage(msg) {
114
115
  const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif');
115
116
  baseMsg.type = isImage ? '图片' : '文件';
116
117
  const buffer = await attachFileBox.toBuffer();
117
- const url = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${attachFileBox.name}`, buffer);
118
+ const url = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${msgId}_${dayjs().valueOf()}_${attachFileBox.name}`, buffer);
118
119
  baseMsg.url = url;
119
120
  break;
120
121
  case this.Message.Type.Audio:
121
122
  baseMsg.type = '语音';
122
123
  const audioFileBox = await msg.toFileBox();
123
124
  const audioBuffer = await audioFileBox.toBuffer();
124
- const audioUrl = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${audioFileBox.name}`, audioBuffer);
125
+ const audioUrl = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${msgId}_${dayjs().valueOf()}_${audioFileBox.name}`, audioBuffer);
125
126
  baseMsg.url = audioUrl;
126
127
  break;
127
128
  case this.Message.Type.ChatHistory:
@@ -170,7 +171,7 @@ async function formatHistory(that, history, conversationRecord) {
170
171
  const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif');
171
172
  baseMsg.type = isImage ? '图片' : '文件';
172
173
  const buffer = await attachFileBox.toBuffer();
173
- const url = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${attachFileBox.name}`, buffer);
174
+ const url = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${msgId}_${dayjs().valueOf()}_${attachFileBox.name}`, buffer);
174
175
  contents.push(`()[${url}]`);
175
176
  }
176
177
  else if (history.type === that.Message.Type.ChatHistory) {
@@ -0,0 +1,397 @@
1
+ import { allConfig } from '../db/configDb.js';
2
+ import { uploadOssFile } from "../lib/oss.js";
3
+ import dayjs from "dayjs";
4
+ import { getPuppetInfo } from "../db/puppetDb.js";
5
+ import path from "path";
6
+ import axios from "axios";
7
+ import { getClawMqttConfig } from "../proxy/aibotk.js";
8
+ import * as mqtt from 'mqtt';
9
+ import { randomRange } from '../lib/index.js';
10
+ import { v4 as uuidv4 } from 'uuid';
11
+ let clawMqttClient = null;
12
+ // allowScope: 1 所有群和好友 2 所有群 3 所有好友 4 部分群和部分好友
13
+ // allowFriends: [{label: '昵称', value: 'wixd'}] 只需要 checkId即可
14
+ async function checkAllow(clawConfig, contactId, roomId) {
15
+ const { allowScope = 1, allowFriends = [], allowRooms = [] } = clawConfig;
16
+ if (allowScope === 1) {
17
+ // 所有群和好友
18
+ return true;
19
+ }
20
+ else if (allowScope === 2) {
21
+ // 仅所有群
22
+ return !!room;
23
+ }
24
+ else if (allowScope === 3) {
25
+ // 仅所有好友
26
+ return !room;
27
+ }
28
+ else if (allowScope === 4) {
29
+ // 部分群和部分好友
30
+ if (room) {
31
+ return allowRooms.some(r => r.value === roomId);
32
+ }
33
+ else {
34
+ return allowFriends.some(f => f.value === contactId);
35
+ }
36
+ }
37
+ return false;
38
+ }
39
+ async function onClawMessage(msg) {
40
+ try {
41
+ const puppetInfo = await getPuppetInfo();
42
+ const config = await allConfig();
43
+ const clawConfig = config?.clawConfig || { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: false, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} };
44
+ const { role } = config && config.userInfo || { role: 'default' };
45
+ if (role !== 'vip' || !clawConfig?.open)
46
+ return;
47
+ if (!clawMqttClient || !clawMqttClient.connected)
48
+ return;
49
+ const contact = msg.talker(); // 发消息人
50
+ const contactName = contact && contact.name() || ''; // 发消息人昵称
51
+ const contactAlias = contact && await contact.alias();
52
+ const room = msg.room(); // 是否为群消息
53
+ const roomName = room ? await room.topic() : '';
54
+ const msgSelf = msg.self(); // 是否自己发给自己的消息
55
+ const type = msg.type();
56
+ const timestamp = msg.timestamp || dayjs().unix();
57
+ const robotInfo = this.currentUser;
58
+ // 权限校验
59
+ const allowed = await checkAllow(clawConfig, contact.id, room ? room.id : null);
60
+ if (!allowed)
61
+ return;
62
+ let isOfficial = null;
63
+ try {
64
+ isOfficial = contact && contact.type() === this.Contact.Type.Official;
65
+ }
66
+ catch (e) {
67
+ console.log('check isOfficial error, don`t worry, no effect :', e);
68
+ isOfficial = false;
69
+ }
70
+ const userWeixin = contact && contact.weixin() || '';
71
+ if (isOfficial)
72
+ return;
73
+ console.log('msg', msg);
74
+ const baseMsg = {
75
+ conversionId: room ? room.id : contact.id,
76
+ conversionName: room ? roomName : contactName,
77
+ isRoom: !!room,
78
+ chatName: contactName,
79
+ chatId: contact.id,
80
+ chatAlias: contactAlias,
81
+ chatUserWeixin: userWeixin,
82
+ isMyself: !!msgSelf,
83
+ time: timestamp.length > 10 ? parseInt(timestamp / 1000) : timestamp,
84
+ msgId: msg.id,
85
+ };
86
+ switch (type) {
87
+ case this.Message.Type.Channel:
88
+ baseMsg.type = '视频号';
89
+ const channelInfo = await msg.toChannel();
90
+ baseMsg.content = `【视频号消息】\n视频号昵称:${channelInfo.nickname()}\n视频号简介:${channelInfo.desc}\n视频号链接:${channelInfo.url}`;
91
+ baseMsg.mediaInfo = {
92
+ nickname: channelInfo.nickname(),
93
+ coverUrl: channelInfo.coverUrl(),
94
+ avatar: channelInfo.avatar(),
95
+ desc: channelInfo.desc(),
96
+ url: channelInfo.url(),
97
+ objectId: channelInfo.objectId(),
98
+ objectNonceId: channelInfo.objectNonceId()
99
+ };
100
+ break;
101
+ case this.Message.Type.Contact:
102
+ baseMsg.type = '名片';
103
+ const contactInfo = await msg.toContact();
104
+ baseMsg.content = "【名片消息】\n" + `联系人昵称:${contactInfo.name()}\n联系人ID:${contactInfo.id}`;
105
+ baseMsg.mediaInfo = {
106
+ name: contactInfo.name(),
107
+ avatar: contactInfo.payload.avatar || '',
108
+ wxid: contactInfo.id,
109
+ };
110
+ break;
111
+ case this.Message.Type.Text:
112
+ baseMsg.type = '文字';
113
+ baseMsg.content = msg.text().trim();
114
+ break;
115
+ case this.Message.Type.Url:
116
+ const urlLink = await msg.toUrlLink();
117
+ baseMsg.type = 'h5链接';
118
+ baseMsg.content = `【链接消息】\n链接标题:${urlLink.title()}\n链接描述:${urlLink.description()}\n链接地址:${urlLink.url()}`;
119
+ baseMsg.mediaInfo = {
120
+ url: urlLink.url(),
121
+ description: urlLink.description(),
122
+ imageUrl: urlLink.thumbnailUrl(),
123
+ title: urlLink.title(),
124
+ };
125
+ break;
126
+ case this.Message.Type.Attachment:
127
+ case this.Message.Type.Image:
128
+ case this.Message.Type.Video:
129
+ const attachFileBox = await msg.toFileBox();
130
+ if (attachFileBox.remoteUrl) {
131
+ // 直接使用远程链接,无需上传
132
+ baseMsg.url = attachFileBox.remoteUrl;
133
+ baseMsg.content = `【${type === this.Message.Type.Image ? '图片' : type === this.Message.Type.Video ? '视频' : '文件'}消息】\n文件名:${attachFileBox.name}\n下载链接:${attachFileBox.remoteUrl}`;
134
+ break;
135
+ }
136
+ const fileExtname = path.extname(attachFileBox.name);
137
+ const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif');
138
+ baseMsg.type = isImage ? '图片' : '文件';
139
+ const buffer = await attachFileBox.toBuffer();
140
+ if (clawConfig?.ossConfig.type) {
141
+ const url = await uploadOssFile(`${clawConfig?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${attachFileBox.name}`, buffer, clawConfig?.ossConfig);
142
+ baseMsg.url = url;
143
+ baseMsg.content = `【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n下载链接:${url}`;
144
+ }
145
+ else {
146
+ // 没有配置OSS,使用base64
147
+ const base64 = attachFileBox.toBase64();
148
+ baseMsg.url = base64;
149
+ baseMsg.content = `【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n文件大小:${buffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`;
150
+ }
151
+ break;
152
+ case this.Message.Type.Audio:
153
+ if (puppetInfo.puppetType.includes('PuppetService') && !msg.text().startsWith('@')) {
154
+ baseMsg.type = '文字';
155
+ baseMsg.content = msg.text().trim();
156
+ break;
157
+ }
158
+ baseMsg.type = '语音';
159
+ const audioFileBox = await msg.toFileBox();
160
+ const audioBuffer = await audioFileBox.toBuffer();
161
+ if (clawConfig?.ossConfig.type) {
162
+ const audioUrl = await uploadOssFile(`${clawConfig?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${audioFileBox.name}`, audioBuffer, clawConfig?.ossConfig);
163
+ baseMsg.url = audioUrl;
164
+ baseMsg.content = `【语音消息】\n文件名:${audioFileBox.name}\n下载链接:${audioUrl}`;
165
+ }
166
+ else {
167
+ // 没有配置OSS,使用base64
168
+ const audioBase64 = audioFileBox.toBase64();
169
+ baseMsg.url = audioBase64;
170
+ baseMsg.content = `【语音消息】\n文件名:${audioFileBox.name}\n文件大小:${audioBuffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`;
171
+ }
172
+ break;
173
+ case this.Message.Type.ChatHistory:
174
+ const historys = await msg.toChatHistory();
175
+ const contents = await formatHistory(this, historys.payload, clawConfig);
176
+ baseMsg.type = '历史记录';
177
+ baseMsg.content = contents;
178
+ break;
179
+ case this.Message.Type.Location:
180
+ const location = await msg.toLocation();
181
+ const locationParse = `【位置解析结果】\n纬度:${locationInfo?.payload?.latitude}\n经度:${locationInfo?.payload?.longitude}\n地点名:${locationInfo?.payload?.name}\n城市:${locationInfo?.payload?.city || ''}\n具体地址:${locationInfo?.payload?.address}\nPoiId:${locationInfo?.payload?.poiId || ''}`;
182
+ baseMsg.type = '位置';
183
+ baseMsg.content = locationParse;
184
+ break;
185
+ default:
186
+ break;
187
+ }
188
+ console.log('baseMsg', baseMsg);
189
+ const { forwardAllMsg, forwardIncludeKeywordsMsg = [], forwardMediaMsg } = clawConfig;
190
+ if (baseMsg.type === '文字') {
191
+ if (!forwardAllMsg) {
192
+ const hit = forwardIncludeKeywordsMsg.some(kw => baseMsg.content && baseMsg.content.includes(kw));
193
+ if (!hit)
194
+ return;
195
+ }
196
+ }
197
+ else {
198
+ if (!forwardMediaMsg)
199
+ return;
200
+ }
201
+ publishClawMessage(baseMsg, robotInfo);
202
+ }
203
+ catch (e) {
204
+ console.log('claw 消息处理失败', e);
205
+ }
206
+ }
207
+ async function formatHistory(that, history, clawConfig) {
208
+ const contents = [];
209
+ for (const history of historys) {
210
+ if (history.type === that.Message.Type.Text) {
211
+ contents.push(history.message);
212
+ }
213
+ else if (history.type === that.Message.Type.Recalled || history.type === that.Message.Type.Attachment || history.type === that.Message.Type.Image || history.type === that.Message.Type.Video) {
214
+ const attachFileBox = await history.message.toFileBox();
215
+ const fileExtname = path.extname(attachFileBox.name);
216
+ const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif');
217
+ baseMsg.type = isImage ? '图片' : '文件';
218
+ if (attachFileBox.remoteUrl) {
219
+ // 直接使用远程链接,无需上传
220
+ const url = attachFileBox.remoteUrl;
221
+ contents.push(`【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n下载链接:${url}`);
222
+ continue;
223
+ }
224
+ const buffer = await attachFileBox.toBuffer();
225
+ if (!clawConfig?.ossConfig.type) {
226
+ const base64 = attachFileBox.toBase64();
227
+ contents.push(`【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n文件大小:${buffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`);
228
+ continue;
229
+ }
230
+ const url = await uploadOssFile(`${clawConfig?.ossConfig?.custom_path || ''}${dayjs().valueOf()}_${attachFileBox.name}`, buffer, clawConfig?.ossConfig);
231
+ contents.push(`【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n下载链接:${url}`);
232
+ }
233
+ else if (history.type === that.Message.Type.ChatHistory) {
234
+ const res = await formatHistory(that, history.message, clawConfig);
235
+ contents.push(res);
236
+ }
237
+ }
238
+ return contents.join('\n');
239
+ }
240
+ /**
241
+ * 将消息通过 MQTT 发布到 reciveTopic
242
+ */
243
+ function publishClawMessage(baseMsg, robotInfo) {
244
+ try {
245
+ if (!clawMqttClient || !clawMqttClient.connected)
246
+ return;
247
+ const payload = {
248
+ content: baseMsg.content || '',
249
+ robotId: robotInfo.id,
250
+ senderId: baseMsg.chatId,
251
+ senderName: baseMsg.chatName,
252
+ isGroup: baseMsg.isRoom,
253
+ groupId: baseMsg.isRoom ? baseMsg.conversionId : undefined,
254
+ groupName: baseMsg.isRoom ? baseMsg.conversionName : undefined,
255
+ timestamp: baseMsg.time * 1000, // 转换为 11 位毫秒时间戳
256
+ messageId: baseMsg.msgId,
257
+ type: baseMsg.type,
258
+ mediaInfo: baseMsg.mediaInfo,
259
+ url: baseMsg.url,
260
+ };
261
+ console.log('发布 Claw MQTT 消息', payload);
262
+ clawMqttClient.publish(clawMqttClient._clawReciveTopic, JSON.stringify(payload), { qos: 1 });
263
+ }
264
+ catch (e) {
265
+ console.log('发布 Claw MQTT 消息失败', e);
266
+ }
267
+ }
268
+ /**
269
+ * 初始化 Claw MQTT 连接
270
+ * 1. 连接 MQTT,将入站消息发布到 reciveTopic
271
+ * 2. 订阅 sendTopic,收到消息后通过微信发送
272
+ */
273
+ async function initClawMqtt(that) {
274
+ try {
275
+ const config = await allConfig();
276
+ const clawConfig = config?.clawConfig || { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: false, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} };
277
+ const { role } = config && config.userInfo || { role: 'default' };
278
+ if (role !== 'vip' || !clawConfig?.open)
279
+ return;
280
+ if (clawMqttClient && clawMqttClient.connected)
281
+ return;
282
+ const mqttConfig = await getClawMqttConfig();
283
+ if (!mqttConfig)
284
+ return;
285
+ const { port, host, username, password, clientId, reciveTopic, sendTopic } = mqttConfig;
286
+ if (!host)
287
+ return;
288
+ clawMqttClient = mqtt.connect(`mqtt://${host}:${port}`, {
289
+ username,
290
+ password,
291
+ clientId: clientId + randomRange(1, 10000),
292
+ });
293
+ // 在 client 上挂载 topic 便于 publishClawMessage 使用
294
+ clawMqttClient._clawReciveTopic = reciveTopic;
295
+ clawMqttClient.on('connect', function () {
296
+ console.log('Claw MQTT 连接成功');
297
+ clawMqttClient.subscribe(sendTopic, function (err) {
298
+ if (err) {
299
+ console.log('Claw MQTT 订阅失败', err);
300
+ }
301
+ else {
302
+ console.log(`Claw MQTT 订阅成功: ${sendTopic}`);
303
+ }
304
+ });
305
+ });
306
+ clawMqttClient.on('reconnect', function () {
307
+ console.log('Claw MQTT 重连中...');
308
+ });
309
+ clawMqttClient.on('error', function (e) {
310
+ console.log('Claw MQTT 错误', e);
311
+ });
312
+ clawMqttClient.on('message', async function (topic, message) {
313
+ try {
314
+ if (topic !== sendTopic)
315
+ return;
316
+ const content = JSON.parse(message.toString());
317
+ /**
318
+ * 收到消息格式:
319
+ * {
320
+ * isGroup: false,
321
+ * groupId: 'roomid_xxx',
322
+ * contactId: 'wxid_xxx',
323
+ * mentionIds: ['wxid_xxx'],
324
+ * messages: [
325
+ * { type: 1, content: '文本内容' },
326
+ * { type: 2, url: 'http link' },
327
+ * ]
328
+ * }
329
+ */
330
+ const { isGroup, groupId, contactId, mentionIds = [], messages = [] } = content;
331
+ if (isGroup && groupId) {
332
+ const room = await that.Room.find({ id: groupId });
333
+ if (!room) {
334
+ console.log(`Claw MQTT: 查找不到群 ${groupId}`);
335
+ return;
336
+ }
337
+ // 解析 @ 联系人
338
+ let atContacts = [];
339
+ for (const wxid of mentionIds) {
340
+ const c = await that.Contact.find({ id: wxid });
341
+ if (c)
342
+ atContacts.push(c);
343
+ }
344
+ for (const msg of messages) {
345
+ if (msg.type === 1) {
346
+ // 文字消息
347
+ if (atContacts.length > 0) {
348
+ await room.say(msg.content, ...atContacts);
349
+ }
350
+ else {
351
+ await room.say(msg.content);
352
+ }
353
+ }
354
+ else if (msg.type === 2) {
355
+ // 图片消息
356
+ const { FileBox } = await import('file-box');
357
+ const fileBox = FileBox.fromUrl(msg.url);
358
+ await room.say(fileBox);
359
+ }
360
+ }
361
+ }
362
+ else if (!isGroup && contactId) {
363
+ const contact = await that.Contact.find({ id: contactId });
364
+ if (!contact) {
365
+ console.log(`Claw MQTT: 查找不到联系人 ${contactId}`);
366
+ return;
367
+ }
368
+ for (const msg of messages) {
369
+ if (msg.type === 1) {
370
+ await contact.say(msg.content);
371
+ }
372
+ else if (msg.type === 2) {
373
+ const { FileBox } = await import('file-box');
374
+ const fileBox = FileBox.fromUrl(msg.url);
375
+ await contact.say(fileBox);
376
+ }
377
+ }
378
+ }
379
+ }
380
+ catch (e) {
381
+ console.log('Claw MQTT 处理消息失败', e);
382
+ }
383
+ });
384
+ }
385
+ catch (e) {
386
+ console.log('Claw MQTT 初始化失败', e);
387
+ }
388
+ }
389
+ function closeClawMqtt() {
390
+ if (clawMqttClient && clawMqttClient.connected) {
391
+ clawMqttClient.end();
392
+ clawMqttClient = null;
393
+ }
394
+ }
395
+ export default onClawMessage;
396
+ export { initClawMqtt, closeClawMqtt };
397
+ //# sourceMappingURL=on-claw-message.js.map
@@ -5,6 +5,7 @@ import { allConfig } from '../db/configDb.js';
5
5
  import { updatePuppetConfig } from "../db/puppetDb.js";
6
6
  import { PUPPET_MAP } from '../const/puppet-type.js';
7
7
  import { packageJson } from '../package-json.js';
8
+ import { initClawMqtt } from './on-claw-message.js';
8
9
  /**
9
10
  * 登录成功监听事件
10
11
  * @param {*} user 登录用户
@@ -49,6 +50,7 @@ async function onLogin(user) {
49
50
  }
50
51
  await sendRobotInfo(avatarUrl, user.name(), userInfo.robotId); // 更新用户头像
51
52
  await initMqtt(this); // 初始化mqtt任务
53
+ await initClawMqtt(this); // 初始化爪子mqtt
52
54
  }
53
55
  catch (e) {
54
56
  console.log('登录后初始化失败', e);
@@ -53,7 +53,7 @@ async function dispatchFriendFilterByMsgType(that, msg) {
53
53
  const userAlias = contact && (await contact.alias()) || '';
54
54
  let isOfficial = null;
55
55
  try {
56
- isOfficial = contact && contact.type() === this.Contact.Type.Official;
56
+ isOfficial = contact && contact.type() === that.Contact.Type.Official;
57
57
  }
58
58
  catch (e) {
59
59
  console.log('check isOfficial error, don`t worry, no effect', e);
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import onRoomleave from './handlers/on-roomleave.js';
14
14
  import onVerifyCode from './handlers/on-verifycode.js';
15
15
  import onRecordMessage from './handlers/on-record-message.js';
16
16
  import onCallbackMessage from "./handlers/on-callback-message.js";
17
+ import onClawMessage from "./handlers/on-claw-message.js";
17
18
  import dayjs from "dayjs";
18
19
  const originalConsoleLog = console.log;
19
20
  // 重写 console.log 方法
@@ -83,5 +84,10 @@ function WechatyMessageCallBackPlugin() {
83
84
  bot.on('message', onCallbackMessage);
84
85
  };
85
86
  }
86
- export { WechatyWebPanelPlugin, WechatyMessageRecordPlugin, WechatyMessageCallBackPlugin };
87
+ function WechatyClawChatPlugin() {
88
+ return function (bot) {
89
+ bot.on('message', onClawMessage);
90
+ };
91
+ }
92
+ export { WechatyWebPanelPlugin, WechatyMessageRecordPlugin, WechatyMessageCallBackPlugin, WechatyClawChatPlugin };
87
93
  //# sourceMappingURL=index.js.map
package/dist/lib/oss.js CHANGED
@@ -2,9 +2,9 @@ import OSS from 'ali-oss';
2
2
  import { allConfig } from '../db/configDb.js';
3
3
  import { uploadGlobalS3File, uploadS3File } from './s3oss.js';
4
4
  import { uploadTencentOssFile, uploadGlobalTencentOssFile } from './tencentOss.js';
5
- export async function uploadOssFile(fileName, file) {
5
+ export async function uploadOssFile(fileName, file, moreOssConfig) {
6
6
  const config = await allConfig();
7
- const ossConfig = config.conversationRecord && config.conversationRecord.ossConfig;
7
+ const ossConfig = config.conversationRecord && config.conversationRecord.ossConfig || moreOssConfig;
8
8
  if (ossConfig.type === 2) {
9
9
  // 使用S3存储
10
10
  return await uploadS3File(fileName, file, ossConfig);
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const packageJson = {
5
5
  "name": "wechaty-web-panel",
6
- "version": "1.6.118",
6
+ "version": "1.6.120",
7
7
  "exports": {
8
8
  ".": {
9
9
  "import": "./dist/index.js"
@@ -60,12 +60,13 @@ export const packageJson = {
60
60
  "dotenv": "^16.3.0",
61
61
  "eventsource-parser": "^1.0.0",
62
62
  "express": "^5.1.0",
63
+ "file-box": "^1.5.5",
63
64
  "form-data": "^4.0.0",
64
65
  "https-proxy-agent": "^5.0.1",
65
66
  "jsonwebtoken": "^9.0.2",
66
67
  "keyv": "^4.5.2",
67
68
  "langchain": "^0.3.19",
68
- "mqtt": "^4.2.6",
69
+ "mqtt": "^4.3.8",
69
70
  "mustache": "^4.2.0",
70
71
  "nedb": "^1.8.0",
71
72
  "node-fetch": "^2.6.9",
@@ -238,7 +238,8 @@ async function getConfig() {
238
238
  ignoreFiles: false,
239
239
  filterLinkContent: false,
240
240
  ...config,
241
- cloudRoom
241
+ cloudRoom,
242
+ clawConfig: { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: true, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} }
242
243
  });
243
244
  return cres;
244
245
  }
@@ -755,6 +756,24 @@ async function getMqttConfig() {
755
756
  console.log('获取mqtt配置错误', error);
756
757
  }
757
758
  }
759
+ /**
760
+ * 获取claw mqtt信息
761
+ * @param {*} version
762
+ */
763
+ async function getClawMqttConfig() {
764
+ try {
765
+ let option = {
766
+ method: 'GET',
767
+ url: '/claw/mqtt/config',
768
+ params: {},
769
+ };
770
+ let content = await aiBotReq(option);
771
+ return content.data;
772
+ }
773
+ catch (error) {
774
+ console.log('获取claw mqtt配置错误', error);
775
+ }
776
+ }
758
777
  /**
759
778
  * 获取实时素材
760
779
  * @param {*} version
@@ -801,6 +820,7 @@ export { getRssLast };
801
820
  export { updateRssLast };
802
821
  export { clearVerifyInfo };
803
822
  export { setVerifyInfo };
823
+ export { getClawMqttConfig };
804
824
  export default {
805
825
  getConfig,
806
826
  getScheduleList,
@@ -824,6 +844,8 @@ export default {
824
844
  updateRssLast,
825
845
  getVerifyCode,
826
846
  clearVerifyInfo,
827
- setVerifyInfo
847
+ setVerifyInfo,
848
+ getClawMqttConfig,
849
+ getClawMqttConfig
828
850
  };
829
851
  //# sourceMappingURL=aibotk.js.map
@@ -13,6 +13,7 @@ import { getCozeReply, getCozeSimpleReply, reset as cozeReset } from '../proxy/c
13
13
  import { getQAnyReply, reset as qanyReset } from '../proxy/qAnyAi.js';
14
14
  import { outApi } from '../proxy/outapi.js';
15
15
  import { getUser } from '../db/userDb.js';
16
+ import { initClawMqtt } from '../handlers/on-claw-message.js';
16
17
  /**
17
18
  * 根据事件名称分配不同的api处理,并获取返回内容
18
19
  * @param {string} eName 事件名称
@@ -129,6 +130,7 @@ async function dispatchEventContent(that, eName, msg, name, id, avatar, room, ro
129
130
  qanyReset();
130
131
  cozeV3Reset();
131
132
  fastGptReset();
133
+ initClawMqtt(that);
132
134
  content = '更新配置成功,请稍等一分钟后生效';
133
135
  break;
134
136
  case 'autoRoomCreate':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wechaty-web-panel",
3
- "version": "1.6.118",
3
+ "version": "1.6.120",
4
4
  "exports": {
5
5
  ".": {
6
6
  "import": "./dist/index.js"
@@ -57,12 +57,13 @@
57
57
  "dotenv": "^16.3.0",
58
58
  "eventsource-parser": "^1.0.0",
59
59
  "express": "^5.1.0",
60
+ "file-box": "^1.5.5",
60
61
  "form-data": "^4.0.0",
61
62
  "https-proxy-agent": "^5.0.1",
62
63
  "jsonwebtoken": "^9.0.2",
63
64
  "keyv": "^4.5.2",
64
65
  "langchain": "^0.3.19",
65
- "mqtt": "^4.2.6",
66
+ "mqtt": "^4.3.8",
66
67
  "mustache": "^4.2.0",
67
68
  "nedb": "^1.8.0",
68
69
  "node-fetch": "^2.6.9",