@mtkruto/browser 0.119.0 → 0.120.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.
Files changed (128) hide show
  1. package/README.md +1 -1
  2. package/esm/0_errors.d.ts.map +1 -1
  3. package/esm/0_errors.js +9 -31
  4. package/esm/3_errors.js +2 -12
  5. package/esm/4_errors.js +2 -12
  6. package/esm/_dnt.polyfills.d.ts +0 -99
  7. package/esm/_dnt.polyfills.d.ts.map +1 -1
  8. package/esm/_dnt.polyfills.js +1 -127
  9. package/esm/client/0_abortable_loop.js +26 -39
  10. package/esm/client/0_storage_operations.js +179 -218
  11. package/esm/client/1_client_plain.js +4 -22
  12. package/esm/client/2_account_manager.js +140 -149
  13. package/esm/client/2_bot_info_manager.js +26 -38
  14. package/esm/client/2_business_connection_manager.js +10 -23
  15. package/esm/client/2_client_encrypted.js +198 -215
  16. package/esm/client/2_file_manager.js +255 -262
  17. package/esm/client/2_network_statistics_manager.js +31 -44
  18. package/esm/client/2_payment_manager.js +7 -20
  19. package/esm/client/2_reaction_manager.js +7 -20
  20. package/esm/client/2_translations_manager.js +101 -111
  21. package/esm/client/2_update_manager.js +750 -745
  22. package/esm/client/3_client_encrypted_pool.js +10 -26
  23. package/esm/client/3_message_manager.js +503 -508
  24. package/esm/client/3_video_chat_manager.js +57 -68
  25. package/esm/client/4_callback_query_manager.js +18 -30
  26. package/esm/client/4_chat_list_manager.js +140 -146
  27. package/esm/client/4_chat_manager.js +161 -169
  28. package/esm/client/4_checklist_manager.js +26 -39
  29. package/esm/client/4_context.js +244 -259
  30. package/esm/client/4_forum_manager.js +67 -73
  31. package/esm/client/4_gift_manager.js +22 -35
  32. package/esm/client/4_inline_query_manager.js +16 -28
  33. package/esm/client/4_link_preview_manager.js +6 -19
  34. package/esm/client/4_poll_manager.js +44 -57
  35. package/esm/client/4_story_manager.js +41 -53
  36. package/esm/client/5_composer.js +13 -26
  37. package/esm/client/6_client.js +866 -896
  38. package/esm/client/6_client_dispatcher.js +308 -325
  39. package/esm/client/7_client_worker.js +16 -29
  40. package/esm/connection/1_connection_tcp.js +55 -82
  41. package/esm/connection/1_connection_web_socket.js +75 -91
  42. package/esm/deps/jsr.io/@roj/tgcrypto/1.0.1/dist/tgcrypto.js +3 -11
  43. package/esm/deps/jsr.io/@std/async/1.2.0/mux_async_iterator.js +31 -47
  44. package/esm/deps/jsr.io/@std/async/1.2.0/tee.js +11 -34
  45. package/esm/deps/jsr.io/@std/cache/0.2.2/lru_cache.js +30 -47
  46. package/esm/deps/jsr.io/@std/datetime/0.225.7/_date_time_formatter.js +4 -17
  47. package/esm/session/0_session_state.js +12 -38
  48. package/esm/session/1_session.js +49 -72
  49. package/esm/session/2_session_encrypted.js +422 -420
  50. package/esm/storage/2_storage_indexed_db.js +26 -44
  51. package/esm/storage/2_storage_local_storage.js +3 -16
  52. package/esm/storage/2_storage_memory.js +24 -41
  53. package/esm/storage/2_storage_session_storage.js +3 -16
  54. package/esm/tl/1_tl_reader.d.ts +1 -1
  55. package/esm/tl/1_tl_reader.d.ts.map +1 -1
  56. package/esm/tl/1_tl_reader.js +95 -103
  57. package/esm/tl/1_tl_writer.js +169 -178
  58. package/esm/transport/0_transport.js +1 -8
  59. package/esm/transport/1_transport_abridged.js +11 -24
  60. package/esm/transport/1_transport_intermediate.js +10 -23
  61. package/esm/utilities/0_mutex.js +4 -19
  62. package/esm/utilities/0_part_stream.js +11 -25
  63. package/esm/utilities/1_crypto.js +42 -53
  64. package/esm/utilities/2_queue.js +29 -47
  65. package/package.json +1 -1
  66. package/script/0_errors.d.ts.map +1 -1
  67. package/script/0_errors.js +9 -31
  68. package/script/3_errors.js +2 -12
  69. package/script/4_errors.js +2 -12
  70. package/script/_dnt.polyfills.d.ts +0 -99
  71. package/script/_dnt.polyfills.d.ts.map +1 -1
  72. package/script/_dnt.polyfills.js +0 -128
  73. package/script/client/0_abortable_loop.js +27 -40
  74. package/script/client/0_storage_operations.js +179 -218
  75. package/script/client/1_client_plain.js +4 -22
  76. package/script/client/2_account_manager.js +140 -149
  77. package/script/client/2_bot_info_manager.js +26 -38
  78. package/script/client/2_business_connection_manager.js +10 -23
  79. package/script/client/2_client_encrypted.js +199 -216
  80. package/script/client/2_file_manager.js +255 -262
  81. package/script/client/2_network_statistics_manager.js +32 -45
  82. package/script/client/2_payment_manager.js +7 -20
  83. package/script/client/2_reaction_manager.js +7 -20
  84. package/script/client/2_translations_manager.js +102 -112
  85. package/script/client/2_update_manager.js +750 -745
  86. package/script/client/3_client_encrypted_pool.js +10 -26
  87. package/script/client/3_message_manager.js +503 -508
  88. package/script/client/3_video_chat_manager.js +57 -68
  89. package/script/client/4_callback_query_manager.js +18 -30
  90. package/script/client/4_chat_list_manager.js +140 -146
  91. package/script/client/4_chat_manager.js +161 -169
  92. package/script/client/4_checklist_manager.js +26 -39
  93. package/script/client/4_context.js +244 -259
  94. package/script/client/4_forum_manager.js +67 -73
  95. package/script/client/4_gift_manager.js +22 -35
  96. package/script/client/4_inline_query_manager.js +16 -28
  97. package/script/client/4_link_preview_manager.js +6 -19
  98. package/script/client/4_poll_manager.js +44 -57
  99. package/script/client/4_story_manager.js +41 -53
  100. package/script/client/5_composer.js +13 -26
  101. package/script/client/6_client.js +866 -896
  102. package/script/client/6_client_dispatcher.js +308 -325
  103. package/script/client/7_client_worker.js +16 -29
  104. package/script/connection/1_connection_tcp.js +55 -82
  105. package/script/connection/1_connection_web_socket.js +75 -91
  106. package/script/deps/jsr.io/@roj/tgcrypto/1.0.1/dist/tgcrypto.js +3 -11
  107. package/script/deps/jsr.io/@std/async/1.2.0/mux_async_iterator.js +31 -47
  108. package/script/deps/jsr.io/@std/async/1.2.0/tee.js +11 -34
  109. package/script/deps/jsr.io/@std/cache/0.2.2/lru_cache.js +30 -47
  110. package/script/deps/jsr.io/@std/datetime/0.225.7/_date_time_formatter.js +4 -17
  111. package/script/session/0_session_state.js +12 -38
  112. package/script/session/1_session.js +49 -72
  113. package/script/session/2_session_encrypted.js +423 -421
  114. package/script/storage/2_storage_indexed_db.js +26 -44
  115. package/script/storage/2_storage_local_storage.js +3 -16
  116. package/script/storage/2_storage_memory.js +24 -41
  117. package/script/storage/2_storage_session_storage.js +3 -16
  118. package/script/tl/1_tl_reader.d.ts +1 -1
  119. package/script/tl/1_tl_reader.d.ts.map +1 -1
  120. package/script/tl/1_tl_reader.js +96 -104
  121. package/script/tl/1_tl_writer.js +170 -179
  122. package/script/transport/0_transport.js +1 -8
  123. package/script/transport/1_transport_abridged.js +11 -24
  124. package/script/transport/1_transport_intermediate.js +10 -23
  125. package/script/utilities/0_mutex.js +4 -19
  126. package/script/utilities/0_part_stream.js +11 -25
  127. package/script/utilities/1_crypto.js +43 -54
  128. package/script/utilities/2_queue.js +30 -48
