wechaty-puppet-matrix 0.0.23 → 0.0.26
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/events/event-friendship.d.ts.map +1 -1
- package/dist/cjs/src/matrix/events/event-message.d.ts.map +1 -1
- package/dist/cjs/src/matrix/events/event-room-invite.d.ts.map +1 -1
- package/dist/cjs/src/matrix/events/event-room-join.d.ts.map +1 -1
- package/dist/cjs/src/matrix/events/event-room-leave.d.ts.map +1 -1
- package/dist/cjs/src/matrix/events/event-room-topic.d.ts.map +1 -1
- package/dist/cjs/src/matrix/service/request.d.ts +8 -3
- package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
- package/dist/cjs/src/matrix/service/request.js +110 -50
- package/dist/cjs/src/matrix/utils/string.d.ts.map +1 -1
- package/dist/cjs/src/puppet-matrix.d.ts +2 -0
- package/dist/cjs/src/puppet-matrix.d.ts.map +1 -1
- package/dist/cjs/src/puppet-matrix.js +107 -5
- package/dist/cjs/src/utils/normalize-filebox.d.ts.map +1 -1
- package/dist/cjs/src/utils/sns-xml-generator.d.ts.map +1 -1
- package/dist/esm/src/matrix/events/event-friendship.d.ts.map +1 -1
- package/dist/esm/src/matrix/events/event-message.d.ts.map +1 -1
- package/dist/esm/src/matrix/events/event-room-invite.d.ts.map +1 -1
- package/dist/esm/src/matrix/events/event-room-join.d.ts.map +1 -1
- package/dist/esm/src/matrix/events/event-room-leave.d.ts.map +1 -1
- package/dist/esm/src/matrix/events/event-room-topic.d.ts.map +1 -1
- package/dist/esm/src/matrix/service/request.d.ts +8 -3
- package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
- package/dist/esm/src/matrix/service/request.js +110 -50
- package/dist/esm/src/matrix/utils/string.d.ts.map +1 -1
- package/dist/esm/src/puppet-matrix.d.ts +2 -0
- package/dist/esm/src/puppet-matrix.d.ts.map +1 -1
- package/dist/esm/src/puppet-matrix.js +107 -5
- package/dist/esm/src/utils/normalize-filebox.d.ts.map +1 -1
- package/dist/esm/src/utils/sns-xml-generator.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/matrix/service/request.ts +124 -62
- package/src/puppet-matrix.ts +169 -69
- package/src/puppet-matrix.ts~ +0 -1674
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-filebox.d.ts","sourceRoot":"","sources":["../../../../src/utils/normalize-filebox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACR,MAA0B,UAAU,CAAA;AACrC,OAAO,EAEL,gBAAgB,EACjB,MAA0B,UAAU,CAAA;AA4BrC,QAAA,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"normalize-filebox.d.ts","sourceRoot":"","sources":["../../../../src/utils/normalize-filebox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACR,MAA0B,UAAU,CAAA;AACrC,OAAO,EAEL,gBAAgB,EACjB,MAA0B,UAAU,CAAA;AA4BrC,QAAA,MAAM,cAAc,GAAI,SAAS,gBAAgB,YA8BhD,CAAA;AAED,QAAA,MAAM,oBAAoB,GAAI,aAAa,OAAO,OAAO,MAAY,SAAS,gBAAgB,wCAkB7F,CAAA;AAED,OAAO,EACL,cAAc,EACd,oBAAoB,GACrB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sns-xml-generator.d.ts","sourceRoot":"","sources":["../../../../src/utils/sns-xml-generator.ts"],"names":[],"mappings":"AAAA,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"sns-xml-generator.d.ts","sourceRoot":"","sources":["../../../../src/utils/sns-xml-generator.ts"],"names":[],"mappings":"AAAA,KAAK,KAAK,GAAG;IACX,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,KAAG,MAkD7D,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,SAAS,MAAM,EAAE,OAAO,KAAK,KAAG,MAgD5E,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,aAAa,MAAM,EAAE,WAAW,KAAK,EAAE,KAAG,MAkEtF,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wechaty-puppet-matrix",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.26",
|
|
4
4
|
"description": "Puppet matrix for Wechaty",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"typings": "./dist/esm/src/mod.d.ts",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"fs-extra": "^10.1.0",
|
|
78
78
|
"image-size": "^1.1.1",
|
|
79
79
|
"lru-cache": "^6.0.0",
|
|
80
|
+
"mqtt": "^5.10.4",
|
|
80
81
|
"node-cleanup": "^2.1.2",
|
|
81
82
|
"wechaty-web-panel": "^1.6.76",
|
|
82
83
|
"ws": "^8.18.0",
|
|
@@ -11,6 +11,7 @@ import imageSize from 'image-size'
|
|
|
11
11
|
import fs from 'fs-extra'
|
|
12
12
|
import os from 'os'
|
|
13
13
|
import path from 'path'
|
|
14
|
+
import mqtt from 'mqtt'
|
|
14
15
|
const PRE = '[PuppetMatrix]'
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -643,10 +644,12 @@ class Client extends EventEmitter {
|
|
|
643
644
|
private readonly HEARTBEAT_TIMEOUT = 5000 // 5秒超时
|
|
644
645
|
private reconnectAttempts = 0
|
|
645
646
|
private heartbeatTimer?: any
|
|
647
|
+
private checkExpiredInterval?: any
|
|
646
648
|
private heartbeatTimeoutTimer?: any
|
|
647
649
|
private getQrcodeTimes = 0
|
|
648
650
|
private restoreTimes = 0
|
|
649
651
|
private maxRestoreTimes = 1
|
|
652
|
+
private hasExpired = false
|
|
650
653
|
socket: any
|
|
651
654
|
server: any
|
|
652
655
|
tokenInfo: any
|
|
@@ -663,6 +666,7 @@ class Client extends EventEmitter {
|
|
|
663
666
|
override emit(event: 'verify-code', verifyInfo: VerifyInfo): boolean;
|
|
664
667
|
override emit(event: 'update-contacts', contacts: ContactPayload[]): boolean;
|
|
665
668
|
override emit(event: 'room-join', info: any): boolean;
|
|
669
|
+
override emit(event: 'expired', info: boolean): boolean;
|
|
666
670
|
|
|
667
671
|
override emit (event: ClientEvent, ...args: any[]): boolean {
|
|
668
672
|
return super.emit(event, ...args)
|
|
@@ -683,6 +687,20 @@ class Client extends EventEmitter {
|
|
|
683
687
|
this.getQrcodeTimes = 0
|
|
684
688
|
this.restoreTimes = 0
|
|
685
689
|
this.maxRestoreTimes = 1
|
|
690
|
+
this.hasExpired = false
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
destroy () {
|
|
694
|
+
log.verbose(PRE, 'destroy()')
|
|
695
|
+
this.hasEmitLogout = false
|
|
696
|
+
this.socket && this.socket.end()
|
|
697
|
+
this.socket = null
|
|
698
|
+
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval)
|
|
699
|
+
this.checkExpiredInterval = undefined
|
|
700
|
+
this.heartbeatTimer && clearTimeout(this.heartbeatTimer)
|
|
701
|
+
this.heartbeatTimer = undefined
|
|
702
|
+
this.heartbeatTimeoutTimer && clearTimeout(this.heartbeatTimeoutTimer)
|
|
703
|
+
this.heartbeatTimeoutTimer = undefined
|
|
686
704
|
}
|
|
687
705
|
|
|
688
706
|
async getTokenInfo () {
|
|
@@ -690,6 +708,16 @@ class Client extends EventEmitter {
|
|
|
690
708
|
const res = await axios.get(`https://api-bot.aibotk.com/openapi/v1/token/info?secret=5be06b6f8d42a7&token=${this.options.token}`)
|
|
691
709
|
if (res.data.code === 0) {
|
|
692
710
|
this.tokenInfo = res.data.data
|
|
711
|
+
this.hasExpired = res.data?.data?.hasExpired
|
|
712
|
+
if (this.hasExpired) {
|
|
713
|
+
log.error('Token已到期,请及时续费')
|
|
714
|
+
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval)
|
|
715
|
+
this.checkExpiredInterval = undefined
|
|
716
|
+
setTimeout(() => {
|
|
717
|
+
this.emit('expired', true)
|
|
718
|
+
}, 3000)
|
|
719
|
+
return false
|
|
720
|
+
}
|
|
693
721
|
return true
|
|
694
722
|
} else {
|
|
695
723
|
log.error('Token auth failed, reason: %s', res.data.message)
|
|
@@ -701,106 +729,108 @@ class Client extends EventEmitter {
|
|
|
701
729
|
}
|
|
702
730
|
}
|
|
703
731
|
|
|
732
|
+
checkHasExpired () {
|
|
733
|
+
this.checkExpiredInterval = setInterval(() => {
|
|
734
|
+
log.info('checkHasExpired')
|
|
735
|
+
void this.getTokenInfo()
|
|
736
|
+
}, 1000 * 60 * 60 * 12)
|
|
737
|
+
}
|
|
738
|
+
|
|
704
739
|
async initServer () {
|
|
705
740
|
await this.getTokenInfo()
|
|
741
|
+
this.checkHasExpired()
|
|
706
742
|
if (this.socket) {
|
|
707
743
|
log.error('socket had already been opened!')
|
|
708
744
|
return
|
|
709
745
|
}
|
|
710
746
|
|
|
711
|
-
await this.
|
|
747
|
+
await this.createMqttConnection()
|
|
712
748
|
}
|
|
713
749
|
|
|
714
|
-
async
|
|
750
|
+
async createMqttConnection (): Promise<void> {
|
|
751
|
+
if (this.hasExpired) {
|
|
752
|
+
return
|
|
753
|
+
}
|
|
715
754
|
if (!this.tokenInfo) {
|
|
716
755
|
log.error('Token info not available')
|
|
717
756
|
return
|
|
718
757
|
}
|
|
719
|
-
const ws = new WebSocket(
|
|
720
|
-
`${this.tokenInfo.endpoint}?guid=${this.tokenInfo.guid}`,
|
|
721
|
-
{
|
|
722
|
-
perMessageDeflate: true,
|
|
723
|
-
maxPayload: 100 * 1024 * 1024,
|
|
724
|
-
},
|
|
725
|
-
)
|
|
726
758
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
this.reconnectAttempts = 0
|
|
732
|
-
log.info('WebSocket connection opened')
|
|
733
|
-
resolve()
|
|
734
|
-
})
|
|
759
|
+
function randomRange (min: number, max: number) {
|
|
760
|
+
// min最小值,max最大值
|
|
761
|
+
return Math.floor(Math.random() * (max - min)) + min
|
|
762
|
+
}
|
|
735
763
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
764
|
+
const client = mqtt.connect(this.tokenInfo.mqServer, {
|
|
765
|
+
username: this.tokenInfo.mqUser,
|
|
766
|
+
password: this.tokenInfo.mqPsd,
|
|
767
|
+
keepalive: 60,
|
|
768
|
+
reconnectPeriod: 1000,
|
|
769
|
+
connectTimeout: 30 * 1000,
|
|
770
|
+
clientId: this.tokenInfo.guid + randomRange(1, 10000),
|
|
771
|
+
})
|
|
740
772
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
773
|
+
client.on('connect', () => {
|
|
774
|
+
this.connectionStatus.status = 'connected'
|
|
775
|
+
this.reconnectAttempts = 0
|
|
776
|
+
log.info('MQTT connection opened')
|
|
777
|
+
this.socket = client
|
|
778
|
+
|
|
779
|
+
// 订阅主题
|
|
780
|
+
client.subscribe(`aibotk/msg/${this.tokenInfo.guid}`, (err: any) => {
|
|
781
|
+
if (err) {
|
|
782
|
+
log.error('Failed to subscribe to topic', err)
|
|
783
|
+
} else {
|
|
784
|
+
log.info('Subscribed to topic')
|
|
785
|
+
}
|
|
744
786
|
})
|
|
745
787
|
})
|
|
746
|
-
this.socket = ws
|
|
747
788
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
789
|
+
client.on('error', (error: any) => {
|
|
790
|
+
log.warn('MQTT connection error', error)
|
|
791
|
+
})
|
|
792
|
+
|
|
793
|
+
client.on('close', () => {
|
|
794
|
+
this.connectionStatus.status = 'disconnected'
|
|
795
|
+
log.warn('MQTT connection closed')
|
|
796
|
+
this.socket = null
|
|
797
|
+
void this.reconnect()
|
|
798
|
+
})
|
|
751
799
|
|
|
752
|
-
|
|
753
|
-
// 消息处理
|
|
754
|
-
ws.on('message', (data: string) => {
|
|
800
|
+
client.on('message', (topic, message) => {
|
|
755
801
|
this.resetHeartbeatTimeout() // 收到任何消息都重置心跳超时
|
|
756
|
-
|
|
757
|
-
|
|
802
|
+
|
|
803
|
+
log.verbose(PRE, 'Received message on topic %s: %s', topic, message.toString())
|
|
804
|
+
if (message.toString() === 'ping' || message.toString() === 'pong') {
|
|
758
805
|
log.verbose('Received heartbeat')
|
|
759
806
|
return
|
|
760
807
|
}
|
|
808
|
+
|
|
761
809
|
try {
|
|
762
|
-
const payload = JSON.parse(
|
|
810
|
+
const payload = JSON.parse(message.toString())
|
|
763
811
|
log.info('Received payload', JSON.stringify(payload))
|
|
764
812
|
void this.eventParse(payload)
|
|
765
813
|
} catch (error) {
|
|
766
|
-
log.warn(PRE, '
|
|
814
|
+
log.warn(PRE, 'Error parsing message: %s', error)
|
|
767
815
|
// @ts-ignore
|
|
768
816
|
this.emit('error', (error as Error).message)
|
|
769
817
|
}
|
|
770
818
|
})
|
|
771
819
|
|
|
772
|
-
|
|
773
|
-
ws.on('error', (error: Error) => {
|
|
774
|
-
if ((error as any).code === 'ECONNREFUSED') {
|
|
775
|
-
log.verbose('Connection refused, potential reconnect scenario')
|
|
776
|
-
return
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
log.verbose(PRE, 'initWebSocket() ws.on(error) %s', error)
|
|
780
|
-
// @ts-ignore
|
|
781
|
-
this.emit('error', error)
|
|
782
|
-
})
|
|
783
|
-
|
|
784
|
-
// 关闭处理
|
|
785
|
-
ws.on('close', (code:any, reason: any) => {
|
|
786
|
-
this.stopHeartbeat()
|
|
787
|
-
void this.handleWebSocketClose(code, reason)
|
|
788
|
-
})
|
|
789
|
-
// 启动心跳
|
|
820
|
+
this.socket = client
|
|
790
821
|
this.startHeartbeat()
|
|
791
822
|
}
|
|
792
823
|
|
|
793
824
|
private startHeartbeat (): void {
|
|
794
825
|
this.stopHeartbeat() // 确保清理现有定时器
|
|
795
|
-
this.socket?.send('ping')
|
|
796
826
|
this.heartbeatTimer = setInterval(() => {
|
|
797
|
-
if (this.socket?.
|
|
827
|
+
if (this.socket?.connected) {
|
|
798
828
|
try {
|
|
799
|
-
this.socket.
|
|
829
|
+
this.socket.publish(`aibotk/msg/${this.tokenInfo.guid}`, 'pong')
|
|
800
830
|
this.setHeartbeatTimeout()
|
|
801
831
|
} catch (error) {
|
|
802
832
|
log.error('Failed to send heartbeat:', error)
|
|
803
|
-
void this.
|
|
833
|
+
void this.handleMqttClose()
|
|
804
834
|
}
|
|
805
835
|
}
|
|
806
836
|
}, this.HEARTBEAT_INTERVAL)
|
|
@@ -826,7 +856,7 @@ class Client extends EventEmitter {
|
|
|
826
856
|
}
|
|
827
857
|
this.heartbeatTimeoutTimer = setTimeout(() => {
|
|
828
858
|
log.warn('Heartbeat timeout, reconnecting...')
|
|
829
|
-
void this.
|
|
859
|
+
void this.handleMqttClose()
|
|
830
860
|
}, this.HEARTBEAT_TIMEOUT)
|
|
831
861
|
}
|
|
832
862
|
|
|
@@ -838,20 +868,48 @@ class Client extends EventEmitter {
|
|
|
838
868
|
}
|
|
839
869
|
}
|
|
840
870
|
|
|
841
|
-
private async
|
|
871
|
+
private async handleMqttClose () {
|
|
842
872
|
this.connectionStatus.status = 'disconnected'
|
|
843
|
-
log.warn(
|
|
873
|
+
log.warn('MQTT connection closed')
|
|
844
874
|
if (this.socket) {
|
|
845
|
-
this.socket.
|
|
875
|
+
this.socket.end()
|
|
846
876
|
this.socket = null
|
|
847
877
|
}
|
|
848
878
|
|
|
849
879
|
// 触发重连
|
|
850
|
-
await this.
|
|
880
|
+
await this.reconnectMqtt()
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
private async reconnectMqtt (): Promise<void> {
|
|
884
|
+
if (this.hasExpired) {
|
|
885
|
+
return
|
|
886
|
+
}
|
|
887
|
+
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
888
|
+
log.error('Max reconnect attempts reached. Stopping reconnection.')
|
|
889
|
+
return
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// 指数退避重连策略
|
|
893
|
+
const delay = Math.min(
|
|
894
|
+
this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts),
|
|
895
|
+
this.MAX_RECONNECT_DELAY,
|
|
896
|
+
)
|
|
851
897
|
|
|
898
|
+
this.reconnectAttempts++
|
|
899
|
+
log.info(`Reconnecting in ${delay}ms (Attempt ${this.reconnectAttempts})`)
|
|
900
|
+
setTimeout(() => {
|
|
901
|
+
try {
|
|
902
|
+
void this.createMqttConnection()
|
|
903
|
+
} catch (error) {
|
|
904
|
+
log.warn('Reconnection failed', error)
|
|
905
|
+
}
|
|
906
|
+
}, delay)
|
|
852
907
|
}
|
|
853
908
|
|
|
854
909
|
private async reconnect (): Promise<void> {
|
|
910
|
+
if (this.hasExpired) {
|
|
911
|
+
return
|
|
912
|
+
}
|
|
855
913
|
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
856
914
|
log.error('Max reconnect attempts reached. Stopping reconnection.')
|
|
857
915
|
return
|
|
@@ -1073,6 +1131,10 @@ class Client extends EventEmitter {
|
|
|
1073
1131
|
}
|
|
1074
1132
|
|
|
1075
1133
|
async postData (data: any) {
|
|
1134
|
+
if (this.hasExpired) {
|
|
1135
|
+
log.error('Token已到期,无法提供服务')
|
|
1136
|
+
return
|
|
1137
|
+
}
|
|
1076
1138
|
const config: any = {
|
|
1077
1139
|
data: {
|
|
1078
1140
|
guid: this.tokenInfo.guid,
|