@mtcute/core 0.2.2 → 0.3.0
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/cjs/base-client.d.ts +33 -166
- package/cjs/base-client.js +70 -48
- package/cjs/base-client.js.map +1 -1
- package/cjs/base-client.types.d.ts +153 -0
- package/cjs/base-client.types.js +3 -0
- package/cjs/base-client.types.js.map +1 -0
- package/cjs/index.d.ts +1 -0
- package/cjs/index.js +1 -0
- package/cjs/index.js.map +1 -1
- package/cjs/network/mtproto-session.d.ts +10 -2
- package/cjs/network/mtproto-session.js +33 -3
- package/cjs/network/mtproto-session.js.map +1 -1
- package/cjs/network/multi-session-connection.d.ts +1 -1
- package/cjs/network/multi-session-connection.js +4 -3
- package/cjs/network/multi-session-connection.js.map +1 -1
- package/cjs/network/network-manager.d.ts +23 -0
- package/cjs/network/network-manager.js +28 -8
- package/cjs/network/network-manager.js.map +1 -1
- package/cjs/network/server-salt.d.ts +12 -0
- package/cjs/network/server-salt.js +45 -0
- package/cjs/network/server-salt.js.map +1 -0
- package/cjs/network/session-connection.d.ts +6 -1
- package/cjs/network/session-connection.js +179 -54
- package/cjs/network/session-connection.js.map +1 -1
- package/cjs/storage/abstract.d.ts +12 -1
- package/cjs/storage/abstract.js.map +1 -1
- package/cjs/storage/idb.d.ts +3 -1
- package/cjs/storage/idb.js +17 -0
- package/cjs/storage/idb.js.map +1 -1
- package/cjs/storage/index.d.ts +1 -0
- package/cjs/storage/index.js +1 -0
- package/cjs/storage/index.js.map +1 -1
- package/cjs/storage/json.js +1 -0
- package/cjs/storage/json.js.map +1 -1
- package/cjs/storage/memory.d.ts +5 -2
- package/cjs/storage/memory.js +16 -2
- package/cjs/storage/memory.js.map +1 -1
- package/cjs/storage/memory.test.js +2 -1
- package/cjs/storage/memory.test.js.map +1 -1
- package/cjs/utils/logger.js +8 -2
- package/cjs/utils/logger.js.map +1 -1
- package/cjs/utils/logger.test.js +12 -0
- package/cjs/utils/logger.test.js.map +1 -1
- package/cjs/utils/long-utils.d.ts +5 -0
- package/cjs/utils/long-utils.js +13 -1
- package/cjs/utils/long-utils.js.map +1 -1
- package/cjs/utils/sorted-array.js +1 -0
- package/cjs/utils/sorted-array.js.map +1 -1
- package/cjs/utils/type-assertions.d.ts +1 -0
- package/cjs/utils/type-assertions.js +7 -1
- package/cjs/utils/type-assertions.js.map +1 -1
- package/esm/base-client.d.ts +33 -166
- package/esm/base-client.js +70 -48
- package/esm/base-client.js.map +1 -1
- package/esm/base-client.types.d.ts +153 -0
- package/esm/base-client.types.js +2 -0
- package/esm/base-client.types.js.map +1 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/network/mtproto-session.d.ts +10 -2
- package/esm/network/mtproto-session.js +34 -4
- package/esm/network/mtproto-session.js.map +1 -1
- package/esm/network/multi-session-connection.d.ts +1 -1
- package/esm/network/multi-session-connection.js +4 -3
- package/esm/network/multi-session-connection.js.map +1 -1
- package/esm/network/network-manager.d.ts +23 -0
- package/esm/network/network-manager.js +29 -9
- package/esm/network/network-manager.js.map +1 -1
- package/esm/network/server-salt.d.ts +12 -0
- package/esm/network/server-salt.js +38 -0
- package/esm/network/server-salt.js.map +1 -0
- package/esm/network/session-connection.d.ts +6 -1
- package/esm/network/session-connection.js +179 -54
- package/esm/network/session-connection.js.map +1 -1
- package/esm/storage/abstract.d.ts +12 -1
- package/esm/storage/abstract.js.map +1 -1
- package/esm/storage/idb.d.ts +3 -1
- package/esm/storage/idb.js +17 -0
- package/esm/storage/idb.js.map +1 -1
- package/esm/storage/index.d.ts +1 -0
- package/esm/storage/index.js +1 -0
- package/esm/storage/index.js.map +1 -1
- package/esm/storage/json.js +1 -0
- package/esm/storage/json.js.map +1 -1
- package/esm/storage/memory.d.ts +5 -2
- package/esm/storage/memory.js +16 -2
- package/esm/storage/memory.js.map +1 -1
- package/esm/storage/memory.test.js +2 -1
- package/esm/storage/memory.test.js.map +1 -1
- package/esm/utils/logger.js +8 -2
- package/esm/utils/logger.js.map +1 -1
- package/esm/utils/logger.test.js +12 -0
- package/esm/utils/logger.test.js.map +1 -1
- package/esm/utils/long-utils.d.ts +5 -0
- package/esm/utils/long-utils.js +11 -0
- package/esm/utils/long-utils.js.map +1 -1
- package/esm/utils/sorted-array.js +1 -0
- package/esm/utils/sorted-array.js.map +1 -1
- package/esm/utils/type-assertions.d.ts +1 -0
- package/esm/utils/type-assertions.js +5 -0
- package/esm/utils/type-assertions.js.map +1 -1
- package/package.json +4 -4
|
@@ -16,7 +16,9 @@ const error_reporting_js_1 = require("../utils/platform/error-reporting.js");
|
|
|
16
16
|
const authorization_js_1 = require("./authorization.js");
|
|
17
17
|
const persistent_connection_js_1 = require("./persistent-connection.js");
|
|
18
18
|
const abstract_js_1 = require("./transports/abstract.js");
|
|
19
|
-
const TEMP_AUTH_KEY_EXPIRY = 86400;
|
|
19
|
+
const TEMP_AUTH_KEY_EXPIRY = 86400; // 24 hours
|
|
20
|
+
const PING_INTERVAL = 60000; // 1 minute
|
|
21
|
+
const GET_STATE_INTERVAL = 1500; // 1.5 seconds
|
|
20
22
|
// destroy_auth_key#d1435160 = DestroyAuthKeyRes;
|
|
21
23
|
// const DESTROY_AUTH_KEY = Buffer.from('605134d1', 'hex')
|
|
22
24
|
// gzip_packed#3072cfa1 packed_data:string = Object;
|
|
@@ -25,6 +27,9 @@ const GZIP_PACKED_ID = 0x3072cfa1;
|
|
|
25
27
|
const MSG_CONTAINER_ID = 0x73f1f8dc;
|
|
26
28
|
// rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult;
|
|
27
29
|
const RPC_RESULT_ID = 0xf35c6d01;
|
|
30
|
+
// invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
|
31
|
+
const INVOKE_AFTER_MSG_ID = 0xcb9f372d;
|
|
32
|
+
const INVOKE_AFTER_MSG_SIZE = 12; // 8 (invokeAfterMsg) + 4 (msg_id)
|
|
28
33
|
function makeNiceStack(error, stack, method) {
|
|
29
34
|
error.stack = `RpcError (${error.code} ${error.text}): ${error.message}\n at ${method}\n${stack
|
|
30
35
|
.split('\n')
|
|
@@ -50,6 +55,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
50
55
|
this._readerMap = params.readerMap;
|
|
51
56
|
this._writerMap = params.writerMap;
|
|
52
57
|
this._crypto = params.crypto;
|
|
58
|
+
this._salts = params.salts;
|
|
53
59
|
this._handleRawMessage = this._handleRawMessage.bind(this);
|
|
54
60
|
}
|
|
55
61
|
getAuthKey(temp = false) {
|
|
@@ -87,6 +93,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
87
93
|
reset(forever = false) {
|
|
88
94
|
this._session.initConnectionCalled = false;
|
|
89
95
|
this._flushTimer.reset();
|
|
96
|
+
this._salts.isFetching = false;
|
|
90
97
|
if (forever) {
|
|
91
98
|
this.removeAllListeners();
|
|
92
99
|
}
|
|
@@ -188,7 +195,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
188
195
|
(0, authorization_js_1.doAuthorization)(this, this._crypto)
|
|
189
196
|
.then(([authKey, serverSalt, timeOffset]) => {
|
|
190
197
|
this._session._authKey.setup(authKey);
|
|
191
|
-
this.
|
|
198
|
+
this._salts.currentSalt = serverSalt;
|
|
192
199
|
this._session._timeOffset = timeOffset;
|
|
193
200
|
this._session.authorizationPending = false;
|
|
194
201
|
this.emit('key-change', authKey);
|
|
@@ -306,7 +313,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
306
313
|
// and primary is not immediately forgot because messages using it may still be in flight)
|
|
307
314
|
this._session._authKeyTempSecondary = this._session._authKeyTemp;
|
|
308
315
|
this._session._authKeyTemp = tempKey;
|
|
309
|
-
this.
|
|
316
|
+
this._salts.currentSalt = tempServerSalt;
|
|
310
317
|
this.log.debug('temp key has been bound, exp = %d', inner.expiresAt);
|
|
311
318
|
this._isPfsBindingPending = false;
|
|
312
319
|
this._isPfsBindingPendingInBackground = false;
|
|
@@ -445,7 +452,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
445
452
|
this._onMsgsStateInfo(message);
|
|
446
453
|
break;
|
|
447
454
|
case 'mt_future_salts':
|
|
448
|
-
|
|
455
|
+
this._onFutureSalts(message);
|
|
449
456
|
break;
|
|
450
457
|
case 'mt_msgs_state_req':
|
|
451
458
|
case 'mt_msg_resend_req':
|
|
@@ -526,7 +533,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
526
533
|
this.log.debug('failed to parse rpc_result for cancel request %l, ignoring', reqMsgId);
|
|
527
534
|
return;
|
|
528
535
|
}
|
|
529
|
-
this.log.debug('received %s for cancelled request %l: %j', result._, reqMsgId);
|
|
536
|
+
this.log.debug('received %s for cancelled request %l: %j', result._, reqMsgId, result);
|
|
530
537
|
this._onMessageAcked(reqMsgId);
|
|
531
538
|
return;
|
|
532
539
|
}
|
|
@@ -552,6 +559,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
552
559
|
}
|
|
553
560
|
// initConnection call was definitely received and
|
|
554
561
|
// processed by the server, so we no longer need to use it
|
|
562
|
+
// todo: is this the case with failed invokeAfterMsg(s) as well?
|
|
555
563
|
if (rpc.initConn) {
|
|
556
564
|
this._session.initConnectionCalled = true;
|
|
557
565
|
}
|
|
@@ -560,37 +568,61 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
560
568
|
if (result._ === 'mt_rpc_error') {
|
|
561
569
|
const res = result;
|
|
562
570
|
this.log.debug('received rpc_error [%d:%s] for %l (%s)', res.errorCode, res.errorMessage, reqMsgId, rpc.method);
|
|
563
|
-
if (res.errorMessage === 'AUTH_KEY_PERM_EMPTY') {
|
|
564
|
-
// happens when temp auth key is not yet bound
|
|
565
|
-
// this shouldn't happen as we block any outbound communications
|
|
566
|
-
// until the temp key is derived and bound.
|
|
567
|
-
//
|
|
568
|
-
// i think it is also possible for the error to be returned
|
|
569
|
-
// when the temp key has expired, but this still shouldn't happen
|
|
570
|
-
// but this is tg, so something may go wrong, and we will receive this as an error
|
|
571
|
-
// (for god's sake why is this not in mtproto and instead hacked into the app layer)
|
|
572
|
-
this._authorizePfs();
|
|
573
|
-
this._onMessageFailed(reqMsgId, 'AUTH_KEY_PERM_EMPTY', true);
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
if (res.errorMessage === 'CONNECTION_NOT_INITED') {
|
|
577
|
-
// this seems to sometimes happen when using pfs
|
|
578
|
-
// no idea why, but tdlib also seems to handle these, so whatever
|
|
579
|
-
this._session.initConnectionCalled = false;
|
|
580
|
-
this._onMessageFailed(reqMsgId, res.errorMessage, true);
|
|
581
|
-
// just setting this flag is not enough because the message
|
|
582
|
-
// is already serialized, so we do this awesome hack
|
|
583
|
-
this.sendRpc({ _: 'help.getNearestDc' })
|
|
584
|
-
.then(() => {
|
|
585
|
-
this.log.debug('additional help.getNearestDc for initConnection ok');
|
|
586
|
-
})
|
|
587
|
-
.catch((err) => {
|
|
588
|
-
this.log.debug('additional help.getNearestDc for initConnection error: %s', err);
|
|
589
|
-
});
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
571
|
if (rpc.cancelled)
|
|
593
572
|
return;
|
|
573
|
+
switch (res.errorMessage) {
|
|
574
|
+
case 'AUTH_KEY_PERM_EMPTY':
|
|
575
|
+
// happens when temp auth key is not yet bound
|
|
576
|
+
// this shouldn't happen as we block any outbound communications
|
|
577
|
+
// until the temp key is derived and bound.
|
|
578
|
+
//
|
|
579
|
+
// i think it is also possible for the error to be returned
|
|
580
|
+
// when the temp key has expired, but this still shouldn't happen
|
|
581
|
+
// but this is tg, so something may go wrong, and we will receive this as an error
|
|
582
|
+
// (for god's sake why is this not in mtproto and instead hacked into the app layer)
|
|
583
|
+
this._authorizePfs();
|
|
584
|
+
this._onMessageFailed(reqMsgId, 'AUTH_KEY_PERM_EMPTY', true);
|
|
585
|
+
return;
|
|
586
|
+
case 'CONNECTION_NOT_INITED': {
|
|
587
|
+
// this seems to sometimes happen when using pfs
|
|
588
|
+
// no idea why, but tdlib also seems to handle these, so whatever
|
|
589
|
+
this._session.initConnectionCalled = false;
|
|
590
|
+
this._onMessageFailed(reqMsgId, res.errorMessage, true);
|
|
591
|
+
// just setting this flag is not enough because the message
|
|
592
|
+
// is already serialized, so we do this awesome hack
|
|
593
|
+
this.sendRpc({ _: 'help.getNearestDc' })
|
|
594
|
+
.then(() => {
|
|
595
|
+
this.log.debug('additional help.getNearestDc for initConnection ok');
|
|
596
|
+
})
|
|
597
|
+
.catch((err) => {
|
|
598
|
+
this.log.debug('additional help.getNearestDc for initConnection error: %s', err);
|
|
599
|
+
});
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
case 'MSG_WAIT_TIMEOUT':
|
|
603
|
+
case 'MSG_WAIT_FAILED': {
|
|
604
|
+
if (!rpc.invokeAfter) {
|
|
605
|
+
this.log.warn('received %s for non-chained request %l', res.errorMessage, reqMsgId);
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
// in some cases, MSG_WAIT_TIMEOUT is returned instead of MSG_WAIT_FAILED when one of the deps
|
|
609
|
+
// failed with MSG_WAIT_TIMEOUT. i have no clue why, this makes zero sense, but what fucking ever
|
|
610
|
+
//
|
|
611
|
+
// this basically means we can't handle a timeout any different than a general failure,
|
|
612
|
+
// because the timeout might not refer to the immediate `.invokeAfter` message, but to
|
|
613
|
+
// its arbitrary-depth dependency, so we indeed have to wait for the message ourselves...
|
|
614
|
+
if (this._session.pendingMessages.has(rpc.invokeAfter)) {
|
|
615
|
+
// the dependency is still pending, postpone the processing
|
|
616
|
+
this.log.debug('chain %s: waiting for %l before processing %l', rpc.chainId, rpc.invokeAfter, reqMsgId);
|
|
617
|
+
this._session.getPendingChainedFails(rpc.chainId).insert(rpc);
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
this._session.chains.delete(rpc.chainId);
|
|
621
|
+
this._onMessageFailed(reqMsgId, 'MSG_WAIT_FAILED', true);
|
|
622
|
+
}
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
594
626
|
const error = tl_1.tl.RpcError.fromTl(res);
|
|
595
627
|
if (this.params.niceStacks !== false) {
|
|
596
628
|
makeNiceStack(error, rpc.stack, rpc.method);
|
|
@@ -606,9 +638,31 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
606
638
|
return;
|
|
607
639
|
rpc.promise.resolve(result);
|
|
608
640
|
}
|
|
641
|
+
if (rpc.chainId) {
|
|
642
|
+
this._processPendingChainedFails(rpc.chainId, reqMsgId);
|
|
643
|
+
}
|
|
609
644
|
this._onMessageAcked(reqMsgId);
|
|
610
645
|
this._session.pendingMessages.delete(reqMsgId);
|
|
611
646
|
}
|
|
647
|
+
_processPendingChainedFails(chainId, sinceMsgId) {
|
|
648
|
+
// sinceMsgId was already definitely received and contained an error.
|
|
649
|
+
// we should now re-send all the pending MSG_WAIT_FAILED after it
|
|
650
|
+
this._session.removeFromChain(chainId, sinceMsgId);
|
|
651
|
+
const oldPending = this._session.chainsPendingFails.get(chainId);
|
|
652
|
+
if (!oldPending?.length) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const idx = oldPending.index({ invokeAfter: sinceMsgId }, true);
|
|
656
|
+
if (idx === -1)
|
|
657
|
+
return;
|
|
658
|
+
const toFail = oldPending.raw.splice(idx);
|
|
659
|
+
this.log.debug('chain %s: failing %d dependant messages: %L', chainId, toFail.length, toFail);
|
|
660
|
+
// we're failing the rest of the chain, including the last message
|
|
661
|
+
this._session.chains.delete(chainId);
|
|
662
|
+
for (const rpc of toFail) {
|
|
663
|
+
this._onMessageFailed(rpc.msgId, 'MSG_WAIT_FAILED', true);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
612
666
|
_onMessageAcked(msgId, inContainer = false) {
|
|
613
667
|
const msg = this._session.pendingMessages.get(msgId);
|
|
614
668
|
if (!msg) {
|
|
@@ -640,6 +694,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
640
694
|
break;
|
|
641
695
|
}
|
|
642
696
|
case 'bind':
|
|
697
|
+
case 'cancel':
|
|
643
698
|
break; // do nothing, wait for the result
|
|
644
699
|
default:
|
|
645
700
|
if (!inContainer) {
|
|
@@ -714,6 +769,12 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
714
769
|
case 'bind':
|
|
715
770
|
this.log.debug('temp key binding request %l failed because of %s, retrying', msgId, reason);
|
|
716
771
|
msgInfo.promise.reject(Error(reason));
|
|
772
|
+
break;
|
|
773
|
+
case 'future_salts':
|
|
774
|
+
this.log.debug('future_salts request %l failed because of %s, will retry', msgId, reason);
|
|
775
|
+
this._salts.isFetching = false;
|
|
776
|
+
// this is enough to make it retry on the next flush.
|
|
777
|
+
break;
|
|
717
778
|
}
|
|
718
779
|
this._session.pendingMessages.delete(msgId);
|
|
719
780
|
}
|
|
@@ -743,7 +804,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
743
804
|
this._session.resetLastPing();
|
|
744
805
|
}
|
|
745
806
|
_onBadServerSalt(msg) {
|
|
746
|
-
this.
|
|
807
|
+
this._salts.currentSalt = msg.newServerSalt;
|
|
747
808
|
this._onMessageFailed(msg.badMsgId, 'bad_server_salt');
|
|
748
809
|
}
|
|
749
810
|
_onBadMsgNotification(msgId, msg) {
|
|
@@ -781,7 +842,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
781
842
|
// just been established, and the client will fetch them anyways
|
|
782
843
|
this.emit('update', { _: 'updatesTooLong' });
|
|
783
844
|
}
|
|
784
|
-
this.
|
|
845
|
+
this._salts.currentSalt = serverSalt;
|
|
785
846
|
this.log.debug('received new_session_created, uid = %l, first msg_id = %l', uniqueId, firstMsgId);
|
|
786
847
|
for (const msgId of this._session.pendingMessages.keys()) {
|
|
787
848
|
const val = this._session.pendingMessages.get(msgId);
|
|
@@ -820,7 +881,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
820
881
|
case 2:
|
|
821
882
|
case 3:
|
|
822
883
|
// message wasn't received by the server
|
|
823
|
-
this._onMessageFailed(msgId, `message info state ${status}`);
|
|
884
|
+
return this._onMessageFailed(msgId, `message info state ${status}`);
|
|
824
885
|
break;
|
|
825
886
|
case 0:
|
|
826
887
|
if (!answerMsgId.isZero()) {
|
|
@@ -839,6 +900,10 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
839
900
|
this._flushTimer.emitWhenIdle();
|
|
840
901
|
return;
|
|
841
902
|
}
|
|
903
|
+
if (answerMsgId.isZero()) {
|
|
904
|
+
this.log.debug('received message info for %l: message is still pending (status = %d)', msgId, status);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
842
907
|
this.log.debug('received message info for %l, and answer (%l) was already received', msgId, answerMsgId);
|
|
843
908
|
}
|
|
844
909
|
_onMessagesInfo(msgIds, info) {
|
|
@@ -861,6 +926,21 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
861
926
|
}
|
|
862
927
|
this._onMessagesInfo(info.msgIds, msg.info);
|
|
863
928
|
}
|
|
929
|
+
_onFutureSalts(msg) {
|
|
930
|
+
const info = this._session.pendingMessages.get(msg.reqMsgId);
|
|
931
|
+
if (!info) {
|
|
932
|
+
this.log.warn('received future_salts to unknown request %l', msg.reqMsgId);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
if (info._ !== 'future_salts') {
|
|
936
|
+
this.log.warn('received future_salts to %s query %l', info._, msg.reqMsgId);
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
this.log.debug('received future_salts: %d salts', msg.salts.length);
|
|
940
|
+
this._salts.isFetching = false;
|
|
941
|
+
this._salts.setFutureSalts(msg.salts.slice());
|
|
942
|
+
this.emit('future-salts', msg.salts);
|
|
943
|
+
}
|
|
864
944
|
_onDestroySessionResult(msg) {
|
|
865
945
|
const reqMsgId = this._session.destroySessionIdToMsgId.get(msg.sessionId);
|
|
866
946
|
if (!reqMsgId) {
|
|
@@ -892,7 +972,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
892
972
|
this._flushTimer.emitWhenIdle();
|
|
893
973
|
}
|
|
894
974
|
}
|
|
895
|
-
sendRpc(request, stack, timeout, abortSignal) {
|
|
975
|
+
sendRpc(request, stack, timeout, abortSignal, chainId) {
|
|
896
976
|
if (this._usable && this.params.inactivityTimeout) {
|
|
897
977
|
this._rescheduleInactivity();
|
|
898
978
|
}
|
|
@@ -963,7 +1043,9 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
963
1043
|
// we will need to know size of gzip_packed overhead in _flush()
|
|
964
1044
|
gzipOverhead: shouldGzip ? 4 + tl_runtime_1.TlSerializationCounter.countBytesOverhead(content.length) : 0,
|
|
965
1045
|
initConn,
|
|
1046
|
+
chainId,
|
|
966
1047
|
// setting them as well so jit can optimize stuff
|
|
1048
|
+
invokeAfter: undefined,
|
|
967
1049
|
sent: undefined,
|
|
968
1050
|
done: undefined,
|
|
969
1051
|
getState: undefined,
|
|
@@ -1010,6 +1092,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1010
1092
|
rpc.cancelled = true;
|
|
1011
1093
|
if (rpc.msgId) {
|
|
1012
1094
|
this._session.queuedCancelReq.push(rpc.msgId);
|
|
1095
|
+
this._session.getStateSchedule.remove(rpc);
|
|
1013
1096
|
this._flushTimer.emitWhenIdle();
|
|
1014
1097
|
}
|
|
1015
1098
|
else {
|
|
@@ -1053,14 +1136,10 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1053
1136
|
// between multiple connections using the same session
|
|
1054
1137
|
this._flushTimer.emitWhenIdle();
|
|
1055
1138
|
}
|
|
1056
|
-
else if (this._inactivityPendingFlush) {
|
|
1057
|
-
this.log.debug('pending messages sent, closing connection');
|
|
1058
|
-
this._flushTimer.reset();
|
|
1059
|
-
this._inactivityPendingFlush = false;
|
|
1060
|
-
super._onInactivityTimeout();
|
|
1061
|
-
}
|
|
1062
1139
|
else {
|
|
1063
|
-
this.
|
|
1140
|
+
const nextPingTime = this._session.lastPingTime + PING_INTERVAL;
|
|
1141
|
+
const nextGetScheduleTime = this._session.getStateSchedule.raw[0]?.getState || Infinity;
|
|
1142
|
+
this._flushTimer.emitBefore(Math.min(nextPingTime, nextGetScheduleTime));
|
|
1064
1143
|
}
|
|
1065
1144
|
}
|
|
1066
1145
|
_doFlush() {
|
|
@@ -1075,6 +1154,8 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1075
1154
|
let containerSize = 0;
|
|
1076
1155
|
let ackRequest = null;
|
|
1077
1156
|
let ackMsgIds = null;
|
|
1157
|
+
let getFutureSaltsRequest = null;
|
|
1158
|
+
let getFutureSaltsMsgId = null;
|
|
1078
1159
|
let pingRequest = null;
|
|
1079
1160
|
let pingId = null;
|
|
1080
1161
|
let pingMsgId = null;
|
|
@@ -1106,16 +1187,16 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1106
1187
|
packetSize += ackRequest.length + 16;
|
|
1107
1188
|
messageCount += 1;
|
|
1108
1189
|
}
|
|
1109
|
-
|
|
1110
|
-
if (now - this._session.lastPingTime > 60000) {
|
|
1190
|
+
if (now - this._session.lastPingTime > PING_INTERVAL) {
|
|
1111
1191
|
if (!this._session.lastPingMsgId.isZero()) {
|
|
1112
1192
|
this.log.warn("didn't receive pong for previous ping (msg_id = %l)", this._session.lastPingMsgId);
|
|
1113
1193
|
this._session.pendingMessages.delete(this._session.lastPingMsgId);
|
|
1114
1194
|
}
|
|
1115
1195
|
pingId = (0, index_js_2.randomLong)();
|
|
1116
1196
|
const obj = {
|
|
1117
|
-
_: '
|
|
1197
|
+
_: 'mt_ping_delay_disconnect',
|
|
1118
1198
|
pingId,
|
|
1199
|
+
disconnectDelay: 75,
|
|
1119
1200
|
};
|
|
1120
1201
|
this._session.lastPingTime = Date.now();
|
|
1121
1202
|
pingRequest = tl_runtime_1.TlBinaryWriter.serializeObject(this._writerMap, obj);
|
|
@@ -1180,6 +1261,16 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1180
1261
|
destroySessions = this._queuedDestroySession;
|
|
1181
1262
|
this._queuedDestroySession = [];
|
|
1182
1263
|
}
|
|
1264
|
+
if (this._salts.shouldFetchSalts()) {
|
|
1265
|
+
const obj = {
|
|
1266
|
+
_: 'mt_get_future_salts',
|
|
1267
|
+
num: 64,
|
|
1268
|
+
};
|
|
1269
|
+
getFutureSaltsRequest = tl_runtime_1.TlBinaryWriter.serializeObject(this._writerMap, obj);
|
|
1270
|
+
containerSize += getFutureSaltsRequest.length + 16;
|
|
1271
|
+
containerMessageCount += 1;
|
|
1272
|
+
this._salts.isFetching = true;
|
|
1273
|
+
}
|
|
1183
1274
|
let forceContainer = false;
|
|
1184
1275
|
const rpcToSend = [];
|
|
1185
1276
|
while (this._session.queuedRpc.length &&
|
|
@@ -1195,6 +1286,9 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1195
1286
|
containerSize += msg.data.length + 16;
|
|
1196
1287
|
if (msg.gzipOverhead)
|
|
1197
1288
|
containerSize += msg.gzipOverhead;
|
|
1289
|
+
if (msg.chainId) {
|
|
1290
|
+
containerSize += INVOKE_AFTER_MSG_SIZE;
|
|
1291
|
+
}
|
|
1198
1292
|
// if message was already assigned a msg_id,
|
|
1199
1293
|
// we must wrap it in a container with a newer msg_id
|
|
1200
1294
|
if (msg.msgId)
|
|
@@ -1287,6 +1381,16 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1287
1381
|
otherPendings.push(pending);
|
|
1288
1382
|
});
|
|
1289
1383
|
}
|
|
1384
|
+
if (getFutureSaltsRequest) {
|
|
1385
|
+
getFutureSaltsMsgId = this._registerOutgoingMsgId(this._session.writeMessage(writer, getFutureSaltsRequest));
|
|
1386
|
+
const pending = {
|
|
1387
|
+
_: 'future_salts',
|
|
1388
|
+
containerId: getFutureSaltsMsgId,
|
|
1389
|
+
};
|
|
1390
|
+
this._session.pendingMessages.set(getFutureSaltsMsgId, pending);
|
|
1391
|
+
otherPendings.push(pending);
|
|
1392
|
+
}
|
|
1393
|
+
const getStateTime = now + GET_STATE_INTERVAL;
|
|
1290
1394
|
for (let i = 0; i < rpcToSend.length; i++) {
|
|
1291
1395
|
const msg = rpcToSend[i];
|
|
1292
1396
|
// not using writeMessage here because we also need seqNo, and
|
|
@@ -1302,6 +1406,10 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1302
1406
|
_: 'rpc',
|
|
1303
1407
|
rpc: msg,
|
|
1304
1408
|
});
|
|
1409
|
+
if (msg.chainId) {
|
|
1410
|
+
msg.invokeAfter = this._session.addToChain(msg.chainId, msgId);
|
|
1411
|
+
this.log.debug('chain %s: invoke %l after %l', msg.chainId, msg.msgId, msg.invokeAfter);
|
|
1412
|
+
}
|
|
1305
1413
|
}
|
|
1306
1414
|
else {
|
|
1307
1415
|
this.log.debug('%s: msg_id already assigned, reusing %l, seqno: %d', msg.method, msg.msgId, msg.seqNo);
|
|
@@ -1318,13 +1426,22 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1318
1426
|
rootMsgId = msg.msgId;
|
|
1319
1427
|
writer.long(this._registerOutgoingMsgId(msg.msgId));
|
|
1320
1428
|
writer.uint(msg.seqNo);
|
|
1429
|
+
const invokeAfterSize = msg.invokeAfter ? INVOKE_AFTER_MSG_SIZE : 0;
|
|
1430
|
+
const writeInvokeAfter = () => {
|
|
1431
|
+
if (!msg.invokeAfter)
|
|
1432
|
+
return;
|
|
1433
|
+
writer.uint(INVOKE_AFTER_MSG_ID);
|
|
1434
|
+
writer.long(msg.invokeAfter);
|
|
1435
|
+
};
|
|
1321
1436
|
if (msg.gzipOverhead) {
|
|
1322
|
-
writer.uint(msg.data.length + msg.gzipOverhead);
|
|
1323
|
-
|
|
1437
|
+
writer.uint(msg.data.length + msg.gzipOverhead + invokeAfterSize);
|
|
1438
|
+
writeInvokeAfter();
|
|
1439
|
+
writer.uint(GZIP_PACKED_ID);
|
|
1324
1440
|
writer.bytes(msg.data);
|
|
1325
1441
|
}
|
|
1326
1442
|
else {
|
|
1327
|
-
writer.uint(msg.data.length);
|
|
1443
|
+
writer.uint(msg.data.length + invokeAfterSize);
|
|
1444
|
+
writeInvokeAfter();
|
|
1328
1445
|
writer.raw(msg.data);
|
|
1329
1446
|
}
|
|
1330
1447
|
msg.sent = true;
|
|
@@ -1333,7 +1450,7 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1333
1450
|
// we now need to assign the container msg_id and seqno
|
|
1334
1451
|
// we couldn't have assigned them earlier because mtproto
|
|
1335
1452
|
// requires them to be >= than the contained messages
|
|
1336
|
-
|
|
1453
|
+
packetSize = writer.pos;
|
|
1337
1454
|
const containerId = this._session.getMessageId();
|
|
1338
1455
|
writer.pos = 0;
|
|
1339
1456
|
rootMsgId = containerId;
|
|
@@ -1359,9 +1476,9 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1359
1476
|
});
|
|
1360
1477
|
}
|
|
1361
1478
|
const result = writer.result();
|
|
1362
|
-
this.log.debug('sending %d messages: size = %db, acks = %
|
|
1479
|
+
this.log.debug('sending %d messages: size = %db, acks = %L, ping = %b (msg_id = %l), state_req = %L (msg_id = %l), resend = %L (msg_id = %l), cancels = %L (msg_id = %l), salts_req = %b (msg_id = %l), rpc = %s, container = %b, root msg_id = %l', messageCount, packetSize, ackMsgIds, pingRequest, pingMsgId, getStateMsgIds, getStateMsgId, resendMsgIds, cancelRpcs, cancelRpcs, resendMsgId, getFutureSaltsRequest, getFutureSaltsMsgId, rpcToSend.map((it) => it.method), useContainer, rootMsgId);
|
|
1363
1480
|
const enc = this._session.encryptMessage(result);
|
|
1364
|
-
this.send(enc).catch((err) => {
|
|
1481
|
+
const promise = this.send(enc).catch((err) => {
|
|
1365
1482
|
this.log.error('error while sending pending messages (root msg_id = %l): %s', rootMsgId, err.stack);
|
|
1366
1483
|
// put acks in the front so they are the first to be sent
|
|
1367
1484
|
if (ackMsgIds) {
|
|
@@ -1371,6 +1488,14 @@ class SessionConnection extends persistent_connection_js_1.PersistentConnection
|
|
|
1371
1488
|
this._onMessageFailed(rootMsgId, 'unknown error');
|
|
1372
1489
|
}
|
|
1373
1490
|
});
|
|
1491
|
+
if (this._inactivityPendingFlush && !this._session.hasPendingMessages) {
|
|
1492
|
+
void promise.then(() => {
|
|
1493
|
+
this.log.debug('pending messages sent, closing connection');
|
|
1494
|
+
this._flushTimer.reset();
|
|
1495
|
+
this._inactivityPendingFlush = false;
|
|
1496
|
+
super._onInactivityTimeout();
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1374
1499
|
}
|
|
1375
1500
|
}
|
|
1376
1501
|
exports.SessionConnection = SessionConnection;
|