@@ -17,18 +17,6 @@
17
17
  * You should have received a copy of the GNU Lesser General Public License
18
18
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19
19
  */
20
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
21
- if (kind === "m") throw new TypeError("Private method is not writable");
22
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
23
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
24
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
25
- };
26
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
27
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
28
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
29
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
30
- };
31
- var _SessionEncrypted_instances, _a, _SessionEncrypted_TGCRYPTO_INITED, _SessionEncrypted_id, _SessionEncrypted_L, _SessionEncrypted_LsendLoop, _SessionEncrypted_LreceiveLoop, _SessionEncrypted_LpingLoop, _SessionEncrypted_authKey, _SessionEncrypted_authKeyId, _SessionEncrypted_sentMessages, _SessionEncrypted_pendingMessages, _SessionEncrypted_containers, _SessionEncrypted_pendingPings, _SessionEncrypted_toAcknowledge, _SessionEncrypted_pendingAcks, _SessionEncrypted_assertNotDisconnected, _SessionEncrypted_invalidateSession, _SessionEncrypted_rejectAllPending, _SessionEncrypted_onMessageFailed, _SessionEncrypted_setServerSalt, _SessionEncrypted_receive, _SessionEncrypted_encryptMessage, _SessionEncrypted_decryptMessage, _SessionEncrypted_awakeSendLoop, _SessionEncrypted_sendLoop, _SessionEncrypted_sendLoopBody, _SessionEncrypted_receiveLoop, _SessionEncrypted_receiveLoopBody, _SessionEncrypted_onMessage, _SessionEncrypted_onRpcResult, _SessionEncrypted_onMsgDetailedInfo, _SessionEncrypted_onMsgNewDetailedInfo, _SessionEncrypted_onBadMsgNotification, _SessionEncrypted_onBadServerSalt, _SessionEncrypted_onPong, _SessionEncrypted_onNewSessionCreated, _SessionEncrypted_onMessageContainer, _SessionEncrypted_pingInterval, _SessionEncrypted_pingLoop, _SessionEncrypted_timeElapsed, _SessionEncrypted_pingLoopBody, _SessionEncrypted_sendPingDelayDisconnect, _SessionEncrypted_resendPendingPing;
32
20
  import { assertEquals, concat, delay, ige256Decrypt, ige256Encrypt, initTgCrypto, LruCache, SECOND } from "../0_deps.js";
33
21
  import { ConnectionError, TransportError } from "../0_errors.js";
34
22
  import { drop, getLogger, getRandomId, gunzip, intFromBytes, intToBytes, mod, sha1, sha256, toUnixTimestamp } from "../1_utilities.js";
@@ -43,465 +31,479 @@ const GZIP_PACKED = 0x3072CFA1;
43
31
  const RPC_RESULT = 0xF35C6D01;
44
32
  const RPC_ERROR = Mtproto.schema.definitions["rpc_error"][0];
45
33
  export class SessionEncrypted extends Session {
34
+ static #TGCRYPTO_INITED = false;
35
+ #id = getRandomId();
36
+ handlers = {};
37
+ #L;
38
+ #LsendLoop;
39
+ #LreceiveLoop;
40
+ #LpingLoop;
41
+ #authKey = new Uint8Array();
42
+ #authKeyId = 0n;
43
+ #sentMessages = new Set();
44
+ #pendingMessages = new Array();
45
+ #containers = new LruCache(20_000);
46
+ #pendingPings = new Map();
47
+ #toAcknowledge = new Array();
48
+ #pendingAcks = new LruCache(100);
46
49
  constructor(dc, params) {
47
50
  super(dc, params);
48
- _SessionEncrypted_instances.add(this);
49
- _SessionEncrypted_id.set(this, getRandomId());
50
- Object.defineProperty(this, "handlers", {
51
- enumerable: true,
52
- configurable: true,
53
- writable: true,
54
- value: {}
55
- });
56
- _SessionEncrypted_L.set(this, void 0);
57
- _SessionEncrypted_LsendLoop.set(this, void 0);
58
- _SessionEncrypted_LreceiveLoop.set(this, void 0);
59
- _SessionEncrypted_LpingLoop.set(this, void 0);
60
- _SessionEncrypted_authKey.set(this, new Uint8Array());
61
- _SessionEncrypted_authKeyId.set(this, 0n);
62
- _SessionEncrypted_sentMessages.set(this, new Set());
63
- _SessionEncrypted_pendingMessages.set(this, new Array());
64
- _SessionEncrypted_containers.set(this, new LruCache(20_000));
65
- _SessionEncrypted_pendingPings.set(this, new Map());
66
- _SessionEncrypted_toAcknowledge.set(this, new Array());
67
- _SessionEncrypted_pendingAcks.set(this, new LruCache(100));
68
- //// SEND LOOP ////
69
- _SessionEncrypted_awakeSendLoop.set(this, void 0);
70
- _SessionEncrypted_sendLoop.set(this, new AbortableLoop(__classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_sendLoopBody).bind(this), (err) => {
71
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").error("unhandled receive loop error:", err);
72
- }));
73
- //// RECEIVE LOOP ////
74
- _SessionEncrypted_receiveLoop.set(this, new AbortableLoop(__classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_receiveLoopBody).bind(this), (err) => {
75
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").error("unhandled receive loop error:", err);
76
- }));
77
- //// PING LOOP ////
78
- _SessionEncrypted_pingInterval.set(this, 56 * SECOND);
79
- _SessionEncrypted_pingLoop.set(this, new AbortableLoop(__classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_pingLoopBody).bind(this), (_, err) => {
80
- __classPrivateFieldGet(this, _SessionEncrypted_LpingLoop, "f").error(err);
81
- }));
82
- _SessionEncrypted_timeElapsed.set(this, 0);
83
- const L = __classPrivateFieldSet(this, _SessionEncrypted_L, getLogger("SessionEncrypted").client(id++), "f");
84
- __classPrivateFieldSet(this, _SessionEncrypted_LsendLoop, L.branch("sendLoop"), "f");
85
- __classPrivateFieldSet(this, _SessionEncrypted_LreceiveLoop, L.branch("receiveLoop"), "f");
86
- __classPrivateFieldSet(this, _SessionEncrypted_LpingLoop, L.branch("pingLoop"), "f");
51
+ const L = this.#L = getLogger("SessionEncrypted").client(id++);
52
+ this.#LsendLoop = L.branch("sendLoop");
53
+ this.#LreceiveLoop = L.branch("receiveLoop");
54
+ this.#LpingLoop = L.branch("pingLoop");
87
55
  }
