wechaty-puppet-matrix 0.0.42 → 0.0.47

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.
@@ -129,14 +129,18 @@ async function getImageInfo(imageUrl) {
129
129
  }
130
130
  const finalFilePath = path.join(tempFilePath, 'temp_image_' + Date.now() + path.extname(imageUrl));
131
131
  await fs.writeFile(finalFilePath, response.data);
132
- const dimensions = imageSize(finalFilePath);
133
- await fs.unlink(finalFilePath);
134
- return {
135
- file_size: fileSize,
136
- image_width: dimensions.width,
137
- image_height: dimensions.height,
138
- file_type: dimensions.type,
139
- };
132
+ try {
133
+ const dimensions = imageSize(finalFilePath);
134
+ return {
135
+ file_size: fileSize,
136
+ image_width: dimensions.width,
137
+ image_height: dimensions.height,
138
+ file_type: dimensions.type,
139
+ };
140
+ }
141
+ finally {
142
+ await fs.unlink(finalFilePath).catch(() => undefined);
143
+ }
140
144
  }
141
145
  catch (error) {
142
146
  console.error('获取图片信息错误:', error);
@@ -358,11 +362,13 @@ class Client extends EventEmitter {
358
362
  this.hasExpired = false;
359
363
  this.lastInitSeqInfo = { contactSeq: 0, roomSeq: 0 };
360
364
  }
361
- destroy() {
365
+ async destroy() {
362
366
  log.verbose(PRE, 'destroy()');
363
367
  this.hasEmitLogout = false;
364
- this.socket && this.socket.end();
365
- this.socket = null;
368
+ if (this.socket) {
369
+ await new Promise(resolve => this.socket.end(false, undefined, resolve));
370
+ this.socket = null;
371
+ }
366
372
  this.checkExpiredInterval && clearInterval(this.checkExpiredInterval);
367
373
  this.checkExpiredInterval = undefined;
368
374
  this.heartbeatTimer && clearTimeout(this.heartbeatTimer);
@@ -404,7 +410,11 @@ class Client extends EventEmitter {
404
410
  }, 1000 * 60 * 60 * 12);
405
411
  }
406
412
  async initServer() {
407
- await this.getTokenInfo();
413
+ const tokenValid = await this.getTokenInfo();
414
+ if (!tokenValid) {
415
+ log.error(PRE, 'initServer: token invalid or expired, abort');
416
+ return;
417
+ }
408
418
  this.checkHasExpired();
409
419
  if (this.socket) {
410
420
  log.error('socket had already been opened!');
@@ -517,6 +527,10 @@ class Client extends EventEmitter {
517
527
  });
518
528
  break;
519
529
  case NotifyTypeEnum.NewMsg:
530
+ if (data.create_time < Math.floor(Date.now() / 1000) - 60) {
531
+ log.warn('消息时间超过60秒,可能是重复消息,已忽略', data);
532
+ return;
533
+ }
520
534
  if (data.is_chatroom_msg) {
521
535
  atWxidList = await getAtWxidList(data.source);
522
536
  }
@@ -635,6 +649,10 @@ class Client extends EventEmitter {
635
649
  log.error('Token已到期,无法提供服务');
636
650
  return;
637
651
  }
652
+ if (!this.tokenInfo) {
653
+ log.error(PRE, 'postData: tokenInfo is null, skip request');
654
+ return;
655
+ }
638
656
  const config = {
639
657
  data: {
640
658
  guid: this.tokenInfo.guid,
@@ -677,21 +695,29 @@ class Client extends EventEmitter {
677
695
  log.info(PRE, 'restore() res: %s', res);
678
696
  }
679
697
  async getStats() {
680
- const res = await this.postData({
681
- path: '/client/get_client_status',
682
- data: {},
683
- });
684
- const { errcode, data } = res;
685
- if (!errcode) {
686
- return {
687
- status: data.status === 1
688
- ? Status.pending
689
- : data.status === 2
690
- ? Status.normal
691
- : Status.offline,
692
- };
698
+ try {
699
+ const res = await this.postData({
700
+ path: '/client/get_client_status',
701
+ data: {},
702
+ });
703
+ if (!res)
704
+ return { status: Status.fail };
705
+ const { errcode, data } = res;
706
+ if (!errcode) {
707
+ return {
708
+ status: data.status === 1
709
+ ? Status.pending
710
+ : data.status === 2
711
+ ? Status.normal
712
+ : Status.offline,
713
+ };
714
+ }
715
+ else {
716
+ return { status: Status.fail };
717
+ }
693
718
  }
694
- else {
719
+ catch (e) {
720
+ log.error(PRE, 'getStats(): %s', e);
695
721
  return { status: Status.fail };
696
722
  }
697
723
  }
@@ -818,7 +844,11 @@ class Client extends EventEmitter {
818
844
  },
819
845
  });
820
846
  if (res.errcode === -1 && res.errmsg === 'bridge guid not exist') {
821
- log.info(PRE, 'setBridgeId(%s): %s', bridgeId, 'bridge guid not exist');
847
+ if (bridgeId === '') {
848
+ log.warn(PRE, 'setBridgeId: empty bridgeId still invalid, skip retry to avoid infinite recursion');
849
+ return;
850
+ }
851
+ log.info(PRE, 'setBridgeId(%s): %s', bridgeId, 'bridge guid not exist, retrying with empty bridgeId');
822
852
  void this.setBridgeId('');
823
853
  return;
824
854
  }
@@ -1080,7 +1110,12 @@ class Client extends EventEmitter {
1080
1110
  };
1081
1111
  }
1082
1112
  }
1083
- async syncContact(init) {
1113
+ async syncContact(init, depth = 0) {
1114
+ const maxDepth = 200;
1115
+ if (depth >= maxDepth) {
1116
+ log.warn(PRE, 'syncContact: reached max recursion depth %d, stop', maxDepth);
1117
+ return;
1118
+ }
1084
1119
  try {
1085
1120
  if (init) {
1086
1121
  this.lastInitSeqInfo = { contactSeq: 0, roomSeq: 0 };
@@ -1102,7 +1137,7 @@ class Client extends EventEmitter {
1102
1137
  this.emit('update-contacts', contactsInfo || []);
1103
1138
  }
1104
1139
  if (continueFlag) {
1105
- await this.syncContact();
1140
+ await this.syncContact(undefined, depth + 1);
1106
1141
  }
1107
1142
  }
1108
1143
  catch (e) {
@@ -1118,8 +1153,8 @@ class Client extends EventEmitter {
1118
1153
  page_size: pageSize,
1119
1154
  },
1120
1155
  });
1121
- const totalPage = res.total_page || 1;
1122
- const contactList = res.contact_list
1156
+ const totalPage = res?.total_page || 1;
1157
+ const contactList = (res?.contact_list || [])
1123
1158
  .filter((item) => item.username)
1124
1159
  .map((contact) => {
1125
1160
  return {
@@ -1154,8 +1189,8 @@ class Client extends EventEmitter {
1154
1189
  page_size: pageSize,
1155
1190
  },
1156
1191
  });
1157
- const totalPage = res.total_page || 1;
1158
- const contactList = res.contact_list
1192
+ const totalPage = res?.total_page || 1;
1193
+ const contactList = (res?.contact_list || [])
1159
1194
  .filter((item) => item.username)
1160
1195
  .map((contact) => {
1161
1196
  return {
@@ -1190,8 +1225,8 @@ class Client extends EventEmitter {
1190
1225
  page_size: pageSize,
1191
1226
  },
1192
1227
  });
1193
- const totalPage = res.total_page || 1;
1194
- const groupList = res.room_list
1228
+ const totalPage = res?.total_page || 1;
1229
+ const groupList = (res?.room_list || [])
1195
1230
  .filter((item) => item.username)
1196
1231
  .map((item) => {
1197
1232
  return {
@@ -1207,8 +1242,8 @@ class Client extends EventEmitter {
1207
1242
  if (groupList.length > 0) {
1208
1243
  this.emit('update-contacts', groupList);
1209
1244
  }
1210
- if (parseInt(page.toString()) < parseInt(totalPage.toString())) {
1211
- await this.getGroupList(parseInt(page.toString()) + 1, pageSize);
1245
+ if (page < totalPage) {
1246
+ await this.getGroupList(page + 1, pageSize);
1212
1247
  }
1213
1248
  }
1214
1249
  catch (e) {
@@ -1262,8 +1297,8 @@ class Client extends EventEmitter {
1262
1297
  page_size: pageSize,
1263
1298
  },
1264
1299
  });
1265
- const totalPage = res.total_page || 1;
1266
- const officeList = res.contact_list
1300
+ const totalPage = res?.total_page || 1;
1301
+ const officeList = (res?.contact_list || [])
1267
1302
  .filter((item) => item.username)
1268
1303
  .map((contact) => {
1269
1304
  return {
@@ -1346,6 +1381,26 @@ class Client extends EventEmitter {
1346
1381
  },
1347
1382
  });
1348
1383
  }
1384
+ async retryDownload(fn) {
1385
+ const maxRetries = 5;
1386
+ const delayMs = 2000;
1387
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1388
+ try {
1389
+ const res = await fn();
1390
+ if (res?.url) {
1391
+ return res;
1392
+ }
1393
+ log.warn(PRE, 'download attempt %d/%d failed (no url in response)', attempt, maxRetries);
1394
+ }
1395
+ catch (e) {
1396
+ log.warn(PRE, 'download attempt %d/%d error: %s', attempt, maxRetries, e);
1397
+ }
1398
+ if (attempt < maxRetries) {
1399
+ await new Promise(resolve => setTimeout(resolve, delayMs));
1400
+ }
1401
+ }
1402
+ return null;
1403
+ }
1349
1404
  async downloadImage(imageInfo) {
1350
1405
  const params = {
1351
1406
  file_type: 2,
@@ -1354,17 +1409,12 @@ class Client extends EventEmitter {
1354
1409
  file_size: imageInfo.file_size,
1355
1410
  file_name: `/微信图片_${format(new Date(), 'yyyyMMddHHmmss')}.png`,
1356
1411
  };
1357
- const res = await this.postData({
1358
- path: '/cloud/cdn_download',
1359
- data: params,
1360
- });
1361
- if (res.url) {
1412
+ const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download', data: params }));
1413
+ if (res?.url) {
1362
1414
  return encodeURI(res.url) || '';
1363
1415
  }
1364
- else {
1365
- console.log('downloadImage error:', res, params);
1366
- return '';
1367
- }
1416
+ log.error(PRE, 'downloadImage failed after %d retries, params: %s', 5, JSON.stringify(params));
1417
+ return '';
1368
1418
  }
1369
1419
  async downloadWWMedia(imageInfo, type) {
1370
1420
  const typeNameMap = {
@@ -1379,17 +1429,12 @@ class Client extends EventEmitter {
1379
1429
  file_name: typeNameMap[type],
1380
1430
  fast_download: false,
1381
1431
  };
1382
- const res = await this.postData({
1383
- path: '/cloud/cdn_download_wwfile',
1384
- data: params,
1385
- });
1386
- if (res.url) {
1432
+ const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download_wwfile', data: params }));
1433
+ if (res?.url) {
1387
1434
  return encodeURI(res.url) || '';
1388
1435
  }
1389
- else {
1390
- console.log('downloadWWMedia error:', res, params);
1391
- return '';
1392
- }
1436
+ log.error(PRE, 'downloadWWMedia failed after %d retries, params: %s', 5, JSON.stringify(params));
1437
+ return '';
1393
1438
  }
1394
1439
  async downloadFile(imageInfo) {
1395
1440
  const params = {
@@ -1399,17 +1444,12 @@ class Client extends EventEmitter {
1399
1444
  file_size: imageInfo.file_size,
1400
1445
  file_name: '/' + sanitizeFilename(imageInfo.file_name),
1401
1446
  };
1402
- const res = await this.postData({
1403
- path: '/cloud/cdn_download',
1404
- data: params,
1405
- });
1406
- if (res.url) {
1447
+ const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download', data: params }));
1448
+ if (res?.url) {
1407
1449
  return encodeURI(res.url) || '';
1408
1450
  }
1409
- else {
1410
- console.log('downloadFile error:', res, params);
1411
- return '';
1412
- }
1451
+ log.error(PRE, 'downloadFile failed after %d retries, params: %s', 5, JSON.stringify(params));
1452
+ return '';
1413
1453
  }
1414
1454
  async downloadAudio(msgId, voiceInfo, roomId) {
1415
1455
  const params = {
@@ -1419,17 +1459,12 @@ class Client extends EventEmitter {
1419
1459
  file_name: '/voice.mp3',
1420
1460
  to_mp3: true,
1421
1461
  };
1422
- const res = await this.postData({
1423
- path: '/cloud/download_voice',
1424
- data: params,
1425
- });
1426
- if (res.url) {
1462
+ const res = await this.retryDownload(() => this.postData({ path: '/cloud/download_voice', data: params }));
1463
+ if (res?.url) {
1427
1464
  return encodeURI(res.url) || '';
1428
1465
  }
1429
- else {
1430
- console.log('downloadAudio error:', res, params);
1431
- return '';
1432
- }
1466
+ log.error(PRE, 'downloadAudio failed after %d retries, params: %s', 5, JSON.stringify(params));
1467
+ return '';
1433
1468
  }
1434
1469
  async downloadVideo(videoInfo) {
1435
1470
  const params = {
@@ -1439,17 +1474,12 @@ class Client extends EventEmitter {
1439
1474
  file_size: videoInfo.file_size,
1440
1475
  file_name: `/微信视频_${format(new Date(), 'yyyyMMddHHmmss')}.mp4`,
1441
1476
  };
1442
- const res = await this.postData({
1443
- path: '/cloud/cdn_download',
1444
- data: params,
1445
- });
1446
- if (res.url) {
1477
+ const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download', data: params }));
1478
+ if (res?.url) {
1447
1479
  return encodeURI(res.url) || '';
1448
1480
  }
1449
- else {
1450
- console.log('downloadVideo error:', res, params);
1451
- return '';
1452
- }
1481
+ log.error(PRE, 'downloadVideo failed after %d retries, params: %s', 5, JSON.stringify(params));
1482
+ return '';
1453
1483
  }
1454
1484
  async sendUrlImg(contactId, url, selfId) {
1455
1485
  try {
@@ -1505,7 +1535,7 @@ class Client extends EventEmitter {
1505
1535
  return {
1506
1536
  id: res?.newMsgId || '',
1507
1537
  timeStamp: res?.createTime || getUnixTime(new Date()),
1508
- msgType: WechatMessageType.Image,
1538
+ msgType: WechatMessageType.Video,
1509
1539
  talkerId: selfId || '',
1510
1540
  text: url,
1511
1541
  msg: url,
@@ -1536,7 +1566,7 @@ class Client extends EventEmitter {
1536
1566
  return {
1537
1567
  id: res?.newMsgId || '',
1538
1568
  timeStamp: res?.createTime || '',
1539
- msgType: WechatMessageType.Image,
1569
+ msgType: WechatMessageType.File,
1540
1570
  talkerId: selfId || '',
1541
1571
  text: url,
1542
1572
  msg: url,
@@ -1859,8 +1889,8 @@ class Client extends EventEmitter {
1859
1889
  const imageBaseInfo = await getImageInfo(image);
1860
1890
  imageInfo.push({ ...res, ...imageBaseInfo });
1861
1891
  }
1862
- xmlContent = genImageSnsXml(wxid, momentInfo.content, imageInfo, momentInfo.location);
1863
1892
  }
1893
+ xmlContent = genImageSnsXml(wxid, momentInfo.content, imageInfo, momentInfo.location);
1864
1894
  }
1865
1895
  else if (momentInfo.videoUrl) {
1866
1896
  const mediaInfo = await this.uploadSnsVideo(momentInfo.videoUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wechaty-puppet-matrix",
3
- "version": "0.0.42",
3
+ "version": "0.0.47",
4
4
  "description": "Puppet matrix for Wechaty",
5
5
  "type": "module",
6
6
  "typings": "./dist/esm/src/mod.d.ts",
@@ -41,7 +41,6 @@
41
41
  ],
42
42
  "devDependencies": {
43
43
  "@chatie/eslint-config": "^1.0.4",
44
- "@chatie/git-scripts": "^0.6.2",
45
44
  "@chatie/semver": "^0.4.7",
46
45
  "@grpc/grpc-js": "1.9.14",
47
46
  "@juzi/wechaty": "^1.0.104",
@@ -94,10 +93,5 @@
94
93
  "bin/",
95
94
  "dist/",
96
95
  "src/"
97
- ],
98
- "git": {
99
- "scripts": {
100
- "pre-push": "npx git-scripts-pre-push"
101
- }
102
- }
96
+ ]
103
97
  }