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.
Files changed (34) hide show
  1. package/dist/cjs/src/matrix/events/event-friendship.d.ts.map +1 -1
  2. package/dist/cjs/src/matrix/events/event-message.d.ts.map +1 -1
  3. package/dist/cjs/src/matrix/events/event-room-invite.d.ts.map +1 -1
  4. package/dist/cjs/src/matrix/events/event-room-join.d.ts.map +1 -1
  5. package/dist/cjs/src/matrix/events/event-room-leave.d.ts.map +1 -1
  6. package/dist/cjs/src/matrix/events/event-room-topic.d.ts.map +1 -1
  7. package/dist/cjs/src/matrix/service/request.d.ts +8 -3
  8. package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
  9. package/dist/cjs/src/matrix/service/request.js +110 -50
  10. package/dist/cjs/src/matrix/utils/string.d.ts.map +1 -1
  11. package/dist/cjs/src/puppet-matrix.d.ts +2 -0
  12. package/dist/cjs/src/puppet-matrix.d.ts.map +1 -1
  13. package/dist/cjs/src/puppet-matrix.js +107 -5
  14. package/dist/cjs/src/utils/normalize-filebox.d.ts.map +1 -1
  15. package/dist/cjs/src/utils/sns-xml-generator.d.ts.map +1 -1
  16. package/dist/esm/src/matrix/events/event-friendship.d.ts.map +1 -1
  17. package/dist/esm/src/matrix/events/event-message.d.ts.map +1 -1
  18. package/dist/esm/src/matrix/events/event-room-invite.d.ts.map +1 -1
  19. package/dist/esm/src/matrix/events/event-room-join.d.ts.map +1 -1
  20. package/dist/esm/src/matrix/events/event-room-leave.d.ts.map +1 -1
  21. package/dist/esm/src/matrix/events/event-room-topic.d.ts.map +1 -1
  22. package/dist/esm/src/matrix/service/request.d.ts +8 -3
  23. package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
  24. package/dist/esm/src/matrix/service/request.js +110 -50
  25. package/dist/esm/src/matrix/utils/string.d.ts.map +1 -1
  26. package/dist/esm/src/puppet-matrix.d.ts +2 -0
  27. package/dist/esm/src/puppet-matrix.d.ts.map +1 -1
  28. package/dist/esm/src/puppet-matrix.js +107 -5
  29. package/dist/esm/src/utils/normalize-filebox.d.ts.map +1 -1
  30. package/dist/esm/src/utils/sns-xml-generator.d.ts.map +1 -1
  31. package/package.json +2 -1
  32. package/src/matrix/service/request.ts +124 -62
  33. package/src/puppet-matrix.ts +169 -69
  34. 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,YAAa,gBAAgB,YA8BhD,CAAA;AAED,QAAA,MAAM,oBAAoB,gBAAiB,OAAO,OAAO,eAAqB,gBAAgB,wCAkB7F,CAAA;AAED,OAAO,EACL,cAAc,EACd,oBAAoB,GACrB,CAAA"}
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,SAAU,MAAM,WAAW,MAAM,KAAG,MAkD7D,CAAA;AAED,eAAO,MAAM,cAAc,SAAU,MAAM,WAAW,MAAM,SAAS,KAAK,KAAG,MAgD5E,CAAA;AAED,eAAO,MAAM,cAAc,SAAU,MAAM,eAAe,MAAM,aAAa,KAAK,EAAE,KAAG,MAkEtF,CAAA"}
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.23",
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.createWebSocket()
747
+ await this.createMqttConnection()
712
748
  }
713
749
 
714
- async createWebSocket (): Promise<void> {
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
- // 连接建立前的 Promise
728
- await new Promise<void>((resolve, reject) => {
729
- ws.once('open', () => {
730
- this.connectionStatus.status = 'connected'
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
- ws.once('error', (error: any) => {
737
- log.warn('WebSocket connection error', error)
738
- reject(error)
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
- ws.once('close', (code: any, reason: any) => {
742
- void this.handleWebSocketClose(code, reason)
743
- reject(new Error(`WebSocket closed: ${code} - ${reason}`))
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
- this.setupWebSocketListeners(ws)
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
- private setupWebSocketListeners (ws: WebSocket): void {
753
- // 消息处理
754
- ws.on('message', (data: string) => {
800
+ client.on('message', (topic, message) => {
755
801
  this.resetHeartbeatTimeout() // 收到任何消息都重置心跳超时
756
- log.silly(PRE, 'initWebSocket() ws.on(message): %s', data)
757
- if (data.toString() === 'pong') {
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(data)
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, 'initWebSocket() ws.on(message) exception: %s', error)
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?.readyState === WebSocket.OPEN) {
827
+ if (this.socket?.connected) {
798
828
  try {
799
- this.socket.send('ping')
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.handleWebSocketClose(1006, 'Heartbeat failed')
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.handleWebSocketClose(1006, 'Heartbeat timeout')
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 handleWebSocketClose (code?: number, reason?: Buffer | String) {
871
+ private async handleMqttClose () {
842
872
  this.connectionStatus.status = 'disconnected'
843
- log.warn(`WebSocket closed: Code ${code}, Reason ${reason}`)
873
+ log.warn('MQTT connection closed')
844
874
  if (this.socket) {
845
- this.socket.close()
875
+ this.socket.end()
846
876
  this.socket = null
847
877
  }
848
878
 
849
879
  // 触发重连
850
- await this.reconnect()
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,