88
56
  async setAuthKey(key) {
89
57
  const hash = await sha1(key);
90
- __classPrivateFieldSet(this, _SessionEncrypted_authKeyId, intFromBytes(hash.slice(-8)), "f");
91
- __classPrivateFieldSet(this, _SessionEncrypted_authKey, key, "f");
58
+ this.#authKeyId = intFromBytes(hash.slice(-8));
59
+ this.#authKey = key;
92
60
  }
93
61
  get authKey() {
94
- return __classPrivateFieldGet(this, _SessionEncrypted_authKey, "f");
62
+ return this.#authKey;
95
63
  }
96
64
  async connect() {
97
65
  if (!this.isConnected) {
98
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_rejectAllPending).call(this, new ConnectionError("The connection was closed."));
66
+ this.#rejectAllPending(new ConnectionError("The connection was closed."));
99
67
  }
100
68
  await super.connect();
101
- if (!__classPrivateFieldGet(_a, _a, "f", _SessionEncrypted_TGCRYPTO_INITED)) {
69
+ if (!SessionEncrypted.#TGCRYPTO_INITED) {
102
70
  await initTgCrypto();
103
- __classPrivateFieldSet(_a, _a, true, "f", _SessionEncrypted_TGCRYPTO_INITED);
71
+ SessionEncrypted.#TGCRYPTO_INITED = true;
104
72
  }
105
- __classPrivateFieldGet(this, _SessionEncrypted_receiveLoop, "f").start();
106
- __classPrivateFieldGet(this, _SessionEncrypted_sendLoop, "f").start();
107
- __classPrivateFieldGet(this, _SessionEncrypted_pingLoop, "f").start();
108
- __classPrivateFieldGet(this, _SessionEncrypted_awakeSendLoop, "f")?.call(this);
73
+ this.#receiveLoop.start();
74
+ this.#sendLoop.start();
75
+ this.#pingLoop.start();
76
+ this.#awakeSendLoop?.();
109
77
  }
110
78
  disconnect() {
111
79
  super.disconnect();
112
80
  this.state.reset();
113
- __classPrivateFieldSet(this, _SessionEncrypted_id, getRandomId(), "f");
114
- __classPrivateFieldGet(this, _SessionEncrypted_pingLoop, "f").abort();
115
- __classPrivateFieldGet(this, _SessionEncrypted_awakeSendLoop, "f")?.call(this);
116
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_rejectAllPending).call(this, new ConnectionError("The connection was disconnected."));
81
+ this.#id = getRandomId();
82
+ this.#pingLoop.abort();
83
+ this.#awakeSendLoop?.();
84
+ this.#rejectAllPending(new ConnectionError("The connection was disconnected."));
85
+ }
86
+ #assertNotDisconnected() {
87
+ if (this.isDisconnected) {
88
+ throw new ConnectionError("The connection was disconnected.");
89
+ }
90
+ }
91
+ async #invalidateSession(reason) {
92
+ this.#L.debug("invalidating session because of", reason);
93
+ this.#id = getRandomId();
94
+ this.state.reset();
95
+ this.disconnect();
96
+ await this.connect();
97
+ this.#rejectAllPending(new SessionError("The session was invalidated."));
98
+ }
99
+ #rejectAllPending(reason) {
100
+ for (const id of this.#sentMessages) {
101
+ this.#onMessageFailed(id, reason);
102
+ }
103
+ for (const pendingPing of this.#pendingPings.values()) {
104
+ pendingPing.promiseWithResolvers.reject(reason);
105
+ }
106
+ this.#sentMessages.clear();
107
+ this.#pendingPings.clear();
108
+ this.#containers.clear();
109
+ }
110
+ #onMessageFailed(id, reason) {
111
+ this.#sentMessages.delete(id);
112
+ const pendingContainer = this.#containers.get(id);
113
+ if (pendingContainer) {
114
+ for (const id of pendingContainer) {
115
+ this.#onMessageFailed(id, reason);
116
+ }
117
+ this.#containers.delete(id);
118
+ return;
119
+ }
120
+ const pendingAck = this.#pendingAcks.get(id);
121
+ if (pendingAck) {
122
+ for (const id of pendingAck) {
123
+ this.#toAcknowledge.push(id);
124
+ }
125
+ this.#pendingAcks.delete(id);
126
+ return;
127
+ }
128
+ const pendingPing = this.#pendingPings.get(id);
129
+ if (pendingPing) {
130
+ this.#pendingPings.delete(id);
131
+ if (reason instanceof SessionError) {
132
+ drop(this.#resendPendingPing(pendingPing));
133
+ }
134
+ else {
135
+ pendingPing.promiseWithResolvers.reject(reason);
136
+ }
137
+ return;
138
+ }
139
+ // message was not sent by us
140
+ this.handlers.onMessageFailed?.(id, reason);
141
+ }
142
+ #setServerSalt(newServerSalt) {
143
+ this.state.serverSalt = newServerSalt;
144
+ this.handlers.onNewServerSalt?.(newServerSalt);
117
145
  }
118
146
  async send(body) {
119
147
  if (!this.isDisconnected && !this.isConnected) {
120
148
  await super.waitUntilConnected();
121
149
  }
122
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_assertNotDisconnected).call(this);
150
+ this.#assertNotDisconnected();
123
151
  const pendingMessage = { body, promiseWithResolvers: Promise.withResolvers() };
124
- __classPrivateFieldGet(this, _SessionEncrypted_pendingMessages, "f").push(pendingMessage);
125
- __classPrivateFieldGet(this, _SessionEncrypted_awakeSendLoop, "f")?.call(this);
152
+ this.#pendingMessages.push(pendingMessage);
153
+ this.#awakeSendLoop?.();
126
154
  return await pendingMessage.promiseWithResolvers.promise;
127
155
  }
