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.
- package/dist/cjs/src/matrix/service/request.d.ts +5 -3
- package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
- package/dist/cjs/src/matrix/service/request.js +117 -87
- package/dist/esm/src/matrix/service/request.d.ts +5 -3
- package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
- package/dist/esm/src/matrix/service/request.js +117 -87
- package/package.json +2 -8
- package/src/matrix/service/request.ts +118 -93
|
@@ -230,7 +230,8 @@ export type ClientEvent =
|
|
|
230
230
|
| 'contact'
|
|
231
231
|
| 'message'
|
|
232
232
|
| 'scan'
|
|
233
|
-
| 'verify-code'
|
|
233
|
+
| 'verify-code'
|
|
234
|
+
| 'room-leave';
|
|
234
235
|
/**
|
|
235
236
|
* 消息类型:1|文本 3|图片 34|语音 42|名片 43|视频 47|动态表情 48|地理位置 49|分享链接或附件 2001|红包 2002|小程序 2003|群邀请 10000|系统消息
|
|
236
237
|
*/
|
|
@@ -442,17 +443,17 @@ async function getImageInfo (imageUrl: string) {
|
|
|
442
443
|
|
|
443
444
|
await fs.writeFile(finalFilePath, response.data)
|
|
444
445
|
|
|
445
|
-
// 4.
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
446
|
+
// 4. 获取图片宽高,确保临时文件始终被删除
|
|
447
|
+
try {
|
|
448
|
+
const dimensions = imageSize(finalFilePath)
|
|
449
|
+
return {
|
|
450
|
+
file_size: fileSize,
|
|
451
|
+
image_width: dimensions.width,
|
|
452
|
+
image_height: dimensions.height,
|
|
453
|
+
file_type: dimensions.type,
|
|
454
|
+
}
|
|
455
|
+
} finally {
|
|
456
|
+
await fs.unlink(finalFilePath).catch(() => undefined)
|
|
456
457
|
}
|
|
457
458
|
} catch (error) {
|
|
458
459
|
console.error('获取图片信息错误:', error)
|
|
@@ -696,6 +697,7 @@ class Client extends EventEmitter {
|
|
|
696
697
|
override emit(event: 'verify-code', verifyInfo: VerifyInfo): boolean;
|
|
697
698
|
override emit(event: 'update-contacts', contacts: ContactPayload[]): boolean;
|
|
698
699
|
override emit(event: 'room-join', info: any): boolean;
|
|
700
|
+
override emit(event: 'room-leave', info: any): boolean;
|
|
699
701
|
override emit(event: 'expired', info: boolean): boolean;
|
|
700
702
|
|
|
701
703
|
override emit (event: ClientEvent, ...args: any[]): boolean {
|
|
@@ -721,11 +723,13 @@ class Client extends EventEmitter {
|
|
|
721
723
|
this.lastInitSeqInfo = { contactSeq: 0, roomSeq: 0 }
|
|
722
724
|
}
|
|
723
725
|
|
|
724
|
-
destroy () {
|
|
726
|
+
async destroy () {
|
|
725
727
|
log.verbose(PRE, 'destroy()')
|
|
726
728
|
this.hasEmitLogout = false
|
|
727
|
-
|
|
728
|
-
|
|
729
|
+
if (this.socket) {
|
|
730
|
+
await new Promise<void>(resolve => this.socket.end(false, undefined, resolve))
|
|
731
|
+
this.socket = null
|
|
732
|
+
}
|
|
729
733
|
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval)
|
|
730
734
|
this.checkExpiredInterval = undefined
|
|
731
735
|
this.heartbeatTimer && clearTimeout(this.heartbeatTimer)
|
|
@@ -768,7 +772,11 @@ class Client extends EventEmitter {
|
|
|
768
772
|
}
|
|
769
773
|
|
|
770
774
|
async initServer () {
|
|
771
|
-
await this.getTokenInfo()
|
|
775
|
+
const tokenValid = await this.getTokenInfo()
|
|
776
|
+
if (!tokenValid) {
|
|
777
|
+
log.error(PRE, 'initServer: token invalid or expired, abort')
|
|
778
|
+
return
|
|
779
|
+
}
|
|
772
780
|
this.checkHasExpired()
|
|
773
781
|
if (this.socket) {
|
|
774
782
|
log.error('socket had already been opened!')
|
|
@@ -899,6 +907,10 @@ class Client extends EventEmitter {
|
|
|
899
907
|
})
|
|
900
908
|
break
|
|
901
909
|
case NotifyTypeEnum.NewMsg:
|
|
910
|
+
if (data.create_time < Math.floor(Date.now() / 1000) - 60) {
|
|
911
|
+
log.warn('消息时间超过60秒,可能是重复消息,已忽略', data)
|
|
912
|
+
return
|
|
913
|
+
}
|
|
902
914
|
if (data.is_chatroom_msg) {
|
|
903
915
|
atWxidList = await getAtWxidList(data.source)
|
|
904
916
|
}
|
|
@@ -976,7 +988,6 @@ class Client extends EventEmitter {
|
|
|
976
988
|
// this.emit('room-join', params)
|
|
977
989
|
break
|
|
978
990
|
case NotifyTypeEnum.RoomMemberDel:
|
|
979
|
-
// @ts-ignore
|
|
980
991
|
this.emit('room-leave', {
|
|
981
992
|
roomId: data.room_username,
|
|
982
993
|
leaveIds: data.member_list.map((item: any) => item.username),
|
|
@@ -1063,6 +1074,10 @@ class Client extends EventEmitter {
|
|
|
1063
1074
|
log.error('Token已到期,无法提供服务')
|
|
1064
1075
|
return
|
|
1065
1076
|
}
|
|
1077
|
+
if (!this.tokenInfo) {
|
|
1078
|
+
log.error(PRE, 'postData: tokenInfo is null, skip request')
|
|
1079
|
+
return
|
|
1080
|
+
}
|
|
1066
1081
|
const config: any = {
|
|
1067
1082
|
data: {
|
|
1068
1083
|
guid: this.tokenInfo.guid,
|
|
@@ -1117,22 +1132,28 @@ class Client extends EventEmitter {
|
|
|
1117
1132
|
* 获取微信运行状态
|
|
1118
1133
|
*/
|
|
1119
1134
|
public async getStats (): Promise<StatsResult> {
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
? Status.
|
|
1133
|
-
:
|
|
1135
|
+
try {
|
|
1136
|
+
const res = await this.postData({
|
|
1137
|
+
path: '/client/get_client_status',
|
|
1138
|
+
data: {},
|
|
1139
|
+
})
|
|
1140
|
+
// 0: stop, 1: running, 2: online
|
|
1141
|
+
if (!res) return { status: Status.fail }
|
|
1142
|
+
const { errcode, data } = res
|
|
1143
|
+
if (!errcode) {
|
|
1144
|
+
return {
|
|
1145
|
+
status:
|
|
1146
|
+
data.status === 1
|
|
1147
|
+
? Status.pending
|
|
1148
|
+
: data.status === 2
|
|
1149
|
+
? Status.normal
|
|
1150
|
+
: Status.offline,
|
|
1151
|
+
}
|
|
1152
|
+
} else {
|
|
1153
|
+
return { status: Status.fail }
|
|
1134
1154
|
}
|
|
1135
|
-
}
|
|
1155
|
+
} catch (e) {
|
|
1156
|
+
log.error(PRE, 'getStats(): %s', e)
|
|
1136
1157
|
return { status: Status.fail }
|
|
1137
1158
|
}
|
|
1138
1159
|
}
|
|
@@ -1297,7 +1318,11 @@ class Client extends EventEmitter {
|
|
|
1297
1318
|
},
|
|
1298
1319
|
})
|
|
1299
1320
|
if (res.errcode === -1 && res.errmsg === 'bridge guid not exist') {
|
|
1300
|
-
|
|
1321
|
+
if (bridgeId === '') {
|
|
1322
|
+
log.warn(PRE, 'setBridgeId: empty bridgeId still invalid, skip retry to avoid infinite recursion')
|
|
1323
|
+
return
|
|
1324
|
+
}
|
|
1325
|
+
log.info(PRE, 'setBridgeId(%s): %s', bridgeId, 'bridge guid not exist, retrying with empty bridgeId')
|
|
1301
1326
|
void this.setBridgeId('')
|
|
1302
1327
|
return
|
|
1303
1328
|
}
|
|
@@ -1585,7 +1610,12 @@ class Client extends EventEmitter {
|
|
|
1585
1610
|
/**
|
|
1586
1611
|
* 同步联系人
|
|
1587
1612
|
*/
|
|
1588
|
-
public async syncContact (init?: boolean): Promise<void> {
|
|
1613
|
+
public async syncContact (init?: boolean, depth = 0): Promise<void> {
|
|
1614
|
+
const maxDepth = 200
|
|
1615
|
+
if (depth >= maxDepth) {
|
|
1616
|
+
log.warn(PRE, 'syncContact: reached max recursion depth %d, stop', maxDepth)
|
|
1617
|
+
return
|
|
1618
|
+
}
|
|
1589
1619
|
try {
|
|
1590
1620
|
if (init) {
|
|
1591
1621
|
this.lastInitSeqInfo = { contactSeq: 0, roomSeq: 0 }
|
|
@@ -1611,7 +1641,7 @@ class Client extends EventEmitter {
|
|
|
1611
1641
|
}
|
|
1612
1642
|
|
|
1613
1643
|
if (continueFlag) {
|
|
1614
|
-
await this.syncContact()
|
|
1644
|
+
await this.syncContact(undefined, depth + 1)
|
|
1615
1645
|
}
|
|
1616
1646
|
} catch (e) {
|
|
1617
1647
|
log.error(PRE, 'syncContact(): %s', e)
|
|
@@ -1634,8 +1664,8 @@ class Client extends EventEmitter {
|
|
|
1634
1664
|
},
|
|
1635
1665
|
})
|
|
1636
1666
|
|
|
1637
|
-
const totalPage = res
|
|
1638
|
-
const contactList: ContactPayload[] = res
|
|
1667
|
+
const totalPage = res?.total_page || 1
|
|
1668
|
+
const contactList: ContactPayload[] = (res?.contact_list || [])
|
|
1639
1669
|
.filter((item: any) => item.username)
|
|
1640
1670
|
.map((contact: any) => {
|
|
1641
1671
|
return {
|
|
@@ -1675,8 +1705,8 @@ class Client extends EventEmitter {
|
|
|
1675
1705
|
},
|
|
1676
1706
|
})
|
|
1677
1707
|
|
|
1678
|
-
const totalPage = res
|
|
1679
|
-
const contactList: ContactPayload[] = res
|
|
1708
|
+
const totalPage = res?.total_page || 1
|
|
1709
|
+
const contactList: ContactPayload[] = (res?.contact_list || [])
|
|
1680
1710
|
.filter((item: any) => item.username)
|
|
1681
1711
|
.map((contact: any) => {
|
|
1682
1712
|
return {
|
|
@@ -1718,8 +1748,8 @@ class Client extends EventEmitter {
|
|
|
1718
1748
|
page_size: pageSize,
|
|
1719
1749
|
},
|
|
1720
1750
|
})
|
|
1721
|
-
const totalPage = res
|
|
1722
|
-
const groupList: ContactPayload[] = res
|
|
1751
|
+
const totalPage = res?.total_page || 1
|
|
1752
|
+
const groupList: ContactPayload[] = (res?.room_list || [])
|
|
1723
1753
|
.filter((item: any) => item.username)
|
|
1724
1754
|
.map((item: any) => {
|
|
1725
1755
|
return {
|
|
@@ -1737,8 +1767,8 @@ class Client extends EventEmitter {
|
|
|
1737
1767
|
this.emit('update-contacts', groupList)
|
|
1738
1768
|
}
|
|
1739
1769
|
|
|
1740
|
-
if (
|
|
1741
|
-
await this.getGroupList(
|
|
1770
|
+
if (page < totalPage) {
|
|
1771
|
+
await this.getGroupList(page + 1, pageSize)
|
|
1742
1772
|
}
|
|
1743
1773
|
} catch (e) {
|
|
1744
1774
|
log.error(PRE, 'getGroupList(): %s', e)
|
|
@@ -1800,8 +1830,8 @@ class Client extends EventEmitter {
|
|
|
1800
1830
|
page_size: pageSize,
|
|
1801
1831
|
},
|
|
1802
1832
|
})
|
|
1803
|
-
const totalPage = res
|
|
1804
|
-
const officeList = res
|
|
1833
|
+
const totalPage = res?.total_page || 1
|
|
1834
|
+
const officeList = (res?.contact_list || [])
|
|
1805
1835
|
.filter((item: any) => item.username)
|
|
1806
1836
|
.map((contact: any) => {
|
|
1807
1837
|
return {
|
|
@@ -1916,6 +1946,26 @@ class Client extends EventEmitter {
|
|
|
1916
1946
|
})
|
|
1917
1947
|
}
|
|
1918
1948
|
|
|
1949
|
+
private async retryDownload (fn: () => Promise<any>): Promise<any> {
|
|
1950
|
+
const maxRetries = 5
|
|
1951
|
+
const delayMs = 2000
|
|
1952
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1953
|
+
try {
|
|
1954
|
+
const res = await fn()
|
|
1955
|
+
if (res?.url) {
|
|
1956
|
+
return res
|
|
1957
|
+
}
|
|
1958
|
+
log.warn(PRE, 'download attempt %d/%d failed (no url in response)', attempt, maxRetries)
|
|
1959
|
+
} catch (e) {
|
|
1960
|
+
log.warn(PRE, 'download attempt %d/%d error: %s', attempt, maxRetries, e)
|
|
1961
|
+
}
|
|
1962
|
+
if (attempt < maxRetries) {
|
|
1963
|
+
await new Promise(resolve => setTimeout(resolve, delayMs))
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return null
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1919
1969
|
public async downloadImage (imageInfo: ImageMessagePayload): Promise<any> {
|
|
1920
1970
|
const params = {
|
|
1921
1971
|
file_type: 2,
|
|
@@ -1924,16 +1974,12 @@ class Client extends EventEmitter {
|
|
|
1924
1974
|
file_size: imageInfo.file_size,
|
|
1925
1975
|
file_name: `/微信图片_${format(new Date(), 'yyyyMMddHHmmss')}.png`,
|
|
1926
1976
|
}
|
|
1927
|
-
const res = await this.postData({
|
|
1928
|
-
|
|
1929
|
-
data: params,
|
|
1930
|
-
})
|
|
1931
|
-
if (res.url) {
|
|
1977
|
+
const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download', data: params }))
|
|
1978
|
+
if (res?.url) {
|
|
1932
1979
|
return encodeURI(res.url) || ''
|
|
1933
|
-
} else {
|
|
1934
|
-
console.log('downloadImage error:', res, params)
|
|
1935
|
-
return ''
|
|
1936
1980
|
}
|
|
1981
|
+
log.error(PRE, 'downloadImage failed after %d retries, params: %s', 5, JSON.stringify(params))
|
|
1982
|
+
return ''
|
|
1937
1983
|
}
|
|
1938
1984
|
|
|
1939
1985
|
public async downloadWWMedia (imageInfo: ImageMessagePayload, type: number): Promise<any> {
|
|
@@ -1949,16 +1995,12 @@ class Client extends EventEmitter {
|
|
|
1949
1995
|
file_name: typeNameMap[type],
|
|
1950
1996
|
fast_download: false,
|
|
1951
1997
|
}
|
|
1952
|
-
const res = await this.postData({
|
|
1953
|
-
|
|
1954
|
-
data: params,
|
|
1955
|
-
})
|
|
1956
|
-
if (res.url) {
|
|
1998
|
+
const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download_wwfile', data: params }))
|
|
1999
|
+
if (res?.url) {
|
|
1957
2000
|
return encodeURI(res.url) || ''
|
|
1958
|
-
} else {
|
|
1959
|
-
console.log('downloadWWMedia error:', res, params)
|
|
1960
|
-
return ''
|
|
1961
2001
|
}
|
|
2002
|
+
log.error(PRE, 'downloadWWMedia failed after %d retries, params: %s', 5, JSON.stringify(params))
|
|
2003
|
+
return ''
|
|
1962
2004
|
}
|
|
1963
2005
|
|
|
1964
2006
|
/**
|
|
@@ -1973,17 +2015,12 @@ class Client extends EventEmitter {
|
|
|
1973
2015
|
file_size: imageInfo.file_size,
|
|
1974
2016
|
file_name: '/' + sanitizeFilename(imageInfo.file_name),
|
|
1975
2017
|
}
|
|
1976
|
-
const res = await this.postData({
|
|
1977
|
-
|
|
1978
|
-
data: params,
|
|
1979
|
-
})
|
|
1980
|
-
|
|
1981
|
-
if (res.url) {
|
|
2018
|
+
const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download', data: params }))
|
|
2019
|
+
if (res?.url) {
|
|
1982
2020
|
return encodeURI(res.url) || ''
|
|
1983
|
-
} else {
|
|
1984
|
-
console.log('downloadFile error:', res, params)
|
|
1985
|
-
return ''
|
|
1986
2021
|
}
|
|
2022
|
+
log.error(PRE, 'downloadFile failed after %d retries, params: %s', 5, JSON.stringify(params))
|
|
2023
|
+
return ''
|
|
1987
2024
|
}
|
|
1988
2025
|
|
|
1989
2026
|
/**
|
|
@@ -2002,17 +2039,12 @@ class Client extends EventEmitter {
|
|
|
2002
2039
|
file_name: '/voice.mp3',
|
|
2003
2040
|
to_mp3: true,
|
|
2004
2041
|
}
|
|
2005
|
-
const res = await this.postData({
|
|
2006
|
-
|
|
2007
|
-
data: params,
|
|
2008
|
-
})
|
|
2009
|
-
|
|
2010
|
-
if (res.url) {
|
|
2042
|
+
const res = await this.retryDownload(() => this.postData({ path: '/cloud/download_voice', data: params }))
|
|
2043
|
+
if (res?.url) {
|
|
2011
2044
|
return encodeURI(res.url) || ''
|
|
2012
|
-
} else {
|
|
2013
|
-
console.log('downloadAudio error:', res, params)
|
|
2014
|
-
return ''
|
|
2015
2045
|
}
|
|
2046
|
+
log.error(PRE, 'downloadAudio failed after %d retries, params: %s', 5, JSON.stringify(params))
|
|
2047
|
+
return ''
|
|
2016
2048
|
}
|
|
2017
2049
|
|
|
2018
2050
|
/**
|
|
@@ -2027,18 +2059,12 @@ class Client extends EventEmitter {
|
|
|
2027
2059
|
file_size: videoInfo.file_size,
|
|
2028
2060
|
file_name: `/微信视频_${format(new Date(), 'yyyyMMddHHmmss')}.mp4`,
|
|
2029
2061
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
path: '/cloud/cdn_download',
|
|
2033
|
-
data: params,
|
|
2034
|
-
})
|
|
2035
|
-
|
|
2036
|
-
if (res.url) {
|
|
2062
|
+
const res = await this.retryDownload(() => this.postData({ path: '/cloud/cdn_download', data: params }))
|
|
2063
|
+
if (res?.url) {
|
|
2037
2064
|
return encodeURI(res.url) || ''
|
|
2038
|
-
} else {
|
|
2039
|
-
console.log('downloadVideo error:', res, params)
|
|
2040
|
-
return ''
|
|
2041
2065
|
}
|
|
2066
|
+
log.error(PRE, 'downloadVideo failed after %d retries, params: %s', 5, JSON.stringify(params))
|
|
2067
|
+
return ''
|
|
2042
2068
|
}
|
|
2043
2069
|
|
|
2044
2070
|
/**
|
|
@@ -2114,7 +2140,7 @@ class Client extends EventEmitter {
|
|
|
2114
2140
|
return {
|
|
2115
2141
|
id: res?.newMsgId || '',
|
|
2116
2142
|
timeStamp: res?.createTime || getUnixTime(new Date()),
|
|
2117
|
-
msgType: WechatMessageType.
|
|
2143
|
+
msgType: WechatMessageType.Video,
|
|
2118
2144
|
talkerId: selfId || '',
|
|
2119
2145
|
text: url,
|
|
2120
2146
|
msg: url,
|
|
@@ -2154,7 +2180,7 @@ class Client extends EventEmitter {
|
|
|
2154
2180
|
return {
|
|
2155
2181
|
id: res?.newMsgId || '',
|
|
2156
2182
|
timeStamp: res?.createTime || '',
|
|
2157
|
-
msgType: WechatMessageType.
|
|
2183
|
+
msgType: WechatMessageType.File,
|
|
2158
2184
|
talkerId: selfId || '',
|
|
2159
2185
|
text: url,
|
|
2160
2186
|
msg: url,
|
|
@@ -2648,9 +2674,8 @@ class Client extends EventEmitter {
|
|
|
2648
2674
|
const imageBaseInfo = await getImageInfo(image)
|
|
2649
2675
|
imageInfo.push({ ...res, ...imageBaseInfo })
|
|
2650
2676
|
}
|
|
2651
|
-
xmlContent = genImageSnsXml(wxid, momentInfo.content, imageInfo, momentInfo.location)
|
|
2652
|
-
|
|
2653
2677
|
}
|
|
2678
|
+
xmlContent = genImageSnsXml(wxid, momentInfo.content, imageInfo, momentInfo.location)
|
|
2654
2679
|
} else if (momentInfo.videoUrl) {
|
|
2655
2680
|
const mediaInfo: any = await this.uploadSnsVideo(momentInfo.videoUrl)
|
|
2656
2681
|
if (mediaInfo) {
|