wechaty-puppet-matrix 0.0.24 → 0.0.27
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 -16
- package/dist/cjs/src/matrix/service/request.d.ts.map +1 -1
- package/dist/cjs/src/matrix/service/request.js +43 -164
- package/dist/cjs/src/puppet-matrix.d.ts.map +1 -1
- package/dist/cjs/src/puppet-matrix.js +8 -0
- package/dist/esm/src/matrix/service/request.d.ts +5 -16
- package/dist/esm/src/matrix/service/request.d.ts.map +1 -1
- package/dist/esm/src/matrix/service/request.js +43 -164
- package/dist/esm/src/puppet-matrix.d.ts.map +1 -1
- package/dist/esm/src/puppet-matrix.js +8 -0
- package/package.json +1 -1
- package/src/matrix/service/request.ts +49 -213
- package/src/puppet-matrix.ts +8 -1
- package/src/puppet-matrix.ts~ +0 -1674
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { log } from '@juzi/wechaty-puppet';
|
|
3
3
|
import { EventEmitter } from 'events';
|
|
4
|
-
import WebSocket from 'ws';
|
|
5
4
|
import * as PUPPET from '@juzi/wechaty-puppet';
|
|
6
5
|
import { format, getUnixTime } from 'date-fns';
|
|
7
6
|
import { xmlToJson } from '../utils/xml-to-json.js';
|
|
@@ -305,17 +304,13 @@ const genImageSnsXml = (wxid, contentDesc, mediaList, location) => {
|
|
|
305
304
|
class Client extends EventEmitter {
|
|
306
305
|
options;
|
|
307
306
|
connectionStatus = { status: 'disconnected' };
|
|
308
|
-
MAX_RECONNECT_ATTEMPTS = 10;
|
|
309
|
-
INITIAL_RECONNECT_DELAY = 1000;
|
|
310
|
-
MAX_RECONNECT_DELAY = 30000;
|
|
311
|
-
HEARTBEAT_INTERVAL = 40 * 1000;
|
|
312
|
-
HEARTBEAT_TIMEOUT = 5000;
|
|
313
|
-
reconnectAttempts = 0;
|
|
314
307
|
heartbeatTimer;
|
|
308
|
+
checkExpiredInterval;
|
|
315
309
|
heartbeatTimeoutTimer;
|
|
316
310
|
getQrcodeTimes = 0;
|
|
317
311
|
restoreTimes = 0;
|
|
318
312
|
maxRestoreTimes = 1;
|
|
313
|
+
hasExpired = false;
|
|
319
314
|
socket;
|
|
320
315
|
server;
|
|
321
316
|
tokenInfo;
|
|
@@ -337,12 +332,35 @@ class Client extends EventEmitter {
|
|
|
337
332
|
this.getQrcodeTimes = 0;
|
|
338
333
|
this.restoreTimes = 0;
|
|
339
334
|
this.maxRestoreTimes = 1;
|
|
335
|
+
this.hasExpired = false;
|
|
336
|
+
}
|
|
337
|
+
destroy() {
|
|
338
|
+
log.verbose(PRE, 'destroy()');
|
|
339
|
+
this.hasEmitLogout = false;
|
|
340
|
+
this.socket && this.socket.end();
|
|
341
|
+
this.socket = null;
|
|
342
|
+
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval);
|
|
343
|
+
this.checkExpiredInterval = undefined;
|
|
344
|
+
this.heartbeatTimer && clearTimeout(this.heartbeatTimer);
|
|
345
|
+
this.heartbeatTimer = undefined;
|
|
346
|
+
this.heartbeatTimeoutTimer && clearTimeout(this.heartbeatTimeoutTimer);
|
|
347
|
+
this.heartbeatTimeoutTimer = undefined;
|
|
340
348
|
}
|
|
341
349
|
async getTokenInfo() {
|
|
342
350
|
try {
|
|
343
351
|
const res = await axios.get(`https://api-bot.aibotk.com/openapi/v1/token/info?secret=5be06b6f8d42a7&token=${this.options.token}`);
|
|
344
352
|
if (res.data.code === 0) {
|
|
345
353
|
this.tokenInfo = res.data.data;
|
|
354
|
+
this.hasExpired = res.data?.data?.hasExpired;
|
|
355
|
+
if (this.hasExpired) {
|
|
356
|
+
log.error('Token已到期,请及时续费');
|
|
357
|
+
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval);
|
|
358
|
+
this.checkExpiredInterval = undefined;
|
|
359
|
+
setTimeout(() => {
|
|
360
|
+
this.emit('expired', true);
|
|
361
|
+
}, 3000);
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
346
364
|
return true;
|
|
347
365
|
}
|
|
348
366
|
else {
|
|
@@ -355,8 +373,15 @@ class Client extends EventEmitter {
|
|
|
355
373
|
return false;
|
|
356
374
|
}
|
|
357
375
|
}
|
|
376
|
+
checkHasExpired() {
|
|
377
|
+
this.checkExpiredInterval = setInterval(() => {
|
|
378
|
+
log.info('checkHasExpired');
|
|
379
|
+
void this.getTokenInfo();
|
|
380
|
+
}, 1000 * 60 * 60 * 12);
|
|
381
|
+
}
|
|
358
382
|
async initServer() {
|
|
359
383
|
await this.getTokenInfo();
|
|
384
|
+
this.checkHasExpired();
|
|
360
385
|
if (this.socket) {
|
|
361
386
|
log.error('socket had already been opened!');
|
|
362
387
|
return;
|
|
@@ -364,6 +389,9 @@ class Client extends EventEmitter {
|
|
|
364
389
|
await this.createMqttConnection();
|
|
365
390
|
}
|
|
366
391
|
async createMqttConnection() {
|
|
392
|
+
if (this.hasExpired) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
367
395
|
if (!this.tokenInfo) {
|
|
368
396
|
log.error('Token info not available');
|
|
369
397
|
return;
|
|
@@ -381,7 +409,6 @@ class Client extends EventEmitter {
|
|
|
381
409
|
});
|
|
382
410
|
client.on('connect', () => {
|
|
383
411
|
this.connectionStatus.status = 'connected';
|
|
384
|
-
this.reconnectAttempts = 0;
|
|
385
412
|
log.info('MQTT connection opened');
|
|
386
413
|
this.socket = client;
|
|
387
414
|
client.subscribe(`aibotk/msg/${this.tokenInfo.guid}`, (err) => {
|
|
@@ -399,11 +426,12 @@ class Client extends EventEmitter {
|
|
|
399
426
|
client.on('close', () => {
|
|
400
427
|
this.connectionStatus.status = 'disconnected';
|
|
401
428
|
log.warn('MQTT connection closed');
|
|
402
|
-
|
|
403
|
-
|
|
429
|
+
});
|
|
430
|
+
client.on('reconnect', () => {
|
|
431
|
+
this.connectionStatus.status = 'reconnecting';
|
|
432
|
+
log.warn('MQTT connection Reconnecting...');
|
|
404
433
|
});
|
|
405
434
|
client.on('message', (topic, message) => {
|
|
406
|
-
this.resetHeartbeatTimeout();
|
|
407
435
|
log.verbose(PRE, 'Received message on topic %s: %s', topic, message.toString());
|
|
408
436
|
if (message.toString() === 'ping' || message.toString() === 'pong') {
|
|
409
437
|
log.verbose('Received heartbeat');
|
|
@@ -420,159 +448,6 @@ class Client extends EventEmitter {
|
|
|
420
448
|
}
|
|
421
449
|
});
|
|
422
450
|
this.socket = client;
|
|
423
|
-
this.startHeartbeat();
|
|
424
|
-
}
|
|
425
|
-
async createWebSocket() {
|
|
426
|
-
if (!this.tokenInfo) {
|
|
427
|
-
log.error('Token info not available');
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
const ws = new WebSocket(`${this.tokenInfo.endpoint}?guid=${this.tokenInfo.guid}`, {
|
|
431
|
-
perMessageDeflate: true,
|
|
432
|
-
maxPayload: 100 * 1024 * 1024,
|
|
433
|
-
});
|
|
434
|
-
await new Promise((resolve, reject) => {
|
|
435
|
-
ws.once('open', () => {
|
|
436
|
-
this.connectionStatus.status = 'connected';
|
|
437
|
-
this.reconnectAttempts = 0;
|
|
438
|
-
log.info('WebSocket connection opened');
|
|
439
|
-
resolve();
|
|
440
|
-
});
|
|
441
|
-
ws.once('error', (error) => {
|
|
442
|
-
log.warn('WebSocket connection error', error);
|
|
443
|
-
reject(error);
|
|
444
|
-
});
|
|
445
|
-
ws.once('close', (code, reason) => {
|
|
446
|
-
void this.handleWebSocketClose(code, reason);
|
|
447
|
-
reject(new Error(`WebSocket closed: ${code} - ${reason}`));
|
|
448
|
-
});
|
|
449
|
-
});
|
|
450
|
-
this.socket = ws;
|
|
451
|
-
this.setupWebSocketListeners(ws);
|
|
452
|
-
}
|
|
453
|
-
setupWebSocketListeners(ws) {
|
|
454
|
-
ws.on('message', (data) => {
|
|
455
|
-
this.resetHeartbeatTimeout();
|
|
456
|
-
log.silly(PRE, 'initWebSocket() ws.on(message): %s', data);
|
|
457
|
-
if (data.toString() === 'pong') {
|
|
458
|
-
log.verbose('Received heartbeat');
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
try {
|
|
462
|
-
const payload = JSON.parse(data);
|
|
463
|
-
log.info('Received payload', JSON.stringify(payload));
|
|
464
|
-
void this.eventParse(payload);
|
|
465
|
-
}
|
|
466
|
-
catch (error) {
|
|
467
|
-
log.warn(PRE, 'initWebSocket() ws.on(message) exception: %s', error);
|
|
468
|
-
this.emit('error', error.message);
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
ws.on('error', (error) => {
|
|
472
|
-
if (error.code === 'ECONNREFUSED') {
|
|
473
|
-
log.verbose('Connection refused, potential reconnect scenario');
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
log.verbose(PRE, 'initWebSocket() ws.on(error) %s', error);
|
|
477
|
-
this.emit('error', error);
|
|
478
|
-
});
|
|
479
|
-
ws.on('close', (code, reason) => {
|
|
480
|
-
this.stopHeartbeat();
|
|
481
|
-
void this.handleWebSocketClose(code, reason);
|
|
482
|
-
});
|
|
483
|
-
this.startHeartbeat();
|
|
484
|
-
}
|
|
485
|
-
startHeartbeat() {
|
|
486
|
-
this.stopHeartbeat();
|
|
487
|
-
this.heartbeatTimer = setInterval(() => {
|
|
488
|
-
if (this.socket?.connected) {
|
|
489
|
-
try {
|
|
490
|
-
this.socket.publish(`aibotk/msg/${this.tokenInfo.guid}`, 'pong');
|
|
491
|
-
this.setHeartbeatTimeout();
|
|
492
|
-
}
|
|
493
|
-
catch (error) {
|
|
494
|
-
log.error('Failed to send heartbeat:', error);
|
|
495
|
-
void this.handleMqttClose();
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}, this.HEARTBEAT_INTERVAL);
|
|
499
|
-
}
|
|
500
|
-
stopHeartbeat() {
|
|
501
|
-
if (this.heartbeatTimer) {
|
|
502
|
-
clearInterval(this.heartbeatTimer);
|
|
503
|
-
this.heartbeatTimer = undefined;
|
|
504
|
-
}
|
|
505
|
-
if (this.heartbeatTimeoutTimer) {
|
|
506
|
-
clearTimeout(this.heartbeatTimeoutTimer);
|
|
507
|
-
this.heartbeatTimeoutTimer = undefined;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
setHeartbeatTimeout() {
|
|
511
|
-
if (this.heartbeatTimeoutTimer) {
|
|
512
|
-
clearTimeout(this.heartbeatTimeoutTimer);
|
|
513
|
-
}
|
|
514
|
-
this.heartbeatTimeoutTimer = setTimeout(() => {
|
|
515
|
-
log.warn('Heartbeat timeout, reconnecting...');
|
|
516
|
-
void this.handleMqttClose();
|
|
517
|
-
}, this.HEARTBEAT_TIMEOUT);
|
|
518
|
-
}
|
|
519
|
-
resetHeartbeatTimeout() {
|
|
520
|
-
if (this.heartbeatTimeoutTimer) {
|
|
521
|
-
clearTimeout(this.heartbeatTimeoutTimer);
|
|
522
|
-
this.heartbeatTimeoutTimer = undefined;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
async handleMqttClose() {
|
|
526
|
-
this.connectionStatus.status = 'disconnected';
|
|
527
|
-
log.warn('MQTT connection closed');
|
|
528
|
-
if (this.socket) {
|
|
529
|
-
this.socket.end();
|
|
530
|
-
this.socket = null;
|
|
531
|
-
}
|
|
532
|
-
await this.reconnectMqtt();
|
|
533
|
-
}
|
|
534
|
-
async reconnectMqtt() {
|
|
535
|
-
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
536
|
-
log.error('Max reconnect attempts reached. Stopping reconnection.');
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
const delay = Math.min(this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts), this.MAX_RECONNECT_DELAY);
|
|
540
|
-
this.reconnectAttempts++;
|
|
541
|
-
log.info(`Reconnecting in ${delay}ms (Attempt ${this.reconnectAttempts})`);
|
|
542
|
-
setTimeout(() => {
|
|
543
|
-
try {
|
|
544
|
-
void this.createMqttConnection();
|
|
545
|
-
}
|
|
546
|
-
catch (error) {
|
|
547
|
-
log.warn('Reconnection failed', error);
|
|
548
|
-
}
|
|
549
|
-
}, delay);
|
|
550
|
-
}
|
|
551
|
-
async handleWebSocketClose(code, reason) {
|
|
552
|
-
this.connectionStatus.status = 'disconnected';
|
|
553
|
-
log.warn(`WebSocket closed: Code ${code}, Reason ${reason}`);
|
|
554
|
-
if (this.socket) {
|
|
555
|
-
this.socket.close();
|
|
556
|
-
this.socket = null;
|
|
557
|
-
}
|
|
558
|
-
await this.reconnect();
|
|
559
|
-
}
|
|
560
|
-
async reconnect() {
|
|
561
|
-
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
562
|
-
log.error('Max reconnect attempts reached. Stopping reconnection.');
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
const delay = Math.min(this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts), this.MAX_RECONNECT_DELAY);
|
|
566
|
-
this.reconnectAttempts++;
|
|
567
|
-
log.info(`Reconnecting in ${delay}ms (Attempt ${this.reconnectAttempts})`);
|
|
568
|
-
setTimeout(async () => {
|
|
569
|
-
try {
|
|
570
|
-
await this.initServer();
|
|
571
|
-
}
|
|
572
|
-
catch (error) {
|
|
573
|
-
log.warn('Reconnection failed', error);
|
|
574
|
-
}
|
|
575
|
-
}, delay);
|
|
576
451
|
}
|
|
577
452
|
async eventParse(eventData) {
|
|
578
453
|
const notifyType = eventData.notify_type;
|
|
@@ -742,6 +617,10 @@ class Client extends EventEmitter {
|
|
|
742
617
|
}
|
|
743
618
|
}
|
|
744
619
|
async postData(data) {
|
|
620
|
+
if (this.hasExpired) {
|
|
621
|
+
log.error('Token已到期,无法提供服务');
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
745
624
|
const config = {
|
|
746
625
|
data: {
|
|
747
626
|
guid: this.tokenInfo.guid,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"puppet-matrix.d.ts","sourceRoot":"","sources":["../../../src/puppet-matrix.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,sBAAsB,CAAA;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAKhD,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExE,OAAO,MAAM,MAAM,6BAA6B,CAAA;AA4BhD,QAAA,MAAM,OAAO,QAAiC,CAAA;AAK9C,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,aAAa,GAAG;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED,cAAM,YAAa,SAAQ,MAAM,CAAC,MAAM;IAoBT,OAAO,EAAE,mBAAmB;IAlBzD,OAAO,CAAC,SAAS,CAAC,CAAc;IAChC,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,OAAO,CAAC,KAAK,CAAC,CAA4B;IAC1C,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,eAAe,CAAC,CAA+B;IACvD,OAAO,CAAC,eAAe,CAAC,CAAuC;IAC/D,OAAO,CAAC,eAAe,CAAC,CAAuC;IAC/D,OAAO,CAAC,sBAAsB,CAAC,CAAuC;IACtE,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,aAAa,CAA6B;IAClD,gBAAgC,OAAO,SAAU;gBAOpB,OAAO,GAAE,mBAA+C;IAuBrF,IAAW,MAAM,uBAEhB;IAEc,OAAO,IAAK,OAAO,CAAC,IAAI,CAAC;YAS1B,YAAY;
|
|
1
|
+
{"version":3,"file":"puppet-matrix.d.ts","sourceRoot":"","sources":["../../../src/puppet-matrix.ts"],"names":[],"mappings":"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"}
|
|
@@ -164,6 +164,12 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
164
164
|
}, 5000);
|
|
165
165
|
}
|
|
166
166
|
}));
|
|
167
|
+
this._client.on('expired', this.wrapAsync(async (expired) => {
|
|
168
|
+
if (expired) {
|
|
169
|
+
log.info(PRE, 'Token has expired');
|
|
170
|
+
void this.onStop();
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
167
173
|
}
|
|
168
174
|
addRunningPuppet(this);
|
|
169
175
|
void this.checkIsLogin();
|
|
@@ -364,6 +370,8 @@ class PuppetMatrix extends PUPPET.Puppet {
|
|
|
364
370
|
async _stopClient() {
|
|
365
371
|
this.__currentUserId = undefined;
|
|
366
372
|
this.__currentUserId = undefined;
|
|
373
|
+
this._client?.destroy();
|
|
374
|
+
this._client = undefined;
|
|
367
375
|
if (this._cacheMgr) {
|
|
368
376
|
log.info(PRE, 'colse cache');
|
|
369
377
|
await this._cacheMgr.close();
|
package/package.json
CHANGED
|
@@ -373,7 +373,7 @@ async function getAtWxidList (source: string): Promise<string[]> {
|
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
interface ConnectionStatus {
|
|
376
|
-
status: 'disconnected' | 'connected' | 'connecting'
|
|
376
|
+
status: 'disconnected' | 'connected' | 'connecting' | 'reconnecting';
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
async function getImageInfo (imageUrl: string) {
|
|
@@ -637,17 +637,13 @@ class Client extends EventEmitter {
|
|
|
637
637
|
|
|
638
638
|
private readonly options: PuppetMatrixOptions
|
|
639
639
|
private connectionStatus: ConnectionStatus = { status: 'disconnected' }
|
|
640
|
-
private readonly MAX_RECONNECT_ATTEMPTS = 10
|
|
641
|
-
private readonly INITIAL_RECONNECT_DELAY = 1000 // 1秒
|
|
642
|
-
private readonly MAX_RECONNECT_DELAY = 30000 // 30秒
|
|
643
|
-
private readonly HEARTBEAT_INTERVAL = 40 * 1000 // 1分钟心跳间隔
|
|
644
|
-
private readonly HEARTBEAT_TIMEOUT = 5000 // 5秒超时
|
|
645
|
-
private reconnectAttempts = 0
|
|
646
640
|
private heartbeatTimer?: any
|
|
641
|
+
private checkExpiredInterval?: any
|
|
647
642
|
private heartbeatTimeoutTimer?: any
|
|
648
643
|
private getQrcodeTimes = 0
|
|
649
644
|
private restoreTimes = 0
|
|
650
645
|
private maxRestoreTimes = 1
|
|
646
|
+
private hasExpired = false
|
|
651
647
|
socket: any
|
|
652
648
|
server: any
|
|
653
649
|
tokenInfo: any
|
|
@@ -664,6 +660,7 @@ class Client extends EventEmitter {
|
|
|
664
660
|
override emit(event: 'verify-code', verifyInfo: VerifyInfo): boolean;
|
|
665
661
|
override emit(event: 'update-contacts', contacts: ContactPayload[]): boolean;
|
|
666
662
|
override emit(event: 'room-join', info: any): boolean;
|
|
663
|
+
override emit(event: 'expired', info: boolean): boolean;
|
|
667
664
|
|
|
668
665
|
override emit (event: ClientEvent, ...args: any[]): boolean {
|
|
669
666
|
return super.emit(event, ...args)
|
|
@@ -684,6 +681,20 @@ class Client extends EventEmitter {
|
|
|
684
681
|
this.getQrcodeTimes = 0
|
|
685
682
|
this.restoreTimes = 0
|
|
686
683
|
this.maxRestoreTimes = 1
|
|
684
|
+
this.hasExpired = false
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
destroy () {
|
|
688
|
+
log.verbose(PRE, 'destroy()')
|
|
689
|
+
this.hasEmitLogout = false
|
|
690
|
+
this.socket && this.socket.end()
|
|
691
|
+
this.socket = null
|
|
692
|
+
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval)
|
|
693
|
+
this.checkExpiredInterval = undefined
|
|
694
|
+
this.heartbeatTimer && clearTimeout(this.heartbeatTimer)
|
|
695
|
+
this.heartbeatTimer = undefined
|
|
696
|
+
this.heartbeatTimeoutTimer && clearTimeout(this.heartbeatTimeoutTimer)
|
|
697
|
+
this.heartbeatTimeoutTimer = undefined
|
|
687
698
|
}
|
|
688
699
|
|
|
689
700
|
async getTokenInfo () {
|
|
@@ -691,6 +702,16 @@ class Client extends EventEmitter {
|
|
|
691
702
|
const res = await axios.get(`https://api-bot.aibotk.com/openapi/v1/token/info?secret=5be06b6f8d42a7&token=${this.options.token}`)
|
|
692
703
|
if (res.data.code === 0) {
|
|
693
704
|
this.tokenInfo = res.data.data
|
|
705
|
+
this.hasExpired = res.data?.data?.hasExpired
|
|
706
|
+
if (this.hasExpired) {
|
|
707
|
+
log.error('Token已到期,请及时续费')
|
|
708
|
+
this.checkExpiredInterval && clearInterval(this.checkExpiredInterval)
|
|
709
|
+
this.checkExpiredInterval = undefined
|
|
710
|
+
setTimeout(() => {
|
|
711
|
+
this.emit('expired', true)
|
|
712
|
+
}, 3000)
|
|
713
|
+
return false
|
|
714
|
+
}
|
|
694
715
|
return true
|
|
695
716
|
} else {
|
|
696
717
|
log.error('Token auth failed, reason: %s', res.data.message)
|
|
@@ -702,8 +723,16 @@ class Client extends EventEmitter {
|
|
|
702
723
|
}
|
|
703
724
|
}
|
|
704
725
|
|
|
726
|
+
checkHasExpired () {
|
|
727
|
+
this.checkExpiredInterval = setInterval(() => {
|
|
728
|
+
log.info('checkHasExpired')
|
|
729
|
+
void this.getTokenInfo()
|
|
730
|
+
}, 1000 * 60 * 60 * 12)
|
|
731
|
+
}
|
|
732
|
+
|
|
705
733
|
async initServer () {
|
|
706
734
|
await this.getTokenInfo()
|
|
735
|
+
this.checkHasExpired()
|
|
707
736
|
if (this.socket) {
|
|
708
737
|
log.error('socket had already been opened!')
|
|
709
738
|
return
|
|
@@ -713,6 +742,9 @@ class Client extends EventEmitter {
|
|
|
713
742
|
}
|
|
714
743
|
|
|
715
744
|
async createMqttConnection (): Promise<void> {
|
|
745
|
+
if (this.hasExpired) {
|
|
746
|
+
return
|
|
747
|
+
}
|
|
716
748
|
if (!this.tokenInfo) {
|
|
717
749
|
log.error('Token info not available')
|
|
718
750
|
return
|
|
@@ -734,12 +766,11 @@ class Client extends EventEmitter {
|
|
|
734
766
|
|
|
735
767
|
client.on('connect', () => {
|
|
736
768
|
this.connectionStatus.status = 'connected'
|
|
737
|
-
this.reconnectAttempts = 0
|
|
738
769
|
log.info('MQTT connection opened')
|
|
739
770
|
this.socket = client
|
|
740
771
|
|
|
741
772
|
// 订阅主题
|
|
742
|
-
client.subscribe(`aibotk/msg/${this.tokenInfo.guid}`, (err) => {
|
|
773
|
+
client.subscribe(`aibotk/msg/${this.tokenInfo.guid}`, (err: any) => {
|
|
743
774
|
if (err) {
|
|
744
775
|
log.error('Failed to subscribe to topic', err)
|
|
745
776
|
} else {
|
|
@@ -755,13 +786,14 @@ class Client extends EventEmitter {
|
|
|
755
786
|
client.on('close', () => {
|
|
756
787
|
this.connectionStatus.status = 'disconnected'
|
|
757
788
|
log.warn('MQTT connection closed')
|
|
758
|
-
this.socket = null
|
|
759
|
-
void this.reconnect()
|
|
760
789
|
})
|
|
761
790
|
|
|
762
|
-
client.on('
|
|
763
|
-
this.
|
|
791
|
+
client.on('reconnect', () => {
|
|
792
|
+
this.connectionStatus.status = 'reconnecting'
|
|
793
|
+
log.warn('MQTT connection Reconnecting...')
|
|
794
|
+
})
|
|
764
795
|
|
|
796
|
+
client.on('message', (topic, message) => {
|
|
765
797
|
log.verbose(PRE, 'Received message on topic %s: %s', topic, message.toString())
|
|
766
798
|
if (message.toString() === 'ping' || message.toString() === 'pong') {
|
|
767
799
|
log.verbose('Received heartbeat')
|
|
@@ -780,206 +812,6 @@ class Client extends EventEmitter {
|
|
|
780
812
|
})
|
|
781
813
|
|
|
782
814
|
this.socket = client
|
|
783
|
-
this.startHeartbeat()
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
async createWebSocket (): Promise<void> {
|
|
787
|
-
if (!this.tokenInfo) {
|
|
788
|
-
log.error('Token info not available')
|
|
789
|
-
return
|
|
790
|
-
}
|
|
791
|
-
const ws = new WebSocket(
|
|
792
|
-
`${this.tokenInfo.endpoint}?guid=${this.tokenInfo.guid}`,
|
|
793
|
-
{
|
|
794
|
-
perMessageDeflate: true,
|
|
795
|
-
maxPayload: 100 * 1024 * 1024,
|
|
796
|
-
},
|
|
797
|
-
)
|
|
798
|
-
|
|
799
|
-
// 连接建立前的 Promise
|
|
800
|
-
await new Promise<void>((resolve, reject) => {
|
|
801
|
-
ws.once('open', () => {
|
|
802
|
-
this.connectionStatus.status = 'connected'
|
|
803
|
-
this.reconnectAttempts = 0
|
|
804
|
-
log.info('WebSocket connection opened')
|
|
805
|
-
resolve()
|
|
806
|
-
})
|
|
807
|
-
|
|
808
|
-
ws.once('error', (error: any) => {
|
|
809
|
-
log.warn('WebSocket connection error', error)
|
|
810
|
-
reject(error)
|
|
811
|
-
})
|
|
812
|
-
|
|
813
|
-
ws.once('close', (code: any, reason: any) => {
|
|
814
|
-
void this.handleWebSocketClose(code, reason)
|
|
815
|
-
reject(new Error(`WebSocket closed: ${code} - ${reason}`))
|
|
816
|
-
})
|
|
817
|
-
})
|
|
818
|
-
this.socket = ws
|
|
819
|
-
|
|
820
|
-
// 设置事件处理器
|
|
821
|
-
this.setupWebSocketListeners(ws)
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
private setupWebSocketListeners (ws: WebSocket): void {
|
|
825
|
-
// 消息处理
|
|
826
|
-
ws.on('message', (data: string) => {
|
|
827
|
-
this.resetHeartbeatTimeout() // 收到任何消息都重置心跳超时
|
|
828
|
-
log.silly(PRE, 'initWebSocket() ws.on(message): %s', data)
|
|
829
|
-
if (data.toString() === 'pong') {
|
|
830
|
-
log.verbose('Received heartbeat')
|
|
831
|
-
return
|
|
832
|
-
}
|
|
833
|
-
try {
|
|
834
|
-
const payload = JSON.parse(data)
|
|
835
|
-
log.info('Received payload', JSON.stringify(payload))
|
|
836
|
-
void this.eventParse(payload)
|
|
837
|
-
} catch (error) {
|
|
838
|
-
log.warn(PRE, 'initWebSocket() ws.on(message) exception: %s', error)
|
|
839
|
-
// @ts-ignore
|
|
840
|
-
this.emit('error', (error as Error).message)
|
|
841
|
-
}
|
|
842
|
-
})
|
|
843
|
-
|
|
844
|
-
// 错误处理
|
|
845
|
-
ws.on('error', (error: Error) => {
|
|
846
|
-
if ((error as any).code === 'ECONNREFUSED') {
|
|
847
|
-
log.verbose('Connection refused, potential reconnect scenario')
|
|
848
|
-
return
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
log.verbose(PRE, 'initWebSocket() ws.on(error) %s', error)
|
|
852
|
-
// @ts-ignore
|
|
853
|
-
this.emit('error', error)
|
|
854
|
-
})
|
|
855
|
-
|
|
856
|
-
// 关闭处理
|
|
857
|
-
ws.on('close', (code:any, reason: any) => {
|
|
858
|
-
this.stopHeartbeat()
|
|
859
|
-
void this.handleWebSocketClose(code, reason)
|
|
860
|
-
})
|
|
861
|
-
// 启动心跳
|
|
862
|
-
this.startHeartbeat()
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
private startHeartbeat (): void {
|
|
866
|
-
this.stopHeartbeat() // 确保清理现有定时器
|
|
867
|
-
this.heartbeatTimer = setInterval(() => {
|
|
868
|
-
if (this.socket?.connected) {
|
|
869
|
-
try {
|
|
870
|
-
this.socket.publish(`aibotk/msg/${this.tokenInfo.guid}`, 'pong')
|
|
871
|
-
this.setHeartbeatTimeout()
|
|
872
|
-
} catch (error) {
|
|
873
|
-
log.error('Failed to send heartbeat:', error)
|
|
874
|
-
void this.handleMqttClose()
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}, this.HEARTBEAT_INTERVAL)
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
private stopHeartbeat (): void {
|
|
881
|
-
if (this.heartbeatTimer) {
|
|
882
|
-
// @ts-ignore
|
|
883
|
-
clearInterval(this.heartbeatTimer)
|
|
884
|
-
this.heartbeatTimer = undefined
|
|
885
|
-
}
|
|
886
|
-
if (this.heartbeatTimeoutTimer) {
|
|
887
|
-
// @ts-ignore
|
|
888
|
-
clearTimeout(this.heartbeatTimeoutTimer)
|
|
889
|
-
this.heartbeatTimeoutTimer = undefined
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
private setHeartbeatTimeout (): void {
|
|
894
|
-
if (this.heartbeatTimeoutTimer) {
|
|
895
|
-
// @ts-ignore
|
|
896
|
-
clearTimeout(this.heartbeatTimeoutTimer)
|
|
897
|
-
}
|
|
898
|
-
this.heartbeatTimeoutTimer = setTimeout(() => {
|
|
899
|
-
log.warn('Heartbeat timeout, reconnecting...')
|
|
900
|
-
void this.handleMqttClose()
|
|
901
|
-
}, this.HEARTBEAT_TIMEOUT)
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
private resetHeartbeatTimeout (): void {
|
|
905
|
-
if (this.heartbeatTimeoutTimer) {
|
|
906
|
-
// @ts-ignore
|
|
907
|
-
clearTimeout(this.heartbeatTimeoutTimer)
|
|
908
|
-
this.heartbeatTimeoutTimer = undefined
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
private async handleMqttClose () {
|
|
913
|
-
this.connectionStatus.status = 'disconnected'
|
|
914
|
-
log.warn('MQTT connection closed')
|
|
915
|
-
if (this.socket) {
|
|
916
|
-
this.socket.end()
|
|
917
|
-
this.socket = null
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// 触发重连
|
|
921
|
-
await this.reconnectMqtt()
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
private async reconnectMqtt (): Promise<void> {
|
|
925
|
-
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
926
|
-
log.error('Max reconnect attempts reached. Stopping reconnection.')
|
|
927
|
-
return
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
// 指数退避重连策略
|
|
931
|
-
const delay = Math.min(
|
|
932
|
-
this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts),
|
|
933
|
-
this.MAX_RECONNECT_DELAY,
|
|
934
|
-
)
|
|
935
|
-
|
|
936
|
-
this.reconnectAttempts++
|
|
937
|
-
log.info(`Reconnecting in ${delay}ms (Attempt ${this.reconnectAttempts})`)
|
|
938
|
-
setTimeout(() => {
|
|
939
|
-
try {
|
|
940
|
-
void this.createMqttConnection()
|
|
941
|
-
} catch (error) {
|
|
942
|
-
log.warn('Reconnection failed', error)
|
|
943
|
-
}
|
|
944
|
-
}, delay)
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
private async handleWebSocketClose (code?: number, reason?: Buffer | String) {
|
|
948
|
-
this.connectionStatus.status = 'disconnected'
|
|
949
|
-
log.warn(`WebSocket closed: Code ${code}, Reason ${reason}`)
|
|
950
|
-
if (this.socket) {
|
|
951
|
-
this.socket.close()
|
|
952
|
-
this.socket = null
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
// 触发重连
|
|
956
|
-
await this.reconnect()
|
|
957
|
-
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
private async reconnect (): Promise<void> {
|
|
961
|
-
if (this.reconnectAttempts >= this.MAX_RECONNECT_ATTEMPTS) {
|
|
962
|
-
log.error('Max reconnect attempts reached. Stopping reconnection.')
|
|
963
|
-
return
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// 指数退避重连策略
|
|
967
|
-
const delay = Math.min(
|
|
968
|
-
this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts),
|
|
969
|
-
this.MAX_RECONNECT_DELAY,
|
|
970
|
-
)
|
|
971
|
-
|
|
972
|
-
this.reconnectAttempts++
|
|
973
|
-
log.info(`Reconnecting in ${delay}ms (Attempt ${this.reconnectAttempts})`)
|
|
974
|
-
|
|
975
|
-
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
976
|
-
setTimeout(async () => {
|
|
977
|
-
try {
|
|
978
|
-
await this.initServer()
|
|
979
|
-
} catch (error) {
|
|
980
|
-
log.warn('Reconnection failed', error)
|
|
981
|
-
}
|
|
982
|
-
}, delay)
|
|
983
815
|
}
|
|
984
816
|
|
|
985
817
|
async eventParse (eventData: any) {
|
|
@@ -1179,6 +1011,10 @@ class Client extends EventEmitter {
|
|
|
1179
1011
|
}
|
|
1180
1012
|
|
|
1181
1013
|
async postData (data: any) {
|
|
1014
|
+
if (this.hasExpired) {
|
|
1015
|
+
log.error('Token已到期,无法提供服务')
|
|
1016
|
+
return
|
|
1017
|
+
}
|
|
1182
1018
|
const config: any = {
|
|
1183
1019
|
data: {
|
|
1184
1020
|
guid: this.tokenInfo.guid,
|