128
- }
129
- _a = SessionEncrypted, _SessionEncrypted_id = new WeakMap(), _SessionEncrypted_L = new WeakMap(), _SessionEncrypted_LsendLoop = new WeakMap(), _SessionEncrypted_LreceiveLoop = new WeakMap(), _SessionEncrypted_LpingLoop = new WeakMap(), _SessionEncrypted_authKey = new WeakMap(), _SessionEncrypted_authKeyId = new WeakMap(), _SessionEncrypted_sentMessages = new WeakMap(), _SessionEncrypted_pendingMessages = new WeakMap(), _SessionEncrypted_containers = new WeakMap(), _SessionEncrypted_pendingPings = new WeakMap(), _SessionEncrypted_toAcknowledge = new WeakMap(), _SessionEncrypted_pendingAcks = new WeakMap(), _SessionEncrypted_awakeSendLoop = new WeakMap(), _SessionEncrypted_sendLoop = new WeakMap(), _SessionEncrypted_receiveLoop = new WeakMap(), _SessionEncrypted_pingInterval = new WeakMap(), _SessionEncrypted_pingLoop = new WeakMap(), _SessionEncrypted_timeElapsed = new WeakMap(), _SessionEncrypted_instances = new WeakSet(), _SessionEncrypted_assertNotDisconnected = function _SessionEncrypted_assertNotDisconnected() {
130
- if (this.isDisconnected) {
131
- throw new ConnectionError("The connection was disconnected.");
132
- }
133
- }, _SessionEncrypted_invalidateSession = async function _SessionEncrypted_invalidateSession(reason) {
134
- __classPrivateFieldGet(this, _SessionEncrypted_L, "f").debug("invalidating session because of", reason);
135
- __classPrivateFieldSet(this, _SessionEncrypted_id, getRandomId(), "f");
136
- this.state.reset();
137
- this.disconnect();
138
- await this.connect();
139
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_rejectAllPending).call(this, new SessionError("The session was invalidated."));
140
- }, _SessionEncrypted_rejectAllPending = function _SessionEncrypted_rejectAllPending(reason) {
141
- for (const id of __classPrivateFieldGet(this, _SessionEncrypted_sentMessages, "f")) {
142
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessageFailed).call(this, id, reason);
143
- }
144
- for (const pendingPing of __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").values()) {
145
- pendingPing.promiseWithResolvers.reject(reason);
146
- }
147
- __classPrivateFieldGet(this, _SessionEncrypted_sentMessages, "f").clear();
148
- __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").clear();
149
- __classPrivateFieldGet(this, _SessionEncrypted_containers, "f").clear();
150
- }, _SessionEncrypted_onMessageFailed = function _SessionEncrypted_onMessageFailed(id, reason) {
151
- __classPrivateFieldGet(this, _SessionEncrypted_sentMessages, "f").delete(id);
152
- const pendingContainer = __classPrivateFieldGet(this, _SessionEncrypted_containers, "f").get(id);
153
- if (pendingContainer) {
154
- for (const id of pendingContainer) {
155
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessageFailed).call(this, id, reason);
156
- }
157
- __classPrivateFieldGet(this, _SessionEncrypted_containers, "f").delete(id);
158
- return;
159
- }
160
- const pendingAck = __classPrivateFieldGet(this, _SessionEncrypted_pendingAcks, "f").get(id);
161
- if (pendingAck) {
162
- for (const id of pendingAck) {
163
- __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").push(id);
156
+ async #receive() {
157
+ this.#assertNotDisconnected();
158
+ const buffer = await this.transport.transport.receive();
159
+ if (buffer.length === 4) {
160
+ const int = intFromBytes(buffer);
161
+ throw new TransportError(Number(int));
164
162
  }
165
- __classPrivateFieldGet(this, _SessionEncrypted_pendingAcks, "f").delete(id);
166
- return;
167
- }
168
- const pendingPing = __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").get(id);
169
- if (pendingPing) {
170
- __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").delete(id);
171
- if (reason instanceof SessionError) {
172
- drop(__classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_resendPendingPing).call(this, pendingPing));
163
+ try {
164
+ const decrypted = await this.#decryptMessage(buffer);
165
+ this.#L.in(decrypted);
166
+ return decrypted;
173
167
  }
174
- else {
175
- pendingPing.promiseWithResolvers.reject(reason);
168
+ catch (err) {
169
+ this.#L.error("decryption error:", err);
170
+ await this.#invalidateSession("decryption error");
171
+ throw err;
176
172
  }
177
- return;
178
- }
179
- // message was not sent by us
180
- this.handlers.onMessageFailed?.(id, reason);
181
- }, _SessionEncrypted_setServerSalt = function _SessionEncrypted_setServerSalt(newServerSalt) {
182
- this.state.serverSalt = newServerSalt;
183
- this.handlers.onNewServerSalt?.(newServerSalt);
184
- }, _SessionEncrypted_receive = async function _SessionEncrypted_receive() {
185
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_assertNotDisconnected).call(this);
186
- const buffer = await this.transport.transport.receive();
187
- if (buffer.length === 4) {
188
- const int = intFromBytes(buffer);
189
- throw new TransportError(Number(int));
190
- }
191
- try {
192
- const decrypted = await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_decryptMessage).call(this, buffer);
193
- __classPrivateFieldGet(this, _SessionEncrypted_L, "f").in(decrypted);
194
- return decrypted;
195
- }
196
- catch (err) {
197
- __classPrivateFieldGet(this, _SessionEncrypted_L, "f").error("decryption error:", err);
198
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_invalidateSession).call(this, "decryption error");
199
- throw err;
200
173
  }
