@mtcute/core 0.27.6 → 0.27.7

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.
@@ -41,9 +41,10 @@ function internalErrorsHandler(params) {
41
41
  }
42
42
  const waitSeconds = res.errorMessage === "WORKER_BUSY_TOO_LONG_RETRY" ? Math.max(1, waitTime) : waitTime;
43
43
  ctx.manager._log.warn(
44
- "Telegram is having internal issues: %d:%s, retrying in %ds",
44
+ "Telegram is having internal issues: %d:%s (%s), retrying in %ds",
45
45
  res.errorCode,
46
46
  res.errorMessage,
47
+ ctx.request._,
47
48
  waitSeconds
48
49
  );
49
50
  if (waitSeconds > 0) {
@@ -34,9 +34,10 @@ function internalErrorsHandler(params) {
34
34
  }
35
35
  const waitSeconds = res.errorMessage === "WORKER_BUSY_TOO_LONG_RETRY" ? Math.max(1, waitTime) : waitTime;
36
36
  ctx.manager._log.warn(
37
- "Telegram is having internal issues: %d:%s, retrying in %ds",
37
+ "Telegram is having internal issues: %d:%s (%s), retrying in %ds",
38
38
  res.errorCode,
39
39
  res.errorMessage,
40
+ ctx.request._,
40
41
  waitSeconds
41
42
  );
42
43
  if (waitSeconds > 0) {
@@ -36,6 +36,8 @@ class MtprotoSession {
36
36
  // recent msg ids
37
37
  recentOutgoingMsgIds = new utils.LruSet(1e3, longUtils.LongSet);
38
38
  recentIncomingMsgIds = new utils.LruSet(1e3, longUtils.LongSet);
39
+ // eslint-disable-next-line ts/no-unsafe-argument
40
+ recentStateRequests = new utils.LruMap(1e3, longUtils.LongMap);
39
41
  // queues
40
42
  queuedRpc = new utils.Deque();
41
43
  queuedAcks = [];
@@ -65,7 +67,7 @@ class MtprotoSession {
65
67
  next429ResetTimeout;
66
68
  get hasPendingMessages() {
67
69
  return Boolean(
68
- this.queuedRpc.length || this.queuedAcks.length || this.queuedStateReq.length || this.queuedResendReq.length
70
+ this.queuedRpc.length || this.queuedAcks.length || this.queuedStateReq.length || this.queuedResendReq.length || this.queuedCancelReq.length
69
71
  );
70
72
  }
71
73
  /**
@@ -111,6 +113,7 @@ class MtprotoSession {
111
113
  }
112
114
  this.recentOutgoingMsgIds.clear();
113
115
  this.recentIncomingMsgIds.clear();
116
+ this.recentStateRequests.clear();
114
117
  if (!keepPending) {
115
118
  while (this.queuedRpc.length) {
116
119
  const rpc = this.queuedRpc.popFront();
@@ -1,4 +1,4 @@
1
- import { Deferred, Deque, LruSet, timers } from '@fuman/utils';
1
+ import { Deferred, Deque, LruMap, LruSet, timers } from '@fuman/utils';
2
2
  import { mtp, tl } from '@mtcute/tl';
3
3
  import { TlBinaryWriter, TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime';
4
4
  import { ICryptoProvider, Logger, LongMap, SortedArray } from '../utils/index.js';
@@ -77,6 +77,7 @@ export declare class MtprotoSession {
77
77
  _seqNo: number;
78
78
  recentOutgoingMsgIds: LruSet<Long>;
79
79
  recentIncomingMsgIds: LruSet<Long>;
80
+ recentStateRequests: LruMap<Long, Long[]>;
80
81
  queuedRpc: Deque<PendingRpc>;
81
82
  queuedAcks: Long[];
82
83
  queuedStateReq: Long[];
@@ -1,4 +1,4 @@
1
- import { Deferred, Deque, LruSet, timers } from '@fuman/utils';
1
+ import { Deferred, Deque, LruMap, LruSet, timers } from '@fuman/utils';
2
2
  import { mtp, tl } from '@mtcute/tl';
3
3
  import { TlBinaryWriter, TlReaderMap, TlWriterMap } from '@mtcute/tl-runtime';
4
4
  import { ICryptoProvider, Logger, LongMap, SortedArray } from '../utils/index.js';
@@ -77,6 +77,7 @@ export declare class MtprotoSession {
77
77
  _seqNo: number;
78
78
  recentOutgoingMsgIds: LruSet<Long>;
79
79
  recentIncomingMsgIds: LruSet<Long>;
80
+ recentStateRequests: LruMap<Long, Long[]>;
80
81
  queuedRpc: Deque<PendingRpc>;
81
82
  queuedAcks: Long[];
82
83
  queuedStateReq: Long[];
@@ -1,4 +1,4 @@
1
- import { LruSet, Deque, timers } from "@fuman/utils";
1
+ import { LruSet, LruMap, Deque, timers } from "@fuman/utils";
2
2
  import { TlSerializationCounter } from "@mtcute/tl-runtime";
3
3
  import Long from "long";
4
4
  import { randomLong, LongSet, LongMap, compareLongs } from "../utils/long-utils.js";
@@ -29,6 +29,8 @@ class MtprotoSession {
29
29
  // recent msg ids
30
30
  recentOutgoingMsgIds = new LruSet(1e3, LongSet);
31
31
  recentIncomingMsgIds = new LruSet(1e3, LongSet);
32
+ // eslint-disable-next-line ts/no-unsafe-argument
33
+ recentStateRequests = new LruMap(1e3, LongMap);
32
34
  // queues
33
35
  queuedRpc = new Deque();
34
36
  queuedAcks = [];
@@ -58,7 +60,7 @@ class MtprotoSession {
58
60
  next429ResetTimeout;
59
61
  get hasPendingMessages() {
60
62
  return Boolean(
61
- this.queuedRpc.length || this.queuedAcks.length || this.queuedStateReq.length || this.queuedResendReq.length
63
+ this.queuedRpc.length || this.queuedAcks.length || this.queuedStateReq.length || this.queuedResendReq.length || this.queuedCancelReq.length
62
64
  );
63
65
  }
64
66
  /**
@@ -104,6 +106,7 @@ class MtprotoSession {
104
106
  }
105
107
  this.recentOutgoingMsgIds.clear();
106
108
  this.recentIncomingMsgIds.clear();
109
+ this.recentStateRequests.clear();
107
110
  if (!keepPending) {
108
111
  while (this.queuedRpc.length) {
109
112
  const rpc = this.queuedRpc.popFront();
@@ -225,7 +225,7 @@ class NetworkManager {
225
225
  _: "initConnection",
226
226
  deviceModel,
227
227
  systemVersion: "1.0",
228
- appVersion: "0.27.6",
228
+ appVersion: "0.27.7",
229
229
  systemLangCode: "en",
230
230
  langPack: "",
231
231
  // "langPacks are for official apps only"
@@ -218,7 +218,7 @@ class NetworkManager {
218
218
  _: "initConnection",
219
219
  deviceModel,
220
220
  systemVersion: "1.0",
221
- appVersion: "0.27.6",
221
+ appVersion: "0.27.7",
222
222
  systemLangCode: "en",
223
223
  langPack: "",
224
224
  // "langPacks are for official apps only"
@@ -17,35 +17,39 @@ class ServerSaltManager {
17
17
  setFutureSalts(salts) {
18
18
  this._futureSalts = salts;
19
19
  const now = Date.now() / 1e3;
20
- while (salts.length > 0 && now > salts[0].validSince) {
20
+ while (salts.length > 0 && now > salts[0].validUntil) {
21
21
  this.currentSalt = salts[0].salt;
22
22
  this._futureSalts.shift();
23
23
  }
24
- if (!this._futureSalts.length) this.currentSalt = Long.ZERO;
25
- else this._scheduleNext();
24
+ if (!this._futureSalts.length) {
25
+ this.currentSalt = Long.ZERO;
26
+ } else {
27
+ this._scheduleReplace(this._futureSalts[0]);
28
+ }
26
29
  }
27
30
  _timer;
28
- _scheduleNext() {
31
+ _scheduleReplace(salt) {
32
+ this._timer = utils.timers.setTimeout(() => {
33
+ this.currentSalt = salt.salt;
34
+ this._replaceAndScheduleNext();
35
+ }, salt.validSince * 1e3 - Date.now());
36
+ }
37
+ _replaceAndScheduleNext() {
29
38
  if (this._timer) utils.timers.clearTimeout(this._timer);
30
39
  const now = Date.now() / 1e3;
31
40
  let next;
32
41
  while (this._futureSalts.length !== 0) {
33
- const salt = this._futureSalts.shift();
42
+ const salt = this._futureSalts[0];
34
43
  if (salt.validSince <= now && now <= salt.validUntil) {
35
44
  next = salt;
36
45
  break;
37
46
  }
47
+ this._futureSalts.shift();
38
48
  }
39
49
  if (!next) {
40
50
  return;
41
51
  }
42
- this._timer = utils.timers.setTimeout(
43
- () => {
44
- this.currentSalt = next.salt;
45
- this._scheduleNext();
46
- },
47
- next.validSince * 1e3 - Date.now()
48
- );
52
+ this._scheduleReplace(next);
49
53
  }
50
54
  destroy() {
51
55
  utils.timers.clearTimeout(this._timer);
@@ -7,6 +7,7 @@ export declare class ServerSaltManager {
7
7
  shouldFetchSalts(): boolean;
8
8
  setFutureSalts(salts: mtp.RawMt_future_salt[]): void;
9
9
  private _timer?;
10
- private _scheduleNext;
10
+ private _scheduleReplace;
11
+ private _replaceAndScheduleNext;
11
12
  destroy(): void;
12
13
  }
@@ -7,6 +7,7 @@ export declare class ServerSaltManager {
7
7
  shouldFetchSalts(): boolean;
8
8
  setFutureSalts(salts: mtp.RawMt_future_salt[]): void;
9
9
  private _timer?;
10
- private _scheduleNext;
10
+ private _scheduleReplace;
11
+ private _replaceAndScheduleNext;
11
12
  destroy(): void;
12
13
  }
@@ -10,35 +10,39 @@ class ServerSaltManager {
10
10
  setFutureSalts(salts) {
11
11
  this._futureSalts = salts;
12
12
  const now = Date.now() / 1e3;
13
- while (salts.length > 0 && now > salts[0].validSince) {
13
+ while (salts.length > 0 && now > salts[0].validUntil) {
14
14
  this.currentSalt = salts[0].salt;
15
15
  this._futureSalts.shift();
16
16
  }
17
- if (!this._futureSalts.length) this.currentSalt = Long.ZERO;
18
- else this._scheduleNext();
17
+ if (!this._futureSalts.length) {
18
+ this.currentSalt = Long.ZERO;
19
+ } else {
20
+ this._scheduleReplace(this._futureSalts[0]);
21
+ }
19
22
  }
20
23
  _timer;
21
- _scheduleNext() {
24
+ _scheduleReplace(salt) {
25
+ this._timer = timers.setTimeout(() => {
26
+ this.currentSalt = salt.salt;
27
+ this._replaceAndScheduleNext();
28
+ }, salt.validSince * 1e3 - Date.now());
29
+ }
30
+ _replaceAndScheduleNext() {
22
31
  if (this._timer) timers.clearTimeout(this._timer);
23
32
  const now = Date.now() / 1e3;
24
33
  let next;
25
34
  while (this._futureSalts.length !== 0) {
26
- const salt = this._futureSalts.shift();
35
+ const salt = this._futureSalts[0];
27
36
  if (salt.validSince <= now && now <= salt.validUntil) {
28
37
  next = salt;
29
38
  break;
30
39
  }
40
+ this._futureSalts.shift();
31
41
  }
32
42
  if (!next) {
33
43
  return;
34
44
  }
35
- this._timer = timers.setTimeout(
36
- () => {
37
- this.currentSalt = next.salt;
38
- this._scheduleNext();
39
- },
40
- next.validSince * 1e3 - Date.now()
41
- );
45
+ this._scheduleReplace(next);
42
46
  }
43
47
  destroy() {
44
48
  timers.clearTimeout(this._timer);
@@ -19,7 +19,7 @@ const abstract = require("./transports/abstract.cjs");
19
19
  const errors = require("../types/errors.cjs");
20
20
  const TEMP_AUTH_KEY_EXPIRY = 86400;
21
21
  const GET_STATE_INTERVAL = 1500;
22
- const GET_STATE_TIMEOUT = 2e3;
22
+ const GET_STATE_TIMEOUT = 2500;
23
23
  const GZIP_PACKED_ID = 812830625;
24
24
  const MSG_CONTAINER_ID = 1945237724;
25
25
  const RPC_RESULT_ID = 4082920705;
@@ -748,8 +748,11 @@ class SessionConnection extends persistentConnection.PersistentConnection {
748
748
  utils.timers.clearTimeout(timer);
749
749
  this._session.pendingGetStateTimeouts.delete(msgId);
750
750
  }
751
- this._session.queuedStateReq.unshift(...msgInfo.msgIds);
752
- this._flushTimer.emitWhenIdle();
751
+ const stillPending = msgInfo.msgIds.filter((id) => this._session.pendingMessages.has(id));
752
+ if (stillPending.length > 0) {
753
+ this._session.queuedStateReq.unshift(...stillPending);
754
+ this._flushTimer.emitWhenIdle();
755
+ }
753
756
  break;
754
757
  }
755
758
  case "bind":
@@ -839,7 +842,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
839
842
  if (msgId.lt(firstMsgId)) {
840
843
  this._session.pendingMessages.delete(msgId);
841
844
  }
842
- return;
845
+ continue;
843
846
  }
844
847
  const containerId = val._ === "rpc" ? val.rpc.containerId || msgId : val.containerId;
845
848
  if (containerId.lt(firstMsgId)) {
@@ -869,7 +872,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
869
872
  status,
870
873
  answerMsgId
871
874
  );
872
- return this._onMessageFailed(msgId, "message info state = 0, ans_id = 0");
875
+ return this._onMessageFailed(msgId, "message info state = 0 with unexpected ans_id");
873
876
  }
874
877
  // fallthrough
875
878
  case 4:
@@ -904,8 +907,16 @@ class SessionConnection extends persistentConnection.PersistentConnection {
904
907
  }
905
908
  _onMsgsStateInfo(msg) {
906
909
  const info = this._session.pendingMessages.get(msg.reqMsgId);
910
+ let timer;
911
+ if (timer = this._session.pendingGetStateTimeouts.get(msg.reqMsgId)) {
912
+ utils.timers.clearTimeout(timer);
913
+ this._session.pendingGetStateTimeouts.delete(msg.reqMsgId);
914
+ }
907
915
  if (!info) {
908
- if (this._session.recentOutgoingMsgIds.has(msg.reqMsgId)) {
916
+ const msgIdsFromRecents = this._session.recentStateRequests.get(msg.reqMsgId);
917
+ if (msgIdsFromRecents) {
918
+ this._session.recentStateRequests.delete(msg.reqMsgId);
919
+ this._onMessagesInfo(msgIdsFromRecents, msg.info);
909
920
  return;
910
921
  }
911
922
  this.log.warn("received msgs_state_info to unknown request %l", msg.reqMsgId);
@@ -915,12 +926,8 @@ class SessionConnection extends persistentConnection.PersistentConnection {
915
926
  this.log.warn("received msgs_state_info to %s query %l", info._, msg.reqMsgId);
916
927
  return;
917
928
  }
929
+ this.log.debug("received msgs_state_info for %l", msg.reqMsgId);
918
930
  this._session.pendingMessages.delete(msg.reqMsgId);
919
- let timer;
920
- if (timer = this._session.pendingGetStateTimeouts.get(msg.reqMsgId)) {
921
- utils.timers.clearTimeout(timer);
922
- this._session.pendingGetStateTimeouts.delete(msg.reqMsgId);
923
- }
924
931
  this._onMessagesInfo(info.msgIds, msg.info);
925
932
  }
926
933
  _onFutureSalts(msg) {
@@ -1323,6 +1330,7 @@ class SessionConnection extends persistentConnection.PersistentConnection {
1323
1330
  containerId: getStateMsgId
1324
1331
  };
1325
1332
  this._session.pendingMessages.set(getStateMsgId, getStatePending);
1333
+ this._session.recentStateRequests.set(getStateMsgId, getStatePending.msgIds);
1326
1334
  otherPendings.push(getStatePending);
1327
1335
  const timeout = utils.timers.setTimeout(this._handleGetStateTimeout, GET_STATE_TIMEOUT, getStateMsgId);
1328
1336
  this._session.pendingGetStateTimeouts.set(getStateMsgId, timeout);
@@ -1466,9 +1474,9 @@ class SessionConnection extends persistentConnection.PersistentConnection {
1466
1474
  getStateMsgIds,
1467
1475
  getStateMsgId,
1468
1476
  resendMsgIds,
1477
+ resendMsgId,
1469
1478
  cancelRpcs,
1470
1479
  cancelRpcs,
1471
- resendMsgId,
1472
1480
  getFutureSaltsRequest,
1473
1481
  getFutureSaltsMsgId,
1474
1482
  rpcToSend.map((it) => it.method),
@@ -12,7 +12,7 @@ import { TransportError } from "./transports/abstract.js";
12
12
  import { MtcuteError, MtTimeoutError, MtArgumentError } from "../types/errors.js";
13
13
  const TEMP_AUTH_KEY_EXPIRY = 86400;
14
14
  const GET_STATE_INTERVAL = 1500;
15
- const GET_STATE_TIMEOUT = 2e3;
15
+ const GET_STATE_TIMEOUT = 2500;
16
16
  const GZIP_PACKED_ID = 812830625;
17
17
  const MSG_CONTAINER_ID = 1945237724;
18
18
  const RPC_RESULT_ID = 4082920705;
@@ -741,8 +741,11 @@ class SessionConnection extends PersistentConnection {
741
741
  timers.clearTimeout(timer);
742
742
  this._session.pendingGetStateTimeouts.delete(msgId);
743
743
  }
744
- this._session.queuedStateReq.unshift(...msgInfo.msgIds);
745
- this._flushTimer.emitWhenIdle();
744
+ const stillPending = msgInfo.msgIds.filter((id) => this._session.pendingMessages.has(id));
745
+ if (stillPending.length > 0) {
746
+ this._session.queuedStateReq.unshift(...stillPending);
747
+ this._flushTimer.emitWhenIdle();
748
+ }
746
749
  break;
747
750
  }
748
751
  case "bind":
@@ -832,7 +835,7 @@ class SessionConnection extends PersistentConnection {
832
835
  if (msgId.lt(firstMsgId)) {
833
836
  this._session.pendingMessages.delete(msgId);
834
837
  }
835
- return;
838
+ continue;
836
839
  }
837
840
  const containerId = val._ === "rpc" ? val.rpc.containerId || msgId : val.containerId;
838
841
  if (containerId.lt(firstMsgId)) {
@@ -862,7 +865,7 @@ class SessionConnection extends PersistentConnection {
862
865
  status,
863
866
  answerMsgId
864
867
  );
865
- return this._onMessageFailed(msgId, "message info state = 0, ans_id = 0");
868
+ return this._onMessageFailed(msgId, "message info state = 0 with unexpected ans_id");
866
869
  }
867
870
  // fallthrough
868
871
  case 4:
@@ -897,8 +900,16 @@ class SessionConnection extends PersistentConnection {
897
900
  }
898
901
  _onMsgsStateInfo(msg) {
899
902
  const info = this._session.pendingMessages.get(msg.reqMsgId);
903
+ let timer;
904
+ if (timer = this._session.pendingGetStateTimeouts.get(msg.reqMsgId)) {
905
+ timers.clearTimeout(timer);
906
+ this._session.pendingGetStateTimeouts.delete(msg.reqMsgId);
907
+ }
900
908
  if (!info) {
901
- if (this._session.recentOutgoingMsgIds.has(msg.reqMsgId)) {
909
+ const msgIdsFromRecents = this._session.recentStateRequests.get(msg.reqMsgId);
910
+ if (msgIdsFromRecents) {
911
+ this._session.recentStateRequests.delete(msg.reqMsgId);
912
+ this._onMessagesInfo(msgIdsFromRecents, msg.info);
902
913
  return;
903
914
  }
904
915
  this.log.warn("received msgs_state_info to unknown request %l", msg.reqMsgId);
@@ -908,12 +919,8 @@ class SessionConnection extends PersistentConnection {
908
919
  this.log.warn("received msgs_state_info to %s query %l", info._, msg.reqMsgId);
909
920
  return;
910
921
  }
922
+ this.log.debug("received msgs_state_info for %l", msg.reqMsgId);
911
923
  this._session.pendingMessages.delete(msg.reqMsgId);
912
- let timer;
913
- if (timer = this._session.pendingGetStateTimeouts.get(msg.reqMsgId)) {
914
- timers.clearTimeout(timer);
915
- this._session.pendingGetStateTimeouts.delete(msg.reqMsgId);
916
- }
917
924
  this._onMessagesInfo(info.msgIds, msg.info);
918
925
  }
919
926
  _onFutureSalts(msg) {
@@ -1316,6 +1323,7 @@ class SessionConnection extends PersistentConnection {
1316
1323
  containerId: getStateMsgId
1317
1324
  };
1318
1325
  this._session.pendingMessages.set(getStateMsgId, getStatePending);
1326
+ this._session.recentStateRequests.set(getStateMsgId, getStatePending.msgIds);
1319
1327
  otherPendings.push(getStatePending);
1320
1328
  const timeout = timers.setTimeout(this._handleGetStateTimeout, GET_STATE_TIMEOUT, getStateMsgId);
1321
1329
  this._session.pendingGetStateTimeouts.set(getStateMsgId, timeout);
@@ -1459,9 +1467,9 @@ class SessionConnection extends PersistentConnection {
1459
1467
  getStateMsgIds,
1460
1468
  getStateMsgId,
1461
1469
  resendMsgIds,
1470
+ resendMsgId,
1462
1471
  cancelRpcs,
1463
1472
  cancelRpcs,
1464
- resendMsgId,
1465
1473
  getFutureSaltsRequest,
1466
1474
  getFutureSaltsMsgId,
1467
1475
  rpcToSend.map((it) => it.method),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mtcute/core",
3
3
  "type": "module",
4
- "version": "0.27.6",
4
+ "version": "0.27.7",
5
5
  "description": "Type-safe library for MTProto (Telegram API)",
6
6
  "license": "MIT",
7
7
  "scripts": {},