201
- }, _SessionEncrypted_encryptMessage = async function _SessionEncrypted_encryptMessage(message) {
202
- const payloadWriter = new TLWriter();
203
- payloadWriter.writeInt64(this.state.serverSalt);
204
- payloadWriter.writeInt64(__classPrivateFieldGet(this, _SessionEncrypted_id, "f"));
205
- payloadWriter.write(await serializeMessage(message));
206
- payloadWriter.write(new Uint8Array(mod(-(payloadWriter.buffer.length + 12), 16) + 12));
207
- const payload = payloadWriter.buffer;
208
- const messageKey = (await sha256(concat([__classPrivateFieldGet(this, _SessionEncrypted_authKey, "f").subarray(88, 120), payload]))).subarray(8, 24);
209
- const a = await sha256(concat([messageKey, __classPrivateFieldGet(this, _SessionEncrypted_authKey, "f").subarray(0, 36)]));
210
- const b = await sha256(concat([__classPrivateFieldGet(this, _SessionEncrypted_authKey, "f").subarray(40, 76), messageKey]));
211
- const aesKey = concat([a.subarray(0, 8), b.subarray(8, 24), a.subarray(24, 32)]);
212
- const aesIV = concat([b.subarray(0, 8), a.subarray(8, 24), b.subarray(24, 32)]);
213
- const messageWriter = new TLWriter();
214
- messageWriter.writeInt64(__classPrivateFieldGet(this, _SessionEncrypted_authKeyId, "f"));
215
- messageWriter.write(messageKey);
216
- messageWriter.write(ige256Encrypt(payload, aesKey, aesIV));
217
- return messageWriter.buffer;
218
- }, _SessionEncrypted_decryptMessage = async function _SessionEncrypted_decryptMessage(buffer) {
219
- const reader = new TLReader(buffer);
220
- assertEquals(reader.readInt64(), __classPrivateFieldGet(this, _SessionEncrypted_authKeyId, "f"));
221
- const messageKey_ = reader.readInt128();
222
- const messageKey = intToBytes(messageKey_, 16);
223
- const a = await sha256(concat([messageKey, __classPrivateFieldGet(this, _SessionEncrypted_authKey, "f").subarray(8, 44)]));
224
- const b = await sha256(concat([__classPrivateFieldGet(this, _SessionEncrypted_authKey, "f").subarray(48, 84), messageKey]));
225
- const aesKey = concat([a.subarray(0, 8), b.subarray(8, 24), a.subarray(24, 32)]);
226
- const aesIv = concat([b.subarray(0, 8), a.subarray(8, 24), b.subarray(24, 32)]);
227
- const plaintext = ige256Decrypt(reader.buffer, aesKey, aesIv);
228
- assertEquals(plaintext.buffer.byteLength % 4, 0);
229
- const plainReader = new TLReader(plaintext);
230
- const _salt = plainReader.readInt64();
231
- const _sessionId_ = plainReader.readInt64(false);
232
- return deserializeMessage(plainReader);
233
- }, _SessionEncrypted_sendLoopBody = async function _SessionEncrypted_sendLoopBody(loop, signal) {
234
- if (!this.isConnected) {
235
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("aborting as not connected");
236
- loop.abort();
237
- return;
238
- }
239
- const pendingMessage = __classPrivateFieldGet(this, _SessionEncrypted_pendingMessages, "f").shift();
240
- if (pendingMessage === undefined) {
241
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("no pending messages");
242
- return await new Promise((resolve) => {
243
- const onAbort = () => {
244
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("got aborted while sleeping");
245
- resolve();
246
- };
247
- signal.addEventListener("abort", onAbort);
248
- __classPrivateFieldSet(this, _SessionEncrypted_awakeSendLoop, () => {
249
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("got awaken");
250
- resolve();
251
- signal.removeEventListener("abort", onAbort);
252
- }, "f");
253
- });
254
- }
255
- const msg_id = this.state.nextMessageId();
256
- const seqno = this.state.nextSeqNo(true);
257
- let message = {
258
- _: "message",
259
- msg_id,
260
- seqno,
261
- body: pendingMessage.body,
262
- };
263
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("msg_id =", msg_id, "seqno =", seqno);
264
- if (__classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").length) {
265
- const msg_ids = __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").splice(0, 8192);
266
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("acknowledging", msg_ids.length, "message(s) while sending this one");
267
- const ack = {
268
- _: "message",
269
- msg_id: this.state.nextMessageId(),
270
- seqno: this.state.nextSeqNo(false),
271
- body: Mtproto.serializeObject({ _: "msgs_ack", msg_ids }),
272
- };
273
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("msgs_ack msg_id =", ack.msg_id, "seqno =", seqno);
274
- __classPrivateFieldGet(this, _SessionEncrypted_pendingAcks, "f").set(ack.msg_id, msg_ids);
275
- message = {
276
- _: "message",
277
- msg_id: this.state.nextMessageId(),
278
- seqno: this.state.nextSeqNo(false),
279
- body: {
280
- _: "msg_container",
281
- messages: [message, ack],
282
- },
283
- };
284
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("container msg_id =", message.msg_id, "seqno =", message.seqno);
285
- }
286
- try {
287
- const payload = await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_encryptMessage).call(this, message);
288
- await this.transport.transport.send(payload);
289
- pendingMessage.promiseWithResolvers.resolve(msg_id);
290
- }
291
- catch (err) {
292
- pendingMessage.promiseWithResolvers.reject(err);
293
- return;
294
- }
295
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").out(message);
296
- __classPrivateFieldGet(this, _SessionEncrypted_sentMessages, "f").add(msg_id);
297
- if (!(message.body instanceof Uint8Array)) {
298
- const msg_ids = message.body.messages.map((v) => v.msg_id);
299
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("sent container", message.msg_id, "with messages", ...msg_ids);
300
- __classPrivateFieldGet(this, _SessionEncrypted_containers, "f").set(message.msg_id, msg_ids);
301
- }
302
- else {
303
- __classPrivateFieldGet(this, _SessionEncrypted_LsendLoop, "f").debug("sent message", message.msg_id);
304
- }
305
- }, _SessionEncrypted_receiveLoopBody = async function _SessionEncrypted_receiveLoopBody(loop) {
306
- let message;
307
- try {
308
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").debug("receiving");
309
- message = await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_receive).call(this);
310
- }
311
- catch (err) {
312
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").error("failed to receive message:", err);
174
+ async #encryptMessage(message) {
175
+ const payloadWriter = new TLWriter();
176
+ payloadWriter.writeInt64(this.state.serverSalt);
177
+ payloadWriter.writeInt64(this.#id);
178
+ payloadWriter.write(await serializeMessage(message));
179
+ payloadWriter.write(new Uint8Array(mod(-(payloadWriter.buffer.length + 12), 16) + 12));
180
+ const payload = payloadWriter.buffer;
181
+ const messageKey = (await sha256(concat([this.#authKey.subarray(88, 120), payload]))).subarray(8, 24);
182
+ const a = await sha256(concat([messageKey, this.#authKey.subarray(0, 36)]));
183
+ const b = await sha256(concat([this.#authKey.subarray(40, 76), messageKey]));
184
+ const aesKey = concat([a.subarray(0, 8), b.subarray(8, 24), a.subarray(24, 32)]);
185
+ const aesIV = concat([b.subarray(0, 8), a.subarray(8, 24), b.subarray(24, 32)]);
186
+ const messageWriter = new TLWriter();
187
+ messageWriter.writeInt64(this.#authKeyId);
188
+ messageWriter.write(messageKey);
189
+ messageWriter.write(ige256Encrypt(payload, aesKey, aesIV));
190
+ return messageWriter.buffer;
191
+ }
192
+ async #decryptMessage(buffer) {
193
+ const reader = new TLReader(buffer);
194
+ assertEquals(reader.readInt64(), this.#authKeyId);
195
+ const messageKey_ = reader.readInt128();
196
+ const messageKey = intToBytes(messageKey_, 16);
197
+ const a = await sha256(concat([messageKey, this.#authKey.subarray(8, 44)]));
198
+ const b = await sha256(concat([this.#authKey.subarray(48, 84), messageKey]));
199
+ const aesKey = concat([a.subarray(0, 8), b.subarray(8, 24), a.subarray(24, 32)]);
200
+ const aesIv = concat([b.subarray(0, 8), a.subarray(8, 24), b.subarray(24, 32)]);
201
+ const plaintext = ige256Decrypt(reader.buffer, aesKey, aesIv);
202
+ assertEquals(plaintext.buffer.byteLength % 4, 0);
203
+ const plainReader = new TLReader(plaintext);
204
+ const _salt = plainReader.readInt64();
205
+ const _sessionId_ = plainReader.readInt64(false);
206
+ return deserializeMessage(plainReader);
207
+ }
208
+ //// SEND LOOP ////
209
+ #awakeSendLoop;
210
+ #sendLoop = new AbortableLoop(this.#sendLoopBody.bind(this), (err) => {
211
+ this.#LsendLoop.error("unhandled receive loop error:", err);
212
+ });
213
+ async #sendLoopBody(loop, signal) {
313
214
  if (!this.isConnected) {
314
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").debug("aborting as not connected");
215
+ this.#LsendLoop.debug("aborting as not connected");
315
216
  loop.abort();
316
217
  return;
317
218
  }
318
- else {
219
+ const pendingMessage = this.#pendingMessages.shift();
220
+ if (pendingMessage === undefined) {
221
+ this.#LsendLoop.debug("no pending messages");
222
+ return await new Promise((resolve) => {
223
+ const onAbort = () => {
224
+ this.#LsendLoop.debug("got aborted while sleeping");
225
+ resolve();
226
+ };
227
+ signal.addEventListener("abort", onAbort);
228
+ this.#awakeSendLoop = () => {
229
+ this.#LsendLoop.debug("got awaken");
230
+ resolve();
231
+ signal.removeEventListener("abort", onAbort);
232
+ };
233
+ });
234
+ }
235
+ const msg_id = this.state.nextMessageId();
236
+ const seqno = this.state.nextSeqNo(true);
237
+ let message = {
238
+ _: "message",
239
+ msg_id,
240
+ seqno,
241
+ body: pendingMessage.body,
242
+ };
243
+ this.#LsendLoop.debug("msg_id =", msg_id, "seqno =", seqno);
244
+ if (this.#toAcknowledge.length) {
245
+ const msg_ids = this.#toAcknowledge.splice(0, 8192);
246
+ this.#LsendLoop.debug("acknowledging", msg_ids.length, "message(s) while sending this one");
247
+ const ack = {
248
+ _: "message",
249
+ msg_id: this.state.nextMessageId(),
250
+ seqno: this.state.nextSeqNo(false),
251
+ body: Mtproto.serializeObject({ _: "msgs_ack", msg_ids }),
252
+ };
253
+ this.#LsendLoop.debug("msgs_ack msg_id =", ack.msg_id, "seqno =", seqno);
254
+ this.#pendingAcks.set(ack.msg_id, msg_ids);
255
+ message = {
256
+ _: "message",
257
+ msg_id: this.state.nextMessageId(),
258
+ seqno: this.state.nextSeqNo(false),
259
+ body: {
260
+ _: "msg_container",
261
+ messages: [message, ack],
262
+ },
263
+ };
264
+ this.#LsendLoop.debug("container msg_id =", message.msg_id, "seqno =", message.seqno);
265
+ }
266
+ try {
267
+ const payload = await this.#encryptMessage(message);
268
+ await this.transport.transport.send(payload);
269
+ pendingMessage.promiseWithResolvers.resolve(msg_id);
270
+ }
271
+ catch (err) {
272
+ pendingMessage.promiseWithResolvers.reject(err);
319
273
  return;
320
274
  }
321
- }
322
- try {
323
- if (message.body instanceof Uint8Array) {
324
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessage).call(this, message.msg_id, message.body, null);
275
+ this.#LsendLoop.out(message);
276
+ this.#sentMessages.add(msg_id);
277
+ if (!(message.body instanceof Uint8Array)) {
278
+ const msg_ids = message.body.messages.map((v) => v.msg_id);
279
+ this.#LsendLoop.debug("sent container", message.msg_id, "with messages", ...msg_ids);
280
+ this.#containers.set(message.msg_id, msg_ids);
325
281
  }
326
282
  else {
327
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessageContainer).call(this, message.msg_id, message.body);
283
+ this.#LsendLoop.debug("sent message", message.msg_id);
328
284
  }
329
285
  }
330
- catch (err) {
331
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").error("failed to handle message:", err);
332
- }
333
- }, _SessionEncrypted_onMessage =
334
- //// RECEIVE LOOP HANDLERS ////
335
- async function _SessionEncrypted_onMessage(msgId, body, containerId) {
336
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").debug("received message with ID", msgId, "and size", body.length, "inside", ...(containerId === null ? ["no container"] : ["container", containerId]));
337
- const logger = __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").branch(msgId + "");
338
- let reader = new TLReader(body);
339
- let id = reader.readInt32(false);
340
- if (id === GZIP_PACKED) {
341
- logger.debug("unpacking compressed body");
342
- reader = new TLReader(await gunzip(reader.readBytes()));
343
- id = reader.readInt32(false);
344
- }
345
- if (id === RPC_RESULT) {
346
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onRpcResult).call(this, msgId, reader.buffer, logger);
347
- return;
348
- }
349
- if (!Mtproto.schema.identifierToName[id]) {
350
- logger.debug("identified body as a non-MTProto constructor");
351
- reader.unreadInt32();
352
- this.handlers.onUpdate?.(reader.buffer);
353
- return;
354
- }
355
- let type;
356
- try {
357
- reader.unreadInt32();
358
- type = await Mtproto.deserializeType(X, reader);
359
- }
360
- catch (err) {
361
- logger.error("failed to deserialize MTProto type:", err);
362
- return;
363
- }
364
- logger.debug("received", repr(type));
365
- if (Mtproto.is("new_session_created", type)) {
366
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onNewSessionCreated).call(this, msgId, type);
367
- }
368
- else if (Mtproto.is("pong", type)) {
369
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onPong).call(this, msgId, type);
370
- }
371
- else if (Mtproto.is("bad_server_salt", type)) {
372
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onBadServerSalt).call(this, type);
373
- }
374
- else if (Mtproto.is("bad_msg_notification", type)) {
375
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onBadMsgNotification).call(this, msgId, type, logger);
376
- }
377
- else if (Mtproto.is("msg_detailed_info", type)) {
378
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMsgDetailedInfo).call(this, type, logger);
379
- }
380
- else if (Mtproto.is("msg_new_detailed_info", type)) {
381
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMsgNewDetailedInfo).call(this, type, logger);
382
- }
383
- else {
384
- logger.warning(`unhandled MTProto type: ${repr(type)}`);
385
- }
386
- }, _SessionEncrypted_onRpcResult = async function _SessionEncrypted_onRpcResult(msgId, body, logger) {
387
- logger.debug("received rpc_result");
388
- __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").push(msgId);
389
- let reader = new TLReader(body);
390
- const reqMsgId = reader.readInt64();
391
- let id = reader.readInt32(false);
392
- if (id === GZIP_PACKED) {
393
- logger.debug("unpacking compressed rpc_result");
394
- reader = new TLReader(await gunzip(reader.readBytes()));
395
- id = reader.readInt32(false);
396
- reader.unreadInt32();
397
- }
398
- else {
399
- reader.unreadInt32();
400
- }
401
- if (id === RPC_ERROR) {
402
- logger.debug("received rpc_error from message", msgId);
403
- const error = await Mtproto.deserializeType("rpc_error", reader);
404
- this.handlers.onRpcError?.(reqMsgId, error);
405
- }
406
- else {
407
- this.handlers.onRpcResult?.(reqMsgId, reader.buffer);
408
- }
409
- }, _SessionEncrypted_onMsgDetailedInfo = function _SessionEncrypted_onMsgDetailedInfo(msgDetailedInfo, logger) {
410
- logger.debug("scheduling the acknowledgement of", msgDetailedInfo.answer_msg_id, "because of", msgDetailedInfo._);
411
- __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").push(msgDetailedInfo.answer_msg_id);
412
- }, _SessionEncrypted_onMsgNewDetailedInfo = function _SessionEncrypted_onMsgNewDetailedInfo(msgNewDetailedInfo, logger) {
413
- logger.debug("scheduling the acknowledgement of", msgNewDetailedInfo.answer_msg_id, "because of", msgNewDetailedInfo._);
414
- __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").push(msgNewDetailedInfo.answer_msg_id);
415
- }, _SessionEncrypted_onBadMsgNotification = async function _SessionEncrypted_onBadMsgNotification(msgId, badMsgNotification, logger) {
416
- let low = false;
417
- switch (badMsgNotification.error_code) {
418
- case 16: // message ID too low
419
- low = true;
420
- /* falls through */
421
- case 17: // message ID too high
422
- this.state.timeDifference = Math.abs(toUnixTimestamp(new Date()) - Number(msgId >> 32n));
423
- if (!low) {
424
- this.state.timeDifference = -this.state.timeDifference;
425
- logger.debug("resetting time difference to", -this.state.timeDifference, "because the ID of the message", badMsgNotification.bad_msg_id, "was too high");
426
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_invalidateSession).call(this, "message ID too high");
286
+ //// RECEIVE LOOP ////
287
+ #receiveLoop = new AbortableLoop(this.#receiveLoopBody.bind(this), (err) => {
288
+ this.#LreceiveLoop.error("unhandled receive loop error:", err);
289
+ });
290
+ async #receiveLoopBody(loop) {
291
+ let message;
292
+ try {
293
+ this.#LreceiveLoop.debug("receiving");
294
+ message = await this.#receive();
295
+ }
296
+ catch (err) {
297
+ this.#LreceiveLoop.error("failed to receive message:", err);
298
+ if (!this.isConnected) {
299
+ this.#LreceiveLoop.debug("aborting as not connected");
300
+ loop.abort();
427
301
  return;
428
302
  }
429
303
  else {
430
- logger.debug("resending message", badMsgNotification.bad_msg_id, "because its ID was too low");
304
+ return;
431
305
  }
432
- break;
433
- case 48: // bad server salt
434
- // resend
435
- __classPrivateFieldGet(this, _SessionEncrypted_L, "f").debug("resending message that caused bad_server_salt");
436
- break;
437
- default:
438
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_invalidateSession).call(this, "unexpected bad_msg_notification");
439
- return;
440
- }
441
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessageFailed).call(this, badMsgNotification.bad_msg_id, new SessionError(badMsgNotification._));
442
- }, _SessionEncrypted_onBadServerSalt = function _SessionEncrypted_onBadServerSalt(badServerSalt) {
443
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_setServerSalt).call(this, badServerSalt.new_server_salt);
444
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessageFailed).call(this, badServerSalt.bad_msg_id, new SessionError(badServerSalt._));
445
- }, _SessionEncrypted_onPong = function _SessionEncrypted_onPong(msgId, pong) {
446
- __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").push(msgId);
447
- const pendingPing = __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").get(pong.msg_id);
448
- if (pendingPing) {
449
- pendingPing.promiseWithResolvers.resolve(pong);
450
- __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").delete(pong.msg_id);
451
- }
452
- else {
453
- // pong is not ours
454
- this.handlers.onPong?.(pong);
306
+ }
307
+ try {
308
+ if (message.body instanceof Uint8Array) {
309
+ await this.#onMessage(message.msg_id, message.body, null);
310
+ }
311
+ else {
312
+ await this.#onMessageContainer(message.msg_id, message.body);
313
+ }
314
+ }
315
+ catch (err) {
316
+ this.#LreceiveLoop.error("failed to handle message:", err);
317
+ }
455
318
  }
456
- }, _SessionEncrypted_onNewSessionCreated = function _SessionEncrypted_onNewSessionCreated(msgId, newSessionCreated) {
457
- __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_setServerSalt).call(this, newSessionCreated.server_salt);
458
- __classPrivateFieldGet(this, _SessionEncrypted_toAcknowledge, "f").push(msgId);
459
- }, _SessionEncrypted_onMessageContainer = async function _SessionEncrypted_onMessageContainer(msgId, msgContainer) {
460
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").debug("received container with ID", msgId, "and", msgContainer.messages.length, "message(s)");
461
- for (const message of msgContainer.messages) {
462
- if (message.body instanceof Uint8Array) {
463
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessage).call(this, message.msg_id, message.body, msgId);
319
+ //// RECEIVE LOOP HANDLERS ////
320
+ async #onMessage(msgId, body, containerId) {
321
+ this.#LreceiveLoop.debug("received message with ID", msgId, "and size", body.length, "inside", ...(containerId === null ? ["no container"] : ["container", containerId]));
322
+ const logger = this.#LreceiveLoop.branch(msgId + "");
323
+ let reader = new TLReader(body);
324
+ let id = reader.readInt32(false);
325
+ if (id === GZIP_PACKED) {
326
+ logger.debug("unpacking compressed body");
327
+ reader = new TLReader(await gunzip(reader.readBytes()));
328
+ id = reader.readInt32(false);
329
+ }
330
+ if (id === RPC_RESULT) {
331
+ this.#onRpcResult(msgId, reader.buffer, logger);
332
+ return;
333
+ }
334
+ if (!Mtproto.schema.identifierToName[id]) {
335
+ logger.debug("identified body as a non-MTProto constructor");
336
+ reader.unreadInt32();
337
+ this.handlers.onUpdate?.(reader.buffer);
338
+ return;
339
+ }
340
+ let type;
341
+ try {
342
+ reader.unreadInt32();
343
+ type = await Mtproto.deserializeType(X, reader);
344
+ }
345
+ catch (err) {
346
+ logger.error("failed to deserialize MTProto type:", err);
347
+ return;
348
+ }
349
+ logger.debug("received", repr(type));
350
+ if (Mtproto.is("new_session_created", type)) {
351
+ this.#onNewSessionCreated(msgId, type);
352
+ }
353
+ else if (Mtproto.is("pong", type)) {
354
+ this.#onPong(msgId, type);
355
+ }
356
+ else if (Mtproto.is("bad_server_salt", type)) {
357
+ this.#onBadServerSalt(type);
358
+ }
359
+ else if (Mtproto.is("bad_msg_notification", type)) {
360
+ await this.#onBadMsgNotification(msgId, type, logger);
361
+ }
362
+ else if (Mtproto.is("msg_detailed_info", type)) {
363
+ this.#onMsgDetailedInfo(type, logger);
364
+ }
365
+ else if (Mtproto.is("msg_new_detailed_info", type)) {
366
+ this.#onMsgNewDetailedInfo(type, logger);
464
367
  }
465
368
  else {
466
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_onMessageContainer).call(this, msgId, message.body);
369
+ logger.warning(`unhandled MTProto type: ${repr(type)}`);
467
370
  }
468
371
  }
469
- }, _SessionEncrypted_pingLoopBody = async function _SessionEncrypted_pingLoopBody(_loop, signal) {
470
- const ms = Math.max(0, __classPrivateFieldGet(this, _SessionEncrypted_pingInterval, "f") - __classPrivateFieldGet(this, _SessionEncrypted_timeElapsed, "f"));
471
- if (ms) {
472
- __classPrivateFieldGet(this, _SessionEncrypted_LpingLoop, "f").debug(`sending ping in ${ms}ms`);
473
- await delay(ms, { signal });
474
- }
475
- else {
476
- __classPrivateFieldGet(this, _SessionEncrypted_LpingLoop, "f").debug("sending ping now");
372
+ async #onRpcResult(msgId, body, logger) {
373
+ logger.debug("received rpc_result");
374
+ this.#toAcknowledge.push(msgId);
375
+ let reader = new TLReader(body);
376
+ const reqMsgId = reader.readInt64();
377
+ let id = reader.readInt32(false);
378
+ if (id === GZIP_PACKED) {
379
+ logger.debug("unpacking compressed rpc_result");
380
+ reader = new TLReader(await gunzip(reader.readBytes()));
381
+ id = reader.readInt32(false);
382
+ reader.unreadInt32();
383
+ }
384
+ else {
385
+ reader.unreadInt32();
386
+ }
387
+ if (id === RPC_ERROR) {
388
+ logger.debug("received rpc_error from message", msgId);
389
+ const error = await Mtproto.deserializeType("rpc_error", reader);
390
+ this.handlers.onRpcError?.(reqMsgId, error);
391
+ }
392
+ else {
393
+ this.handlers.onRpcResult?.(reqMsgId, reader.buffer);
394
+ }
477
395
  }
478
- signal.throwIfAborted();
479
- const then = Date.now();
480
- try {
481
- await __classPrivateFieldGet(this, _SessionEncrypted_instances, "m", _SessionEncrypted_sendPingDelayDisconnect).call(this, __classPrivateFieldGet(this, _SessionEncrypted_pingInterval, "f") / SECOND + 15);
482
- __classPrivateFieldGet(this, _SessionEncrypted_LpingLoop, "f").debug("received pong");
396
+ #onMsgDetailedInfo(msgDetailedInfo, logger) {
397
+ logger.debug("scheduling the acknowledgement of", msgDetailedInfo.answer_msg_id, "because of", msgDetailedInfo._);
398
+ this.#toAcknowledge.push(msgDetailedInfo.answer_msg_id);
399
+ }
400
+ #onMsgNewDetailedInfo(msgNewDetailedInfo, logger) {
401
+ logger.debug("scheduling the acknowledgement of", msgNewDetailedInfo.answer_msg_id, "because of", msgNewDetailedInfo._);
402
+ this.#toAcknowledge.push(msgNewDetailedInfo.answer_msg_id);
403
+ }
404
+ async #onBadMsgNotification(msgId, badMsgNotification, logger) {
405
+ let low = false;
406
+ switch (badMsgNotification.error_code) {
407
+ case 16: // message ID too low
408
+ low = true;
409
+ /* falls through */
410
+ case 17: // message ID too high
411
+ this.state.timeDifference = Math.abs(toUnixTimestamp(new Date()) - Number(msgId >> 32n));
412
+ if (!low) {
413
+ this.state.timeDifference = -this.state.timeDifference;
414
+ logger.debug("resetting time difference to", -this.state.timeDifference, "because the ID of the message", badMsgNotification.bad_msg_id, "was too high");
415
+ await this.#invalidateSession("message ID too high");
416
+ return;
417
+ }
418
+ else {
419
+ logger.debug("resending message", badMsgNotification.bad_msg_id, "because its ID was too low");
420
+ }
421
+ break;
422
+ case 48: // bad server salt
423
+ // resend
424
+ this.#L.debug("resending message that caused bad_server_salt");
425
+ break;
426
+ default:
427
+ await this.#invalidateSession("unexpected bad_msg_notification");
428
+ return;
429
+ }
430
+ this.#onMessageFailed(badMsgNotification.bad_msg_id, new SessionError(badMsgNotification._));
431
+ }
432
+ #onBadServerSalt(badServerSalt) {
433
+ this.#setServerSalt(badServerSalt.new_server_salt);
434
+ this.#onMessageFailed(badServerSalt.bad_msg_id, new SessionError(badServerSalt._));
435
+ }
436
+ #onPong(msgId, pong) {
437
+ this.#toAcknowledge.push(msgId);
438
+ const pendingPing = this.#pendingPings.get(pong.msg_id);
439
+ if (pendingPing) {
440
+ pendingPing.promiseWithResolvers.resolve(pong);
441
+ this.#pendingPings.delete(pong.msg_id);
442
+ }
443
+ else {
444
+ // pong is not ours
445
+ this.handlers.onPong?.(pong);
446
+ }
483
447
  }
484
- finally {
485
- __classPrivateFieldSet(this, _SessionEncrypted_timeElapsed, Date.now() - then, "f");
486
- __classPrivateFieldGet(this, _SessionEncrypted_LpingLoop, "f").debug(`took ${__classPrivateFieldGet(this, _SessionEncrypted_timeElapsed, "f")}`);
448
+ #onNewSessionCreated(msgId, newSessionCreated) {
449
+ this.#setServerSalt(newSessionCreated.server_salt);
450
+ this.#toAcknowledge.push(msgId);
487
451
  }
488
- signal.throwIfAborted();
489
- }, _SessionEncrypted_sendPingDelayDisconnect = async function _SessionEncrypted_sendPingDelayDisconnect(disconnect_delay) {
490
- const ping_id = getRandomId();
491
- const call = { _: "ping_delay_disconnect", ping_id, disconnect_delay };
492
- const messageId = await this.send(Mtproto.serializeObject(call));
493
- const promiseWithResolvers = Promise.withResolvers();
494
- __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").set(messageId, { call, promiseWithResolvers });
495
- await promiseWithResolvers.promise;
496
- }, _SessionEncrypted_resendPendingPing = async function _SessionEncrypted_resendPendingPing(pendingPing) {
497
- try {
498
- const messageId = await this.send(Mtproto.serializeObject(pendingPing.call));
499
- __classPrivateFieldGet(this, _SessionEncrypted_pendingPings, "f").set(messageId, pendingPing);
500
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").debug("ping resent");
452
+ async #onMessageContainer(msgId, msgContainer) {
453
+ this.#LreceiveLoop.debug("received container with ID", msgId, "and", msgContainer.messages.length, "message(s)");
454
+ for (const message of msgContainer.messages) {
455
+ if (message.body instanceof Uint8Array) {
456
+ await this.#onMessage(message.msg_id, message.body, msgId);
457
+ }
458
+ else {
459
+ await this.#onMessageContainer(msgId, message.body);
460
+ }
461
+ }
501
462
  }
502
- catch (err) {
503
- __classPrivateFieldGet(this, _SessionEncrypted_LreceiveLoop, "f").debug("rejecting ping because of failed resend:", err);
504
- pendingPing.promiseWithResolvers.reject(err);
463
+ //// PING LOOP ////
464
+ #pingInterval = 56 * SECOND;
465
+ #pingLoop = new AbortableLoop(this.#pingLoopBody.bind(this), (_, err) => {
466
+ this.#LpingLoop.error(err);
467
+ });
468
+ #timeElapsed = 0;
469
+ async #pingLoopBody(_loop, signal) {
470
+ const ms = Math.max(0, this.#pingInterval - this.#timeElapsed);
471
+ if (ms) {
472
+ this.#LpingLoop.debug(`sending ping in ${ms}ms`);
473
+ await delay(ms, { signal });
474
+ }
475
+ else {
476
+ this.#LpingLoop.debug("sending ping now");
477
+ }
478
+ signal.throwIfAborted();
479
+ const then = Date.now();
480
+ try {
481
+ await this.#sendPingDelayDisconnect(this.#pingInterval / SECOND + 15);
482
+ this.#LpingLoop.debug("received pong");
483
+ }
484
+ finally {
485
+ this.#timeElapsed = Date.now() - then;
486
+ this.#LpingLoop.debug(`took ${this.#timeElapsed}`);
487
+ }
488
+ signal.throwIfAborted();
489
+ }
490
+ async #sendPingDelayDisconnect(disconnect_delay) {
491
+ const ping_id = getRandomId();
492
+ const call = { _: "ping_delay_disconnect", ping_id, disconnect_delay };
493
+ const messageId = await this.send(Mtproto.serializeObject(call));
494
+ const promiseWithResolvers = Promise.withResolvers();
495
+ this.#pendingPings.set(messageId, { call, promiseWithResolvers });
496
+ await promiseWithResolvers.promise;
497
+ }
498
+ async #resendPendingPing(pendingPing) {
499
+ try {
500
+ const messageId = await this.send(Mtproto.serializeObject(pendingPing.call));
501
+ this.#pendingPings.set(messageId, pendingPing);
502
+ this.#LreceiveLoop.debug("ping resent");
503
+ }
504
+ catch (err) {
505
+ this.#LreceiveLoop.debug("rejecting ping because of failed resend:", err);
506
+ pendingPing.promiseWithResolvers.reject(err);
507
+ }
505
508
  }
506
- };
507
- _SessionEncrypted_TGCRYPTO_INITED = { value: false };
509
+ }