@mtcute/core 0.1.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 (502) hide show
  1. package/LICENSE +8 -0
  2. package/README.md +26 -0
  3. package/cjs/base-client.d.ts +297 -0
  4. package/cjs/base-client.js +324 -0
  5. package/cjs/base-client.js.map +1 -0
  6. package/cjs/index.d.ts +10 -0
  7. package/cjs/index.js +30 -0
  8. package/cjs/index.js.map +1 -0
  9. package/cjs/network/auth-key.d.ts +21 -0
  10. package/cjs/network/auth-key.js +101 -0
  11. package/cjs/network/auth-key.js.map +1 -0
  12. package/cjs/network/authorization.d.ts +9 -0
  13. package/cjs/network/authorization.js +332 -0
  14. package/cjs/network/authorization.js.map +1 -0
  15. package/cjs/network/config-manager.d.ts +33 -0
  16. package/cjs/network/config-manager.js +93 -0
  17. package/cjs/network/config-manager.js.map +1 -0
  18. package/cjs/network/index.d.ts +4 -0
  19. package/cjs/network/index.js +20 -0
  20. package/cjs/network/index.js.map +1 -0
  21. package/cjs/network/mtproto-session.d.ts +116 -0
  22. package/cjs/network/mtproto-session.js +209 -0
  23. package/cjs/network/mtproto-session.js.map +1 -0
  24. package/cjs/network/multi-session-connection.d.ts +33 -0
  25. package/cjs/network/multi-session-connection.js +243 -0
  26. package/cjs/network/multi-session-connection.js.map +1 -0
  27. package/cjs/network/network-manager.d.ts +190 -0
  28. package/cjs/network/network-manager.js +547 -0
  29. package/cjs/network/network-manager.js.map +1 -0
  30. package/cjs/network/persistent-connection.d.ts +51 -0
  31. package/cjs/network/persistent-connection.js +173 -0
  32. package/cjs/network/persistent-connection.js.map +1 -0
  33. package/cjs/network/reconnection.d.ts +11 -0
  34. package/cjs/network/reconnection.js +18 -0
  35. package/cjs/network/reconnection.js.map +1 -0
  36. package/cjs/network/session-connection.d.ts +72 -0
  37. package/cjs/network/session-connection.js +1363 -0
  38. package/cjs/network/session-connection.js.map +1 -0
  39. package/cjs/network/transports/abstract.d.ts +99 -0
  40. package/cjs/network/transports/abstract.js +38 -0
  41. package/cjs/network/transports/abstract.js.map +1 -0
  42. package/cjs/network/transports/index.d.ts +8 -0
  43. package/cjs/network/transports/index.js +26 -0
  44. package/cjs/network/transports/index.js.map +1 -0
  45. package/cjs/network/transports/intermediate.d.ts +20 -0
  46. package/cjs/network/transports/intermediate.js +67 -0
  47. package/cjs/network/transports/intermediate.js.map +1 -0
  48. package/cjs/network/transports/obfuscated.d.ts +18 -0
  49. package/cjs/network/transports/obfuscated.js +83 -0
  50. package/cjs/network/transports/obfuscated.js.map +1 -0
  51. package/cjs/network/transports/streamed.d.ts +24 -0
  52. package/cjs/network/transports/streamed.js +32 -0
  53. package/cjs/network/transports/streamed.js.map +1 -0
  54. package/cjs/network/transports/tcp.d.ts +33 -0
  55. package/cjs/network/transports/tcp.js +130 -0
  56. package/cjs/network/transports/tcp.js.map +1 -0
  57. package/cjs/network/transports/websocket.d.ts +47 -0
  58. package/cjs/network/transports/websocket.js +124 -0
  59. package/cjs/network/transports/websocket.js.map +1 -0
  60. package/cjs/network/transports/wrapped.d.ts +11 -0
  61. package/cjs/network/transports/wrapped.js +26 -0
  62. package/cjs/network/transports/wrapped.js.map +1 -0
  63. package/cjs/package.json +3 -0
  64. package/cjs/storage/abstract.d.ts +174 -0
  65. package/cjs/storage/abstract.js +3 -0
  66. package/cjs/storage/abstract.js.map +1 -0
  67. package/cjs/storage/index.d.ts +5 -0
  68. package/cjs/storage/index.js +22 -0
  69. package/cjs/storage/index.js.map +1 -0
  70. package/cjs/storage/json-file.d.ts +31 -0
  71. package/cjs/storage/json-file.js +90 -0
  72. package/cjs/storage/json-file.js.map +1 -0
  73. package/cjs/storage/json.d.ts +9 -0
  74. package/cjs/storage/json.js +65 -0
  75. package/cjs/storage/json.js.map +1 -0
  76. package/cjs/storage/localstorage.d.ts +7 -0
  77. package/cjs/storage/localstorage.js +25 -0
  78. package/cjs/storage/localstorage.js.map +1 -0
  79. package/cjs/storage/memory.d.ts +98 -0
  80. package/cjs/storage/memory.js +299 -0
  81. package/cjs/storage/memory.js.map +1 -0
  82. package/cjs/types/errors.d.ts +53 -0
  83. package/cjs/types/errors.js +58 -0
  84. package/cjs/types/errors.js.map +1 -0
  85. package/cjs/types/index.d.ts +3 -0
  86. package/cjs/types/index.js +20 -0
  87. package/cjs/types/index.js.map +1 -0
  88. package/cjs/types/peers.d.ts +4 -0
  89. package/cjs/types/peers.js +3 -0
  90. package/cjs/types/peers.js.map +1 -0
  91. package/cjs/types/utils.d.ts +6 -0
  92. package/cjs/types/utils.js +9 -0
  93. package/cjs/types/utils.js.map +1 -0
  94. package/cjs/utils/async-lock.d.ts +10 -0
  95. package/cjs/utils/async-lock.js +43 -0
  96. package/cjs/utils/async-lock.js.map +1 -0
  97. package/cjs/utils/bigint-utils.d.ts +40 -0
  98. package/cjs/utils/bigint-utils.js +104 -0
  99. package/cjs/utils/bigint-utils.js.map +1 -0
  100. package/cjs/utils/binary/asn1-parser.d.ts +17 -0
  101. package/cjs/utils/binary/asn1-parser.js +121 -0
  102. package/cjs/utils/binary/asn1-parser.js.map +1 -0
  103. package/cjs/utils/buffer-utils.d.ts +21 -0
  104. package/cjs/utils/buffer-utils.js +63 -0
  105. package/cjs/utils/buffer-utils.js.map +1 -0
  106. package/cjs/utils/condition-variable.d.ts +9 -0
  107. package/cjs/utils/condition-variable.js +28 -0
  108. package/cjs/utils/condition-variable.js.map +1 -0
  109. package/cjs/utils/controllable-promise.d.ts +16 -0
  110. package/cjs/utils/controllable-promise.js +25 -0
  111. package/cjs/utils/controllable-promise.js.map +1 -0
  112. package/cjs/utils/crypto/abstract.d.ts +23 -0
  113. package/cjs/utils/crypto/abstract.js +19 -0
  114. package/cjs/utils/crypto/abstract.js.map +1 -0
  115. package/cjs/utils/crypto/common.d.ts +12 -0
  116. package/cjs/utils/crypto/common.js +54 -0
  117. package/cjs/utils/crypto/common.js.map +1 -0
  118. package/cjs/utils/crypto/factorization.d.ts +5 -0
  119. package/cjs/utils/crypto/factorization.js +69 -0
  120. package/cjs/utils/crypto/factorization.js.map +1 -0
  121. package/cjs/utils/crypto/index.d.ts +5 -0
  122. package/cjs/utils/crypto/index.js +23 -0
  123. package/cjs/utils/crypto/index.js.map +1 -0
  124. package/cjs/utils/crypto/keys.d.ts +27 -0
  125. package/cjs/utils/crypto/keys.js +70 -0
  126. package/cjs/utils/crypto/keys.js.map +1 -0
  127. package/cjs/utils/crypto/miller-rabin.d.ts +2 -0
  128. package/cjs/utils/crypto/miller-rabin.js +44 -0
  129. package/cjs/utils/crypto/miller-rabin.js.map +1 -0
  130. package/cjs/utils/crypto/mtproto.d.ts +31 -0
  131. package/cjs/utils/crypto/mtproto.js +66 -0
  132. package/cjs/utils/crypto/mtproto.js.map +1 -0
  133. package/cjs/utils/crypto/node-crypto.d.ts +10 -0
  134. package/cjs/utils/crypto/node-crypto.js +46 -0
  135. package/cjs/utils/crypto/node-crypto.js.map +1 -0
  136. package/cjs/utils/crypto/password.d.ts +29 -0
  137. package/cjs/utils/crypto/password.js +106 -0
  138. package/cjs/utils/crypto/password.js.map +1 -0
  139. package/cjs/utils/crypto/subtle.d.ts +12 -0
  140. package/cjs/utils/crypto/subtle.js +86 -0
  141. package/cjs/utils/crypto/subtle.js.map +1 -0
  142. package/cjs/utils/crypto/utils.d.ts +14 -0
  143. package/cjs/utils/crypto/utils.js +30 -0
  144. package/cjs/utils/crypto/utils.js.map +1 -0
  145. package/cjs/utils/default-dcs.d.ts +7 -0
  146. package/cjs/utils/default-dcs.js +76 -0
  147. package/cjs/utils/default-dcs.js.map +1 -0
  148. package/cjs/utils/deque.d.ts +29 -0
  149. package/cjs/utils/deque.js +210 -0
  150. package/cjs/utils/deque.js.map +1 -0
  151. package/cjs/utils/early-timer.d.ts +42 -0
  152. package/cjs/utils/early-timer.js +79 -0
  153. package/cjs/utils/early-timer.js.map +1 -0
  154. package/cjs/utils/flood-control.d.ts +14 -0
  155. package/cjs/utils/flood-control.js +65 -0
  156. package/cjs/utils/flood-control.js.map +1 -0
  157. package/cjs/utils/function-utils.d.ts +13 -0
  158. package/cjs/utils/function-utils.js +30 -0
  159. package/cjs/utils/function-utils.js.map +1 -0
  160. package/cjs/utils/index.d.ts +24 -0
  161. package/cjs/utils/index.js +41 -0
  162. package/cjs/utils/index.js.map +1 -0
  163. package/cjs/utils/linked-list.d.ts +21 -0
  164. package/cjs/utils/linked-list.js +73 -0
  165. package/cjs/utils/linked-list.js.map +1 -0
  166. package/cjs/utils/links/bots.d.ts +71 -0
  167. package/cjs/utils/links/bots.js +259 -0
  168. package/cjs/utils/links/bots.js.map +1 -0
  169. package/cjs/utils/links/bundle.d.ts +7 -0
  170. package/cjs/utils/links/bundle.js +24 -0
  171. package/cjs/utils/links/bundle.js.map +1 -0
  172. package/cjs/utils/links/calls.d.ts +16 -0
  173. package/cjs/utils/links/calls.js +59 -0
  174. package/cjs/utils/links/calls.js.map +1 -0
  175. package/cjs/utils/links/chat.d.ts +46 -0
  176. package/cjs/utils/links/chat.js +160 -0
  177. package/cjs/utils/links/chat.js.map +1 -0
  178. package/cjs/utils/links/common.d.ts +31 -0
  179. package/cjs/utils/links/common.js +60 -0
  180. package/cjs/utils/links/common.js.map +1 -0
  181. package/cjs/utils/links/index.d.ts +2 -0
  182. package/cjs/utils/links/index.js +29 -0
  183. package/cjs/utils/links/index.js.map +1 -0
  184. package/cjs/utils/links/misc.d.ts +19 -0
  185. package/cjs/utils/links/misc.js +77 -0
  186. package/cjs/utils/links/misc.js.map +1 -0
  187. package/cjs/utils/links/proxy.d.ts +17 -0
  188. package/cjs/utils/links/proxy.js +61 -0
  189. package/cjs/utils/links/proxy.js.map +1 -0
  190. package/cjs/utils/links/stickers.d.ts +9 -0
  191. package/cjs/utils/links/stickers.js +28 -0
  192. package/cjs/utils/links/stickers.js.map +1 -0
  193. package/cjs/utils/links/user.d.ts +27 -0
  194. package/cjs/utils/links/user.js +81 -0
  195. package/cjs/utils/links/user.js.map +1 -0
  196. package/cjs/utils/logger.d.ts +54 -0
  197. package/cjs/utils/logger.js +158 -0
  198. package/cjs/utils/logger.js.map +1 -0
  199. package/cjs/utils/long-utils.d.ts +75 -0
  200. package/cjs/utils/long-utils.js +161 -0
  201. package/cjs/utils/long-utils.js.map +1 -0
  202. package/cjs/utils/lru-map.d.ts +21 -0
  203. package/cjs/utils/lru-map.js +107 -0
  204. package/cjs/utils/lru-map.js.map +1 -0
  205. package/cjs/utils/lru-set.d.ts +22 -0
  206. package/cjs/utils/lru-set.js +48 -0
  207. package/cjs/utils/lru-set.js.map +1 -0
  208. package/cjs/utils/misc-utils.d.ts +7 -0
  209. package/cjs/utils/misc-utils.js +15 -0
  210. package/cjs/utils/misc-utils.js.map +1 -0
  211. package/cjs/utils/peer-utils.d.ts +35 -0
  212. package/cjs/utils/peer-utils.js +188 -0
  213. package/cjs/utils/peer-utils.js.map +1 -0
  214. package/cjs/utils/platform/crypto.d.ts +1 -0
  215. package/cjs/utils/platform/crypto.js +8 -0
  216. package/cjs/utils/platform/crypto.js.map +1 -0
  217. package/cjs/utils/platform/crypto.web.d.ts +1 -0
  218. package/cjs/utils/platform/crypto.web.js +14 -0
  219. package/cjs/utils/platform/crypto.web.js.map +1 -0
  220. package/cjs/utils/platform/error-reporting.d.ts +3 -0
  221. package/cjs/utils/platform/error-reporting.js +22 -0
  222. package/cjs/utils/platform/error-reporting.js.map +1 -0
  223. package/cjs/utils/platform/logging.d.ts +1 -0
  224. package/cjs/utils/platform/logging.js +35 -0
  225. package/cjs/utils/platform/logging.js.map +1 -0
  226. package/cjs/utils/platform/logging.web.d.ts +1 -0
  227. package/cjs/utils/platform/logging.web.js +35 -0
  228. package/cjs/utils/platform/logging.web.js.map +1 -0
  229. package/cjs/utils/platform/random.d.ts +1 -0
  230. package/cjs/utils/platform/random.js +7 -0
  231. package/cjs/utils/platform/random.js.map +1 -0
  232. package/cjs/utils/platform/random.web.d.ts +1 -0
  233. package/cjs/utils/platform/random.web.js +10 -0
  234. package/cjs/utils/platform/random.web.js.map +1 -0
  235. package/cjs/utils/platform/transport.d.ts +1 -0
  236. package/cjs/utils/platform/transport.js +8 -0
  237. package/cjs/utils/platform/transport.js.map +1 -0
  238. package/cjs/utils/platform/transport.web.d.ts +1 -0
  239. package/cjs/utils/platform/transport.web.js +15 -0
  240. package/cjs/utils/platform/transport.web.js.map +1 -0
  241. package/cjs/utils/sorted-array.d.ts +17 -0
  242. package/cjs/utils/sorted-array.js +83 -0
  243. package/cjs/utils/sorted-array.js.map +1 -0
  244. package/cjs/utils/string-session.d.ts +11 -0
  245. package/cjs/utils/string-session.js +73 -0
  246. package/cjs/utils/string-session.js.map +1 -0
  247. package/cjs/utils/tl-json.d.ts +13 -0
  248. package/cjs/utils/tl-json.js +62 -0
  249. package/cjs/utils/tl-json.js.map +1 -0
  250. package/cjs/utils/type-assertions.d.ts +37 -0
  251. package/cjs/utils/type-assertions.js +70 -0
  252. package/cjs/utils/type-assertions.js.map +1 -0
  253. package/esm/base-client.d.ts +297 -0
  254. package/esm/base-client.js +317 -0
  255. package/esm/base-client.js.map +1 -0
  256. package/esm/index.d.ts +10 -0
  257. package/esm/index.js +11 -0
  258. package/esm/index.js.map +1 -0
  259. package/esm/network/auth-key.d.ts +21 -0
  260. package/esm/network/auth-key.js +97 -0
  261. package/esm/network/auth-key.js.map +1 -0
  262. package/esm/network/authorization.d.ts +9 -0
  263. package/esm/network/authorization.js +325 -0
  264. package/esm/network/authorization.js.map +1 -0
  265. package/esm/network/config-manager.d.ts +33 -0
  266. package/esm/network/config-manager.js +89 -0
  267. package/esm/network/config-manager.js.map +1 -0
  268. package/esm/network/index.d.ts +4 -0
  269. package/esm/network/index.js +4 -0
  270. package/esm/network/index.js.map +1 -0
  271. package/esm/network/mtproto-session.d.ts +116 -0
  272. package/esm/network/mtproto-session.js +202 -0
  273. package/esm/network/mtproto-session.js.map +1 -0
  274. package/esm/network/multi-session-connection.d.ts +33 -0
  275. package/esm/network/multi-session-connection.js +236 -0
  276. package/esm/network/multi-session-connection.js.map +1 -0
  277. package/esm/network/network-manager.d.ts +190 -0
  278. package/esm/network/network-manager.js +542 -0
  279. package/esm/network/network-manager.js.map +1 -0
  280. package/esm/network/persistent-connection.d.ts +51 -0
  281. package/esm/network/persistent-connection.js +166 -0
  282. package/esm/network/persistent-connection.js.map +1 -0
  283. package/esm/network/reconnection.d.ts +11 -0
  284. package/esm/network/reconnection.js +14 -0
  285. package/esm/network/reconnection.js.map +1 -0
  286. package/esm/network/session-connection.d.ts +72 -0
  287. package/esm/network/session-connection.js +1356 -0
  288. package/esm/network/session-connection.js.map +1 -0
  289. package/esm/network/transports/abstract.d.ts +99 -0
  290. package/esm/network/transports/abstract.js +34 -0
  291. package/esm/network/transports/abstract.js.map +1 -0
  292. package/esm/network/transports/index.d.ts +8 -0
  293. package/esm/network/transports/index.js +9 -0
  294. package/esm/network/transports/index.js.map +1 -0
  295. package/esm/network/transports/intermediate.d.ts +20 -0
  296. package/esm/network/transports/intermediate.js +62 -0
  297. package/esm/network/transports/intermediate.js.map +1 -0
  298. package/esm/network/transports/obfuscated.d.ts +18 -0
  299. package/esm/network/transports/obfuscated.js +79 -0
  300. package/esm/network/transports/obfuscated.js.map +1 -0
  301. package/esm/network/transports/streamed.d.ts +24 -0
  302. package/esm/network/transports/streamed.js +25 -0
  303. package/esm/network/transports/streamed.js.map +1 -0
  304. package/esm/network/transports/tcp.d.ts +33 -0
  305. package/esm/network/transports/tcp.js +122 -0
  306. package/esm/network/transports/tcp.js.map +1 -0
  307. package/esm/network/transports/websocket.d.ts +47 -0
  308. package/esm/network/transports/websocket.js +116 -0
  309. package/esm/network/transports/websocket.js.map +1 -0
  310. package/esm/network/transports/wrapped.d.ts +11 -0
  311. package/esm/network/transports/wrapped.js +19 -0
  312. package/esm/network/transports/wrapped.js.map +1 -0
  313. package/esm/storage/abstract.d.ts +174 -0
  314. package/esm/storage/abstract.js +2 -0
  315. package/esm/storage/abstract.js.map +1 -0
  316. package/esm/storage/index.d.ts +5 -0
  317. package/esm/storage/index.js +6 -0
  318. package/esm/storage/index.js.map +1 -0
  319. package/esm/storage/json-file.d.ts +31 -0
  320. package/esm/storage/json-file.js +63 -0
  321. package/esm/storage/json-file.js.map +1 -0
  322. package/esm/storage/json.d.ts +9 -0
  323. package/esm/storage/json.js +61 -0
  324. package/esm/storage/json.js.map +1 -0
  325. package/esm/storage/localstorage.d.ts +7 -0
  326. package/esm/storage/localstorage.js +21 -0
  327. package/esm/storage/localstorage.js.map +1 -0
  328. package/esm/storage/memory.d.ts +98 -0
  329. package/esm/storage/memory.js +295 -0
  330. package/esm/storage/memory.js.map +1 -0
  331. package/esm/types/errors.d.ts +53 -0
  332. package/esm/types/errors.js +49 -0
  333. package/esm/types/errors.js.map +1 -0
  334. package/esm/types/index.d.ts +3 -0
  335. package/esm/types/index.js +4 -0
  336. package/esm/types/index.js.map +1 -0
  337. package/esm/types/peers.d.ts +4 -0
  338. package/esm/types/peers.js +2 -0
  339. package/esm/types/peers.js.map +1 -0
  340. package/esm/types/utils.d.ts +6 -0
  341. package/esm/types/utils.js +5 -0
  342. package/esm/types/utils.js.map +1 -0
  343. package/esm/utils/async-lock.d.ts +10 -0
  344. package/esm/utils/async-lock.js +39 -0
  345. package/esm/utils/async-lock.js.map +1 -0
  346. package/esm/utils/bigint-utils.d.ts +40 -0
  347. package/esm/utils/bigint-utils.js +92 -0
  348. package/esm/utils/bigint-utils.js.map +1 -0
  349. package/esm/utils/binary/asn1-parser.d.ts +17 -0
  350. package/esm/utils/binary/asn1-parser.js +116 -0
  351. package/esm/utils/binary/asn1-parser.js.map +1 -0
  352. package/esm/utils/buffer-utils.d.ts +21 -0
  353. package/esm/utils/buffer-utils.js +55 -0
  354. package/esm/utils/buffer-utils.js.map +1 -0
  355. package/esm/utils/condition-variable.d.ts +9 -0
  356. package/esm/utils/condition-variable.js +24 -0
  357. package/esm/utils/condition-variable.js.map +1 -0
  358. package/esm/utils/controllable-promise.d.ts +16 -0
  359. package/esm/utils/controllable-promise.js +20 -0
  360. package/esm/utils/controllable-promise.js.map +1 -0
  361. package/esm/utils/crypto/abstract.d.ts +23 -0
  362. package/esm/utils/crypto/abstract.js +15 -0
  363. package/esm/utils/crypto/abstract.js.map +1 -0
  364. package/esm/utils/crypto/common.d.ts +12 -0
  365. package/esm/utils/crypto/common.js +50 -0
  366. package/esm/utils/crypto/common.js.map +1 -0
  367. package/esm/utils/crypto/factorization.d.ts +5 -0
  368. package/esm/utils/crypto/factorization.js +62 -0
  369. package/esm/utils/crypto/factorization.js.map +1 -0
  370. package/esm/utils/crypto/index.d.ts +5 -0
  371. package/esm/utils/crypto/index.js +6 -0
  372. package/esm/utils/crypto/index.js.map +1 -0
  373. package/esm/utils/crypto/keys.d.ts +27 -0
  374. package/esm/utils/crypto/keys.js +64 -0
  375. package/esm/utils/crypto/keys.js.map +1 -0
  376. package/esm/utils/crypto/miller-rabin.d.ts +2 -0
  377. package/esm/utils/crypto/miller-rabin.js +37 -0
  378. package/esm/utils/crypto/miller-rabin.js.map +1 -0
  379. package/esm/utils/crypto/mtproto.d.ts +31 -0
  380. package/esm/utils/crypto/mtproto.js +60 -0
  381. package/esm/utils/crypto/mtproto.js.map +1 -0
  382. package/esm/utils/crypto/node-crypto.d.ts +10 -0
  383. package/esm/utils/crypto/node-crypto.js +42 -0
  384. package/esm/utils/crypto/node-crypto.js.map +1 -0
  385. package/esm/utils/crypto/password.d.ts +29 -0
  386. package/esm/utils/crypto/password.js +97 -0
  387. package/esm/utils/crypto/password.js.map +1 -0
  388. package/esm/utils/crypto/subtle.d.ts +12 -0
  389. package/esm/utils/crypto/subtle.js +59 -0
  390. package/esm/utils/crypto/subtle.js.map +1 -0
  391. package/esm/utils/crypto/utils.d.ts +14 -0
  392. package/esm/utils/crypto/utils.js +25 -0
  393. package/esm/utils/crypto/utils.js.map +1 -0
  394. package/esm/utils/default-dcs.d.ts +7 -0
  395. package/esm/utils/default-dcs.js +73 -0
  396. package/esm/utils/default-dcs.js.map +1 -0
  397. package/esm/utils/deque.d.ts +29 -0
  398. package/esm/utils/deque.js +206 -0
  399. package/esm/utils/deque.js.map +1 -0
  400. package/esm/utils/early-timer.d.ts +42 -0
  401. package/esm/utils/early-timer.js +75 -0
  402. package/esm/utils/early-timer.js.map +1 -0
  403. package/esm/utils/flood-control.d.ts +14 -0
  404. package/esm/utils/flood-control.js +61 -0
  405. package/esm/utils/flood-control.js.map +1 -0
  406. package/esm/utils/function-utils.d.ts +13 -0
  407. package/esm/utils/function-utils.js +26 -0
  408. package/esm/utils/function-utils.js.map +1 -0
  409. package/esm/utils/index.d.ts +24 -0
  410. package/esm/utils/index.js +25 -0
  411. package/esm/utils/index.js.map +1 -0
  412. package/esm/utils/linked-list.d.ts +21 -0
  413. package/esm/utils/linked-list.js +69 -0
  414. package/esm/utils/linked-list.js.map +1 -0
  415. package/esm/utils/links/bots.d.ts +71 -0
  416. package/esm/utils/links/bots.js +256 -0
  417. package/esm/utils/links/bots.js.map +1 -0
  418. package/esm/utils/links/bundle.d.ts +7 -0
  419. package/esm/utils/links/bundle.js +8 -0
  420. package/esm/utils/links/bundle.js.map +1 -0
  421. package/esm/utils/links/calls.d.ts +16 -0
  422. package/esm/utils/links/calls.js +56 -0
  423. package/esm/utils/links/calls.js.map +1 -0
  424. package/esm/utils/links/chat.d.ts +46 -0
  425. package/esm/utils/links/chat.js +157 -0
  426. package/esm/utils/links/chat.js.map +1 -0
  427. package/esm/utils/links/common.d.ts +31 -0
  428. package/esm/utils/links/common.js +56 -0
  429. package/esm/utils/links/common.js.map +1 -0
  430. package/esm/utils/links/index.d.ts +2 -0
  431. package/esm/utils/links/index.js +3 -0
  432. package/esm/utils/links/index.js.map +1 -0
  433. package/esm/utils/links/misc.d.ts +19 -0
  434. package/esm/utils/links/misc.js +74 -0
  435. package/esm/utils/links/misc.js.map +1 -0
  436. package/esm/utils/links/proxy.d.ts +17 -0
  437. package/esm/utils/links/proxy.js +58 -0
  438. package/esm/utils/links/proxy.js.map +1 -0
  439. package/esm/utils/links/stickers.d.ts +9 -0
  440. package/esm/utils/links/stickers.js +25 -0
  441. package/esm/utils/links/stickers.js.map +1 -0
  442. package/esm/utils/links/user.d.ts +27 -0
  443. package/esm/utils/links/user.js +78 -0
  444. package/esm/utils/links/user.js.map +1 -0
  445. package/esm/utils/logger.d.ts +54 -0
  446. package/esm/utils/logger.js +154 -0
  447. package/esm/utils/logger.js.map +1 -0
  448. package/esm/utils/long-utils.d.ts +75 -0
  449. package/esm/utils/long-utils.js +148 -0
  450. package/esm/utils/long-utils.js.map +1 -0
  451. package/esm/utils/lru-map.d.ts +21 -0
  452. package/esm/utils/lru-map.js +103 -0
  453. package/esm/utils/lru-map.js.map +1 -0
  454. package/esm/utils/lru-set.d.ts +22 -0
  455. package/esm/utils/lru-set.js +44 -0
  456. package/esm/utils/lru-set.js.map +1 -0
  457. package/esm/utils/misc-utils.d.ts +7 -0
  458. package/esm/utils/misc-utils.js +10 -0
  459. package/esm/utils/misc-utils.js.map +1 -0
  460. package/esm/utils/peer-utils.d.ts +35 -0
  461. package/esm/utils/peer-utils.js +179 -0
  462. package/esm/utils/peer-utils.js.map +1 -0
  463. package/esm/utils/platform/crypto.d.ts +1 -0
  464. package/esm/utils/platform/crypto.js +4 -0
  465. package/esm/utils/platform/crypto.js.map +1 -0
  466. package/esm/utils/platform/crypto.web.d.ts +1 -0
  467. package/esm/utils/platform/crypto.web.js +10 -0
  468. package/esm/utils/platform/crypto.web.js.map +1 -0
  469. package/esm/utils/platform/error-reporting.d.ts +3 -0
  470. package/esm/utils/platform/error-reporting.js +18 -0
  471. package/esm/utils/platform/error-reporting.js.map +1 -0
  472. package/esm/utils/platform/logging.d.ts +1 -0
  473. package/esm/utils/platform/logging.js +32 -0
  474. package/esm/utils/platform/logging.js.map +1 -0
  475. package/esm/utils/platform/logging.web.d.ts +1 -0
  476. package/esm/utils/platform/logging.web.js +31 -0
  477. package/esm/utils/platform/logging.web.js.map +1 -0
  478. package/esm/utils/platform/random.d.ts +1 -0
  479. package/esm/utils/platform/random.js +4 -0
  480. package/esm/utils/platform/random.js.map +1 -0
  481. package/esm/utils/platform/random.web.d.ts +1 -0
  482. package/esm/utils/platform/random.web.js +6 -0
  483. package/esm/utils/platform/random.web.js.map +1 -0
  484. package/esm/utils/platform/transport.d.ts +1 -0
  485. package/esm/utils/platform/transport.js +4 -0
  486. package/esm/utils/platform/transport.js.map +1 -0
  487. package/esm/utils/platform/transport.web.d.ts +1 -0
  488. package/esm/utils/platform/transport.web.js +12 -0
  489. package/esm/utils/platform/transport.web.js.map +1 -0
  490. package/esm/utils/sorted-array.d.ts +17 -0
  491. package/esm/utils/sorted-array.js +79 -0
  492. package/esm/utils/sorted-array.js.map +1 -0
  493. package/esm/utils/string-session.d.ts +11 -0
  494. package/esm/utils/string-session.js +68 -0
  495. package/esm/utils/string-session.js.map +1 -0
  496. package/esm/utils/tl-json.d.ts +13 -0
  497. package/esm/utils/tl-json.js +57 -0
  498. package/esm/utils/tl-json.js.map +1 -0
  499. package/esm/utils/type-assertions.d.ts +37 -0
  500. package/esm/utils/type-assertions.js +61 -0
  501. package/esm/utils/type-assertions.js.map +1 -0
  502. package/package.json +50 -0
@@ -0,0 +1,1356 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ // will be reworked in MTQ-32
3
+ import Long from 'long';
4
+ import { tl } from '@mtcute/tl';
5
+ import { gzipDeflate, gzipInflate, TlBinaryReader, TlBinaryWriter, TlSerializationCounter, } from '@mtcute/tl-runtime';
6
+ import { MtArgumentError, MtcuteError, MtTimeoutError } from '../types/index.js';
7
+ import { createAesIgeForMessageOld } from '../utils/crypto/mtproto.js';
8
+ import { concatBuffers, createControllablePromise, EarlyTimer, longFromBuffer, randomBytes, randomLong, removeFromLongArray, } from '../utils/index.js';
9
+ import { reportUnknownError } from '../utils/platform/error-reporting.js';
10
+ import { doAuthorization } from './authorization.js';
11
+ import { PersistentConnection } from './persistent-connection.js';
12
+ import { TransportError } from './transports/abstract.js';
13
+ const TEMP_AUTH_KEY_EXPIRY = 86400;
14
+ // destroy_auth_key#d1435160 = DestroyAuthKeyRes;
15
+ // const DESTROY_AUTH_KEY = Buffer.from('605134d1', 'hex')
16
+ function makeNiceStack(error, stack, method) {
17
+ error.stack = `RpcError (${error.code} ${error.text}): ${error.message}\n at ${method}\n${stack
18
+ .split('\n')
19
+ .slice(2)
20
+ .join('\n')}`;
21
+ }
22
+ /**
23
+ * A connection to a single DC.
24
+ */
25
+ export class SessionConnection extends PersistentConnection {
26
+ constructor(params, _session) {
27
+ super(params, _session.log.create('conn'));
28
+ this._session = _session;
29
+ this._flushTimer = new EarlyTimer();
30
+ this._queuedDestroySession = [];
31
+ // waitForMessage
32
+ this._pendingWaitForUnencrypted = [];
33
+ this._usePfs = this.params.usePfs ?? false;
34
+ this._isPfsBindingPending = false;
35
+ this._isPfsBindingPendingInBackground = false;
36
+ this._inactivityPendingFlush = false;
37
+ this._flushTimer.onTimeout(this._flush.bind(this));
38
+ this._readerMap = params.readerMap;
39
+ this._writerMap = params.writerMap;
40
+ this._handleRawMessage = this._handleRawMessage.bind(this);
41
+ }
42
+ getAuthKey(temp = false) {
43
+ const key = temp ? this._session._authKeyTemp : this._session._authKey;
44
+ if (!key.ready)
45
+ return null;
46
+ return key.key;
47
+ }
48
+ setUsePfs(usePfs) {
49
+ if (this._usePfs === usePfs)
50
+ return;
51
+ this.log.debug('use pfs changed to %s', usePfs);
52
+ this._usePfs = usePfs;
53
+ if (!usePfs) {
54
+ this._isPfsBindingPending = false;
55
+ this._isPfsBindingPendingInBackground = false;
56
+ this._session._authKeyTemp.reset();
57
+ clearTimeout(this._pfsUpdateTimeout);
58
+ }
59
+ this._resetSession();
60
+ }
61
+ onTransportClose() {
62
+ super.onTransportClose();
63
+ Object.values(this._pendingWaitForUnencrypted).forEach(([prom, timeout]) => {
64
+ prom.reject(new MtcuteError('Connection closed'));
65
+ clearTimeout(timeout);
66
+ });
67
+ this.emit('disconnect');
68
+ this.reset();
69
+ }
70
+ destroy() {
71
+ super.destroy();
72
+ this.reset(true);
73
+ }
74
+ reset(forever = false) {
75
+ this._session.initConnectionCalled = false;
76
+ this._flushTimer.reset();
77
+ if (forever) {
78
+ this.removeAllListeners();
79
+ }
80
+ }
81
+ onConnected() {
82
+ // check if we have all the needed keys
83
+ if (!this._session._authKey.ready) {
84
+ if (!this.params.isMainConnection) {
85
+ this.log.info('no auth key, waiting for main connection');
86
+ // once it is done, we will be notified
87
+ return;
88
+ }
89
+ this.log.info('no perm auth key, authorizing...');
90
+ this._authorize();
91
+ // if we use pfs, we *could* also start temp key exchange here
92
+ // but telegram restricts us to only have one auth session per connection,
93
+ // and having a separate connection for pfs is not worth it
94
+ return;
95
+ }
96
+ if (this._usePfs && !this._session._authKeyTemp.ready) {
97
+ this.log.info('no temp auth key but using pfs, authorizing');
98
+ this._authorizePfs();
99
+ return;
100
+ }
101
+ this.log.info('auth keys are already available');
102
+ this.onConnectionUsable();
103
+ }
104
+ onError(error) {
105
+ // https://core.telegram.org/mtproto/mtproto-_transports#_transport-errors
106
+ if (error instanceof TransportError) {
107
+ if (error.code === 404) {
108
+ // if we are using pfs, this could be due to the server
109
+ // forgetting our temp key (which is kinda weird but expected)
110
+ if (this._usePfs) {
111
+ if (!this._isPfsBindingPending && this._session._authKeyTemp.ready) {
112
+ this.log.info('transport error 404, reauthorizing pfs');
113
+ // this is important! we must reset temp auth key before
114
+ // we proceed with new temp key derivation.
115
+ // otherwise, we can end up in an infinite loop in case it
116
+ // was actually perm_key that got 404-ed
117
+ //
118
+ // if temp key binding is already in process in background,
119
+ // _authorizePfs will mark it as foreground to prevent new
120
+ // queries from being sent (to avoid even more 404s)
121
+ this._session._authKeyTemp.reset();
122
+ this._authorizePfs();
123
+ this._onAllFailed('temp key expired, binding started');
124
+ return;
125
+ }
126
+ else if (this._isPfsBindingPending) {
127
+ this.log.info('transport error 404, pfs binding in progress');
128
+ this._onAllFailed('temp key expired, binding pending');
129
+ return;
130
+ }
131
+ // otherwise, 404 must be referencing the perm_key
132
+ this.log.info('transport error 404, reauthorizing');
133
+ }
134
+ // there happened a little trolling
135
+ this._session.reset(true);
136
+ this.emit('key-change', null);
137
+ this._authorize();
138
+ return;
139
+ }
140
+ this.log.error('transport error %d', error.code);
141
+ // all pending queries must be resent
142
+ this._onAllFailed(`transport error ${error.code}`);
143
+ if (error.code === 429) {
144
+ this._session.onTransportFlood(this.emit.bind(this, 'flood-done'));
145
+ return;
146
+ }
147
+ }
148
+ this.emit('error', error);
149
+ }
150
+ onConnectionUsable() {
151
+ super.onConnectionUsable();
152
+ if (this.params.withUpdates) {
153
+ // we must send some user-related rpc to the server to make sure that
154
+ // it will send us updates
155
+ this.sendRpc({ _: 'updates.getState' }).catch((err) => {
156
+ this.log.warn('failed to send updates.getState: %s', err.text || err.message);
157
+ });
158
+ }
159
+ // just in case
160
+ this._flushTimer.emitBeforeNext(1000);
161
+ }
162
+ _authorize() {
163
+ if (this._session.authorizationPending) {
164
+ this.log.info('_authorize(): authorization already in progress');
165
+ return;
166
+ }
167
+ if (!this.params.isMainConnection) {
168
+ // we don't authorize on non-main connections
169
+ this.log.debug('_authorize(): non-main connection, requesting...');
170
+ this.emit('request-auth');
171
+ return;
172
+ }
173
+ this._session.authorizationPending = true;
174
+ this.emit('auth-begin');
175
+ doAuthorization(this, this.params.crypto)
176
+ .then(async ([authKey, serverSalt, timeOffset]) => {
177
+ await this._session._authKey.setup(authKey);
178
+ this._session.serverSalt = serverSalt;
179
+ this._session._timeOffset = timeOffset;
180
+ this._session.authorizationPending = false;
181
+ this.emit('key-change', authKey);
182
+ if (this._usePfs) {
183
+ return this._authorizePfs();
184
+ }
185
+ this.onConnectionUsable();
186
+ })
187
+ .catch((err) => {
188
+ this._session.authorizationPending = false;
189
+ this.log.error('Authorization error: %s', err.message);
190
+ this.onError(err);
191
+ this.reconnect();
192
+ });
193
+ }
194
+ _authorizePfs(background = false) {
195
+ if (this._isPfsBindingPending)
196
+ return;
197
+ if (this._pfsUpdateTimeout) {
198
+ clearTimeout(this._pfsUpdateTimeout);
199
+ this._pfsUpdateTimeout = undefined;
200
+ }
201
+ if (this._isPfsBindingPendingInBackground) {
202
+ // e.g. temp key has expired while we were binding a key in the background
203
+ // in this case, we shouldn't start pfs binding again, and instead wait for
204
+ // current operation to complete
205
+ this._isPfsBindingPendingInBackground = false;
206
+ this._isPfsBindingPending = true;
207
+ return;
208
+ }
209
+ if (background) {
210
+ this._isPfsBindingPendingInBackground = true;
211
+ }
212
+ else {
213
+ this._isPfsBindingPending = true;
214
+ }
215
+ doAuthorization(this, this.params.crypto, TEMP_AUTH_KEY_EXPIRY)
216
+ .then(async ([tempAuthKey, tempServerSalt]) => {
217
+ if (!this._usePfs) {
218
+ this.log.info('pfs has been disabled while generating temp key');
219
+ return;
220
+ }
221
+ const tempKey = this._session._authKeyTempSecondary;
222
+ await tempKey.setup(tempAuthKey);
223
+ const msgId = this._session.getMessageId();
224
+ this.log.debug('binding temp_auth_key (%h) to perm_auth_key (%h), msg_id = %l...', tempKey.id, this._session._authKey.id, msgId);
225
+ // we now need to bind the key
226
+ const inner = {
227
+ _: 'mt_bind_auth_key_inner',
228
+ nonce: randomLong(),
229
+ tempAuthKeyId: longFromBuffer(tempKey.id),
230
+ permAuthKeyId: longFromBuffer(this._session._authKey.id),
231
+ tempSessionId: this._session._sessionId,
232
+ expiresAt: Math.floor(Date.now() / 1000) + TEMP_AUTH_KEY_EXPIRY,
233
+ };
234
+ // encrypt using mtproto v1 (fucking kill me plz)
235
+ const writer = TlBinaryWriter.alloc(this.params.writerMap, 80);
236
+ // = 40 (inner length) + 32 (mtproto header) + 8 (pad 72 so mod 16 = 0)
237
+ writer.raw(randomBytes(16));
238
+ writer.long(msgId);
239
+ writer.int(0); // seq_no
240
+ writer.int(40); // msg_len
241
+ writer.object(inner);
242
+ const msgWithoutPadding = writer.result();
243
+ writer.raw(randomBytes(8));
244
+ const msgWithPadding = writer.result();
245
+ const hash = await this.params.crypto.sha1(msgWithoutPadding);
246
+ const msgKey = hash.subarray(4, 20);
247
+ const ige = await createAesIgeForMessageOld(this.params.crypto, this._session._authKey.key, msgKey, true);
248
+ const encryptedData = await ige.encrypt(msgWithPadding);
249
+ const encryptedMessage = concatBuffers([this._session._authKey.id, msgKey, encryptedData]);
250
+ const promise = createControllablePromise();
251
+ // encrypt the message using temp key and same msg id
252
+ // this is a bit of a hack, but it works
253
+ //
254
+ // hacking inside main send loop to allow sending
255
+ // with another key is just too much hassle.
256
+ // we could just always use temp key if one is available,
257
+ // but that way we won't be able to refresh the key
258
+ // that is about to expire in the background without
259
+ // interrupting actual message flow
260
+ // decrypting is trivial though, since key id
261
+ // is in the first bytes of the message, and is never used later on.
262
+ this._session.pendingMessages.set(msgId, {
263
+ _: 'bind',
264
+ promise,
265
+ });
266
+ const request = {
267
+ _: 'auth.bindTempAuthKey',
268
+ permAuthKeyId: inner.permAuthKeyId,
269
+ nonce: inner.nonce,
270
+ expiresAt: inner.expiresAt,
271
+ encryptedMessage,
272
+ };
273
+ const reqSize = TlSerializationCounter.countNeededBytes(this._writerMap, request);
274
+ const reqWriter = TlBinaryWriter.alloc(this._writerMap, reqSize + 16);
275
+ reqWriter.long(this._registerOutgoingMsgId(msgId));
276
+ reqWriter.uint(this._session.getSeqNo());
277
+ reqWriter.uint(reqSize);
278
+ reqWriter.object(request);
279
+ // we can now send it as is
280
+ const requestEncrypted = await tempKey.encryptMessage(reqWriter.result(), tempServerSalt, this._session._sessionId);
281
+ await this.send(requestEncrypted);
282
+ const res = await promise;
283
+ this._session.pendingMessages.delete(msgId);
284
+ if (!this._usePfs) {
285
+ this.log.info('pfs has been disabled while binding temp key');
286
+ return;
287
+ }
288
+ if (typeof res === 'object') {
289
+ this.log.error('failed to bind temp key: %s:%s', res.errorCode, res.errorMessage);
290
+ throw new MtcuteError('Failed to bind temporary key');
291
+ }
292
+ // now we can swap the keys (secondary becomes primary,
293
+ // and primary is not immediately forgot because messages using it may still be in flight)
294
+ this._session._authKeyTempSecondary = this._session._authKeyTemp;
295
+ this._session._authKeyTemp = tempKey;
296
+ this._session.serverSalt = tempServerSalt;
297
+ this.log.debug('temp key has been bound, exp = %d', inner.expiresAt);
298
+ this._isPfsBindingPending = false;
299
+ this._isPfsBindingPendingInBackground = false;
300
+ // we must re-init connection after binding temp key
301
+ this._session.initConnectionCalled = false;
302
+ this.emit('tmp-key-change', tempAuthKey, inner.expiresAt);
303
+ this.onConnectionUsable();
304
+ // set a timeout to update temp auth key in advance to avoid interruption
305
+ this._pfsUpdateTimeout = setTimeout(() => {
306
+ this._pfsUpdateTimeout = undefined;
307
+ this.log.debug('temp key is expiring soon');
308
+ this._authorizePfs(true);
309
+ }, (TEMP_AUTH_KEY_EXPIRY - 60) * 1000);
310
+ })
311
+ .catch((err) => {
312
+ this.log.error('PFS Authorization error: %s', err.message);
313
+ if (this._isPfsBindingPendingInBackground) {
314
+ this._isPfsBindingPendingInBackground = false;
315
+ // if we are in background, we can just retry
316
+ return this._authorizePfs(true);
317
+ }
318
+ this._isPfsBindingPending = false;
319
+ this.onError(err);
320
+ this.reconnect();
321
+ });
322
+ }
323
+ waitForUnencryptedMessage(timeout = 5000) {
324
+ const promise = createControllablePromise();
325
+ const timeoutId = setTimeout(() => {
326
+ promise.reject(new MtTimeoutError(timeout));
327
+ this._pendingWaitForUnencrypted = this._pendingWaitForUnencrypted.filter((it) => it[0] !== promise);
328
+ }, timeout);
329
+ this._pendingWaitForUnencrypted.push([promise, timeoutId]);
330
+ return promise;
331
+ }
332
+ async onMessage(data) {
333
+ if (this._pendingWaitForUnencrypted.length) {
334
+ const int32 = new Int32Array(data.buffer, data.byteOffset, 2);
335
+ if (int32[0] === 0 && int32[1] === 0) {
336
+ // auth_key_id = 0, meaning it's an unencrypted message used for authorization
337
+ const [promise, timeout] = this._pendingWaitForUnencrypted.shift();
338
+ clearTimeout(timeout);
339
+ promise.resolve(data);
340
+ return;
341
+ }
342
+ }
343
+ if (!this._session._authKey.ready) {
344
+ // if a message is received before authorization,
345
+ // either the server is misbehaving,
346
+ // or there was a problem with authorization.
347
+ this.log.warn('received message before authorization: %h', data);
348
+ return;
349
+ }
350
+ try {
351
+ await this._session.decryptMessage(data, this._handleRawMessage);
352
+ }
353
+ catch (err) {
354
+ this.log.error('failed to decrypt message: %s\ndata: %h', err, data);
355
+ }
356
+ }
357
+ _handleRawMessage(messageId, seqNo, message) {
358
+ if (message.peekUint() === 0x3072cfa1) {
359
+ // gzip_packed
360
+ // we can't use message.gzip() because it may contain msg_container,
361
+ // so we parse it manually.
362
+ message.uint();
363
+ return this._handleRawMessage(messageId, seqNo, new TlBinaryReader(this._readerMap, gzipInflate(message.bytes())));
364
+ }
365
+ if (message.peekUint() === 0x73f1f8dc) {
366
+ // msg_container
367
+ message.uint();
368
+ const count = message.uint();
369
+ for (let i = 0; i < count; i++) {
370
+ // msg_id:long seqno:int bytes:int
371
+ const msgId = message.long();
372
+ const seqNo = message.uint(); // seqno
373
+ const length = message.uint();
374
+ // container can't contain other containers, but can contain rpc_result
375
+ const obj = message.raw(length);
376
+ this._handleRawMessage(msgId, seqNo, new TlBinaryReader(this._readerMap, obj));
377
+ }
378
+ return;
379
+ }
380
+ if (message.peekUint() === 0xf35c6d01) {
381
+ // rpc_result
382
+ message.uint();
383
+ return this._onRpcResult(messageId, message);
384
+ }
385
+ // we are safe.. i guess
386
+ this._handleMessage(messageId, message.object());
387
+ }
388
+ _handleMessage(messageId, message_) {
389
+ if (messageId.isEven()) {
390
+ this.log.warn('warn: ignoring message with invalid messageId = %s (is even)', messageId);
391
+ return;
392
+ }
393
+ if (this._session.recentIncomingMsgIds.has(messageId)) {
394
+ this.log.debug('ignoring duplicate message %s', messageId);
395
+ return;
396
+ }
397
+ const message = message_;
398
+ this.log.debug('received %s (msg_id: %l)', message._, messageId);
399
+ this._session.recentIncomingMsgIds.add(messageId);
400
+ switch (message._) {
401
+ case 'mt_msgs_ack':
402
+ case 'mt_http_wait':
403
+ case 'mt_bad_msg_notification':
404
+ case 'mt_bad_server_salt':
405
+ case 'mt_msgs_all_info':
406
+ case 'mt_msgs_state_info':
407
+ case 'mt_msg_detailed_info':
408
+ case 'mt_msg_new_detailed_info':
409
+ break;
410
+ default:
411
+ this._sendAck(messageId);
412
+ }
413
+ switch (message._) {
414
+ case 'mt_pong':
415
+ this._onPong(message);
416
+ break;
417
+ case 'mt_bad_server_salt':
418
+ this._onBadServerSalt(message);
419
+ break;
420
+ case 'mt_bad_msg_notification':
421
+ this._onBadMsgNotification(messageId, message);
422
+ break;
423
+ case 'mt_msgs_ack':
424
+ message.msgIds.forEach((msgId) => this._onMessageAcked(msgId));
425
+ break;
426
+ case 'mt_new_session_created':
427
+ this._onNewSessionCreated(message);
428
+ break;
429
+ case 'mt_msgs_all_info':
430
+ this._onMessagesInfo(message.msgIds, message.info);
431
+ break;
432
+ case 'mt_msg_detailed_info':
433
+ this._onMessageInfo(message.msgId, message.status, message.answerMsgId);
434
+ break;
435
+ case 'mt_msg_new_detailed_info':
436
+ this._onMessageInfo(Long.ZERO, 0, message.answerMsgId);
437
+ break;
438
+ case 'mt_msgs_state_info':
439
+ this._onMsgsStateInfo(message);
440
+ break;
441
+ case 'mt_future_salts':
442
+ // todo
443
+ break;
444
+ case 'mt_msgs_state_req':
445
+ case 'mt_msg_resend_req':
446
+ // tdlib doesnt handle them, so why should we? :upside_down_face:
447
+ this.log.warn('received %s (msg_id = %l): %j', message._, messageId, message);
448
+ break;
449
+ case 'mt_destroy_session_ok':
450
+ case 'mt_destroy_session_none':
451
+ this._onDestroySessionResult(message);
452
+ break;
453
+ default:
454
+ if (tl.isAnyUpdates(message)) {
455
+ if (this._usable && this.params.inactivityTimeout) {
456
+ this._rescheduleInactivity();
457
+ }
458
+ this.log.verbose('<<< %j', message);
459
+ if (this.params.disableUpdates) {
460
+ this.log.warn('received updates, but updates are disabled');
461
+ // likely due to some request in the session missing invokeWithoutUpdates
462
+ break;
463
+ }
464
+ this.emit('update', message);
465
+ return;
466
+ }
467
+ this.log.warn('unknown message received: %j', message);
468
+ }
469
+ }
470
+ _onRpcResult(messageId, message) {
471
+ if (this._usable && this.params.inactivityTimeout) {
472
+ this._rescheduleInactivity();
473
+ }
474
+ const reqMsgId = message.long();
475
+ if (reqMsgId.isZero()) {
476
+ let resultType;
477
+ try {
478
+ // eslint-disable-next-line
479
+ resultType = message.object()._;
480
+ }
481
+ catch (err) {
482
+ resultType = message.peekUint();
483
+ }
484
+ this.log.warn('received rpc_result with %j with req_msg_id = 0', resultType);
485
+ return;
486
+ }
487
+ const msg = this._session.pendingMessages.get(reqMsgId);
488
+ if (!msg) {
489
+ let result;
490
+ try {
491
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
492
+ result = message.object();
493
+ }
494
+ catch (err) {
495
+ result = '[failed to parse]';
496
+ }
497
+ // check if the msg is one of the recent ones
498
+ if (this._session.recentOutgoingMsgIds.has(reqMsgId)) {
499
+ this.log.debug('received rpc_result again for %l (contains %j)', reqMsgId, result);
500
+ }
501
+ else {
502
+ this.log.warn('received rpc_result for unknown message %l: %j', reqMsgId, result);
503
+ }
504
+ return;
505
+ }
506
+ this._sendAck(messageId);
507
+ // special case for auth key binding
508
+ if (msg._ !== 'rpc') {
509
+ if (msg._ === 'bind') {
510
+ this._sendAck(messageId);
511
+ msg.promise.resolve(message.object());
512
+ return;
513
+ }
514
+ if (msg._ === 'cancel') {
515
+ let result;
516
+ try {
517
+ result = message.object();
518
+ }
519
+ catch (err) {
520
+ this.log.debug('failed to parse rpc_result for cancel request %l, ignoring', reqMsgId);
521
+ return;
522
+ }
523
+ this.log.debug('received %s for cancelled request %l: %j', result._, reqMsgId);
524
+ this._onMessageAcked(reqMsgId);
525
+ return;
526
+ }
527
+ this.log.error('received rpc_result for %s request %l', msg._, reqMsgId);
528
+ return;
529
+ }
530
+ const rpc = msg.rpc;
531
+ const customReader = this._readerMap._results[rpc.method];
532
+ const result = customReader ? customReader(message) : message.object();
533
+ // initConnection call was definitely received and
534
+ // processed by the server, so we no longer need to use it
535
+ if (rpc.initConn) {
536
+ this._session.initConnectionCalled = true;
537
+ }
538
+ rpc.done = true;
539
+ this.log.verbose('<<< (%s) %j', rpc.method, result);
540
+ if (result._ === 'mt_rpc_error') {
541
+ const res = result;
542
+ this.log.debug('received rpc_error [%d:%s] for %l (%s)', res.errorCode, res.errorMessage, reqMsgId, rpc.method);
543
+ if (res.errorMessage === 'AUTH_KEY_PERM_EMPTY') {
544
+ // happens when temp auth key is not yet bound
545
+ // this shouldn't happen as we block any outbound communications
546
+ // until the temp key is derived and bound.
547
+ //
548
+ // i think it is also possible for the error to be returned
549
+ // when the temp key has expired, but this still shouldn't happen
550
+ // but this is tg, so something may go wrong, and we will receive this as an error
551
+ // (for god's sake why is this not in mtproto and instead hacked into the app layer)
552
+ this._authorizePfs();
553
+ this._onMessageFailed(reqMsgId, 'AUTH_KEY_PERM_EMPTY', true);
554
+ return;
555
+ }
556
+ if (res.errorMessage === 'CONNECTION_NOT_INITED') {
557
+ // this seems to sometimes happen when using pfs
558
+ // no idea why, but tdlib also seems to handle these, so whatever
559
+ this._session.initConnectionCalled = false;
560
+ this._onMessageFailed(reqMsgId, res.errorMessage, true);
561
+ // just setting this flag is not enough because the message
562
+ // is already serialized, so we do this awesome hack
563
+ this.sendRpc({ _: 'help.getNearestDc' })
564
+ .then(() => {
565
+ this.log.debug('additional help.getNearestDc for initConnection ok');
566
+ })
567
+ .catch((err) => {
568
+ this.log.debug('additional help.getNearestDc for initConnection error: %s', err);
569
+ });
570
+ return;
571
+ }
572
+ if (rpc.cancelled)
573
+ return;
574
+ const error = tl.RpcError.fromTl(res);
575
+ if (this.params.niceStacks !== false) {
576
+ makeNiceStack(error, rpc.stack, rpc.method);
577
+ }
578
+ if (error.unknown && this.params.enableErrorReporting) {
579
+ reportUnknownError(this.log, error, rpc.method);
580
+ }
581
+ rpc.promise.reject(error);
582
+ }
583
+ else {
584
+ this.log.debug('received rpc_result (%s) for request %l (%s)', result._, reqMsgId, rpc.method);
585
+ if (rpc.cancelled)
586
+ return;
587
+ rpc.promise.resolve(result);
588
+ }
589
+ this._onMessageAcked(reqMsgId);
590
+ this._session.pendingMessages.delete(reqMsgId);
591
+ }
592
+ _onMessageAcked(msgId, inContainer = false) {
593
+ const msg = this._session.pendingMessages.get(msgId);
594
+ if (!msg) {
595
+ if (!this._session.recentOutgoingMsgIds.has(msgId)) {
596
+ this.log.warn('received ack for unknown message %l', msgId);
597
+ }
598
+ return;
599
+ }
600
+ switch (msg._) {
601
+ case 'container':
602
+ this.log.debug('received ack for container %l (size = %d)', msgId, msg.msgIds.length);
603
+ msg.msgIds.forEach((msgId) => this._onMessageAcked(msgId, true));
604
+ // we no longer need info about the container
605
+ this._session.pendingMessages.delete(msgId);
606
+ break;
607
+ case 'rpc': {
608
+ const rpc = msg.rpc;
609
+ this.log.debug('received ack for rpc query %l (%s, acked before = %s)', msgId, rpc.method, rpc.acked);
610
+ rpc.acked = true;
611
+ if (!inContainer && rpc.containerId && this._session.pendingMessages.has(rpc.containerId)) {
612
+ // ack all the messages in that container
613
+ this._onMessageAcked(rpc.containerId);
614
+ }
615
+ // this message could also already be in some queue,
616
+ removeFromLongArray(this._session.queuedStateReq, msgId);
617
+ removeFromLongArray(this._session.queuedResendReq, msgId);
618
+ // if resend/state was already requested, it will simply be ignored
619
+ this._session.getStateSchedule.remove(rpc);
620
+ break;
621
+ }
622
+ case 'bind':
623
+ break; // do nothing, wait for the result
624
+ default:
625
+ if (!inContainer) {
626
+ this.log.warn('received unexpected ack for %s query %l', msg._, msgId);
627
+ }
628
+ }
629
+ }
630
+ _onAllFailed(reason) {
631
+ // called when all the pending messages are to be resent
632
+ // e.g. when server returns 429
633
+ // most service messages can be omitted as stale
634
+ for (const msgId of this._session.pendingMessages.keys()) {
635
+ const info = this._session.pendingMessages.get(msgId);
636
+ switch (info._) {
637
+ case 'container':
638
+ case 'state':
639
+ case 'resend':
640
+ case 'ping':
641
+ // no longer relevant
642
+ this._session.pendingMessages.delete(msgId);
643
+ break;
644
+ default:
645
+ this._onMessageFailed(msgId, reason, true);
646
+ break;
647
+ }
648
+ }
649
+ }
650
+ _onMessageFailed(msgId, reason, inContainer = false) {
651
+ const msgInfo = this._session.pendingMessages.get(msgId);
652
+ if (!msgInfo) {
653
+ this.log.debug('unknown message %l failed because of %s', msgId, reason);
654
+ return;
655
+ }
656
+ switch (msgInfo._) {
657
+ case 'container':
658
+ this.log.debug('container %l (size = %d) failed because of %s', msgId, msgInfo.msgIds.length, reason);
659
+ msgInfo.msgIds.forEach((msgId) => this._onMessageFailed(msgId, reason, true));
660
+ break;
661
+ case 'ping':
662
+ this.log.debug('ping (msg_id = %l) failed because of %s', msgId, reason);
663
+ // restart ping
664
+ this._session.resetLastPing(true);
665
+ break;
666
+ case 'rpc': {
667
+ const rpc = msgInfo.rpc;
668
+ this.log.debug('rpc query %l (%s) failed because of %s', msgId, rpc.method, reason);
669
+ // since the query was rejected, we can let it reassign msg_id to avoid containers
670
+ this._session.pendingMessages.delete(msgId);
671
+ rpc.msgId = undefined;
672
+ this._enqueueRpc(rpc, true);
673
+ if (!inContainer && rpc.containerId && this._session.pendingMessages.has(rpc.containerId)) {
674
+ // fail all the messages in that container
675
+ this._onMessageFailed(rpc.containerId, reason);
676
+ }
677
+ // this message could also already be in some queue,
678
+ removeFromLongArray(this._session.queuedStateReq, msgId);
679
+ removeFromLongArray(this._session.queuedResendReq, msgId);
680
+ // if resend/state was already requested, it will simply be ignored
681
+ this._session.getStateSchedule.remove(rpc);
682
+ break;
683
+ }
684
+ case 'resend':
685
+ this.log.debug('resend request %l (size = %d) failed because of %s', msgId, msgInfo.msgIds.length, reason);
686
+ this._session.queuedResendReq.splice(0, 0, ...msgInfo.msgIds);
687
+ this._flushTimer.emitWhenIdle();
688
+ break;
689
+ case 'state':
690
+ this.log.debug('state request %l (size = %d) failed because of %s', msgId, msgInfo.msgIds.length, reason);
691
+ this._session.queuedStateReq.splice(0, 0, ...msgInfo.msgIds);
692
+ this._flushTimer.emitWhenIdle();
693
+ break;
694
+ case 'bind':
695
+ this.log.debug('temp key binding request %l failed because of %s, retrying', msgId, reason);
696
+ msgInfo.promise.reject(Error(reason));
697
+ }
698
+ this._session.pendingMessages.delete(msgId);
699
+ }
700
+ _registerOutgoingMsgId(msgId) {
701
+ this._session.recentOutgoingMsgIds.add(msgId);
702
+ return msgId;
703
+ }
704
+ _onPong({ msgId, pingId }) {
705
+ const info = this._session.pendingMessages.get(msgId);
706
+ if (!info) {
707
+ this.log.warn('received pong to unknown ping (msg_id %l, ping_id %l)', msgId, pingId);
708
+ return;
709
+ }
710
+ if (info._ !== 'ping') {
711
+ this.log.warn('received pong to %s query, not ping (msg_id %l, ping_id %l)', info._, msgId, pingId);
712
+ return;
713
+ }
714
+ if (info.pingId.neq(pingId)) {
715
+ this.log.warn('received pong to %l, but expected ping_id = %l (got %l)', msgId, info.pingId, pingId);
716
+ }
717
+ const rtt = Date.now() - this._session.lastPingTime;
718
+ this._session.lastPingRtt = rtt;
719
+ if (info.containerId.neq(msgId)) {
720
+ this._onMessageAcked(info.containerId);
721
+ }
722
+ this.log.debug('received pong: msg_id %l, ping_id %l, rtt = %dms', msgId, pingId, rtt);
723
+ this._session.resetLastPing();
724
+ }
725
+ _onBadServerSalt(msg) {
726
+ this._session.serverSalt = msg.newServerSalt;
727
+ this._onMessageFailed(msg.badMsgId, 'bad_server_salt');
728
+ }
729
+ _onBadMsgNotification(msgId, msg) {
730
+ switch (msg.errorCode) {
731
+ case 16:
732
+ case 17:
733
+ case 20: {
734
+ if (msg.errorCode !== 20) {
735
+ // msg_id is either too high or too low
736
+ // code 20 means msg_id is too old,
737
+ // we just need to resend the message
738
+ const serverTime = msgId.low >>> 0;
739
+ const timeOffset = Math.floor(Date.now() / 1000) - serverTime;
740
+ this._session._timeOffset = timeOffset;
741
+ this.log.debug('server time: %d, corrected offset to %d', serverTime, timeOffset);
742
+ }
743
+ this._onMessageFailed(msg.badMsgId, `bad_msg_notification ${msg.errorCode}`);
744
+ break;
745
+ }
746
+ default:
747
+ // something went very wrong, we need to reset the session
748
+ this.log.error('received bad_msg_notification for msg_id = %l, code = %d. session will be reset', msg.badMsgId, msg.errorCode);
749
+ this._resetSession();
750
+ break;
751
+ }
752
+ }
753
+ _onNewSessionCreated({ firstMsgId, serverSalt, uniqueId }) {
754
+ if (uniqueId.eq(this._session.lastSessionCreatedUid)) {
755
+ this.log.debug('received new_session_created with the same uid = %l, ignoring', uniqueId);
756
+ return;
757
+ }
758
+ if (!this._session.lastSessionCreatedUid.isZero() && !this.params.disableUpdates) {
759
+ // force the client to fetch missed updates
760
+ // when _lastSessionCreatedUid == 0, the connection has
761
+ // just been established, and the client will fetch them anyways
762
+ this.emit('update', { _: 'updatesTooLong' });
763
+ }
764
+ this._session.serverSalt = serverSalt;
765
+ this.log.debug('received new_session_created, uid = %l, first msg_id = %l', uniqueId, firstMsgId);
766
+ for (const msgId of this._session.pendingMessages.keys()) {
767
+ const val = this._session.pendingMessages.get(msgId);
768
+ if (val._ === 'bind') {
769
+ // should NOT happen.
770
+ if (msgId.lt(firstMsgId)) {
771
+ this._onMessageFailed(msgId, 'received in wrong session');
772
+ }
773
+ continue;
774
+ }
775
+ if (val._ === 'container') {
776
+ if (msgId.lt(firstMsgId)) {
777
+ // all messages in this container will be resent
778
+ // info about this container is no longer needed
779
+ this._session.pendingMessages.delete(msgId);
780
+ }
781
+ return;
782
+ }
783
+ const containerId = val._ === 'rpc' ? val.rpc.containerId || msgId : val.containerId;
784
+ if (containerId.lt(firstMsgId)) {
785
+ this._onMessageFailed(msgId, 'new_session_created', true);
786
+ }
787
+ }
788
+ }
789
+ _onMessageInfo(msgId, status, answerMsgId) {
790
+ if (!msgId.isZero()) {
791
+ const info = this._session.pendingMessages.get(msgId);
792
+ if (!info) {
793
+ if (!this._session.recentOutgoingMsgIds.has(msgId)) {
794
+ this.log.warn('received message info about unknown message %l', msgId);
795
+ }
796
+ return;
797
+ }
798
+ switch (status & 7) {
799
+ case 1:
800
+ case 2:
801
+ case 3:
802
+ // message wasn't received by the server
803
+ this._onMessageFailed(msgId, `message info state ${status}`);
804
+ break;
805
+ case 0:
806
+ if (!answerMsgId.isZero()) {
807
+ this.log.warn('received message info with status = 0: msg_id = %l, status = %d, ans_id = %l', msgId, status, answerMsgId);
808
+ return this._onMessageFailed(msgId, 'message info state = 0, ans_id = 0');
809
+ }
810
+ // fallthrough
811
+ case 4:
812
+ this._onMessageAcked(msgId);
813
+ break;
814
+ }
815
+ }
816
+ if (!answerMsgId.isZero() && !this._session.recentIncomingMsgIds.has(answerMsgId)) {
817
+ this.log.debug('received message info for %l, but answer (%l) was not received yet', msgId, answerMsgId);
818
+ this._session.queuedResendReq.push(answerMsgId);
819
+ this._flushTimer.emitWhenIdle();
820
+ return;
821
+ }
822
+ this.log.debug('received message info for %l, and answer (%l) was already received', msgId, answerMsgId);
823
+ }
824
+ _onMessagesInfo(msgIds, info) {
825
+ if (msgIds.length !== info.length) {
826
+ this.log.warn('messages state info was invalid: msg_ids.length !== info.length');
827
+ }
828
+ for (let i = 0; i < msgIds.length; i++) {
829
+ this._onMessageInfo(msgIds[i], info[i], Long.ZERO);
830
+ }
831
+ }
832
+ _onMsgsStateInfo(msg) {
833
+ const info = this._session.pendingMessages.get(msg.reqMsgId);
834
+ if (!info) {
835
+ this.log.warn('received msgs_state_info to unknown request %l', msg.reqMsgId);
836
+ return;
837
+ }
838
+ if (info._ !== 'state') {
839
+ this.log.warn('received msgs_state_info to %s query %l', info._, msg.reqMsgId);
840
+ return;
841
+ }
842
+ this._onMessagesInfo(info.msgIds, msg.info);
843
+ }
844
+ _onDestroySessionResult(msg) {
845
+ const reqMsgId = this._session.destroySessionIdToMsgId.get(msg.sessionId);
846
+ if (!reqMsgId) {
847
+ this.log.warn('received %s for unknown session %h', msg._, msg.sessionId);
848
+ return;
849
+ }
850
+ this._session.destroySessionIdToMsgId.delete(msg.sessionId);
851
+ this._session.pendingMessages.delete(reqMsgId);
852
+ this.log.debug('received %s for session %h', msg._, msg.sessionId);
853
+ }
854
+ _enqueueRpc(rpc, force) {
855
+ if (this._session.enqueueRpc(rpc, force)) {
856
+ this._flushTimer.emitWhenIdle();
857
+ }
858
+ }
859
+ _resetSession() {
860
+ this._queuedDestroySession.push(this._session._sessionId);
861
+ this._session.resetState(true);
862
+ this.reconnect();
863
+ // once we receive new_session_created, all pending messages will be resent.
864
+ this._flushTimer.reset();
865
+ }
866
+ _sendAck(msgId) {
867
+ if (this._session.queuedAcks.length === 0) {
868
+ this._flushTimer.emitBeforeNext(30000);
869
+ }
870
+ this._session.queuedAcks.push(msgId);
871
+ if (this._session.queuedAcks.length >= 100) {
872
+ this._flushTimer.emitWhenIdle();
873
+ }
874
+ }
875
+ sendRpc(request, stack, timeout, abortSignal) {
876
+ if (this._usable && this.params.inactivityTimeout) {
877
+ this._rescheduleInactivity();
878
+ }
879
+ if (!stack && this.params.niceStacks !== false) {
880
+ stack = new Error().stack;
881
+ }
882
+ const method = request._;
883
+ let obj = request;
884
+ let initConn = false;
885
+ if (this.params.disableUpdates) {
886
+ obj = {
887
+ _: 'invokeWithoutUpdates',
888
+ query: obj,
889
+ };
890
+ }
891
+ if (!this._session.initConnectionCalled) {
892
+ // we will wrap every rpc call with initConnection
893
+ // until some of the requests wrapped with it is
894
+ // either acked or returns rpc_result
895
+ this.log.debug('wrapping %s with initConnection, layer: %d', method, this.params.layer);
896
+ const proxy = this._transport.getMtproxyInfo?.();
897
+ obj = {
898
+ _: 'invokeWithLayer',
899
+ layer: this.params.layer,
900
+ query: {
901
+ ...this.params.initConnection,
902
+ proxy,
903
+ query: obj,
904
+ },
905
+ };
906
+ initConn = true;
907
+ }
908
+ this.log.verbose('>>> %j', obj);
909
+ let content = TlBinaryWriter.serializeObject(this._writerMap, obj);
910
+ if (content.length > 1044404) {
911
+ // if you send larger payloads, telegram will just close connection,
912
+ // and since we resend them, it will get resent after reconnection and
913
+ // that will be an endless loop of reconnections. we don't want that,
914
+ // and payloads this large are usually a sign of an error in the code.
915
+ throw new MtArgumentError(`Payload is too big (${content.length} > 1044404)`);
916
+ }
917
+ // gzip
918
+ let shouldGzip = content.length > 128;
919
+ if (content.length > 16384) {
920
+ // test compression ratio for the middle part
921
+ // if it is less than 0.9, then try to compress the whole request
922
+ const middle = ~~((content.length - 1024) / 2);
923
+ const gzipped = gzipDeflate(content.subarray(middle, middle + 1024), 0.9);
924
+ if (!gzipped)
925
+ shouldGzip = false;
926
+ }
927
+ if (shouldGzip) {
928
+ const gzipped = gzipDeflate(content, 0.9);
929
+ if (gzipped) {
930
+ this.log.debug('gzipped %s (%db -> %db)', method, content.length, gzipped.length);
931
+ content = gzipped;
932
+ }
933
+ else {
934
+ shouldGzip = false;
935
+ }
936
+ }
937
+ const pending = {
938
+ method,
939
+ promise: createControllablePromise(),
940
+ data: content,
941
+ stack,
942
+ // we will need to know size of gzip_packed overhead in _flush()
943
+ gzipOverhead: shouldGzip ? 4 + TlSerializationCounter.countBytesOverhead(content.length) : 0,
944
+ initConn,
945
+ // setting them as well so jit can optimize stuff
946
+ sent: undefined,
947
+ done: undefined,
948
+ getState: undefined,
949
+ msgId: undefined,
950
+ seqNo: undefined,
951
+ containerId: undefined,
952
+ acked: undefined,
953
+ cancelled: undefined,
954
+ timeout: undefined,
955
+ };
956
+ if (abortSignal?.aborted) {
957
+ pending.promise.reject(abortSignal.reason);
958
+ return pending.promise;
959
+ }
960
+ if (timeout) {
961
+ pending.timeout = setTimeout(this._cancelRpc, timeout, pending, true);
962
+ }
963
+ if (abortSignal) {
964
+ abortSignal.addEventListener('abort', () => this._cancelRpc(pending, false, abortSignal));
965
+ }
966
+ this._enqueueRpc(pending, true);
967
+ return pending.promise;
968
+ }
969
+ _cancelRpc(rpc, onTimeout = false, abortSignal) {
970
+ if (rpc.done)
971
+ return;
972
+ if (rpc.cancelled && !onTimeout) {
973
+ throw new MtcuteError('RPC was already cancelled');
974
+ }
975
+ if (!onTimeout && rpc.timeout) {
976
+ clearTimeout(rpc.timeout);
977
+ }
978
+ if (onTimeout) {
979
+ // todo: replace with MtTimeoutError
980
+ const error = new tl.RpcError(400, 'Client timeout');
981
+ if (this.params.niceStacks !== false) {
982
+ makeNiceStack(error, rpc.stack, rpc.method);
983
+ }
984
+ rpc.promise.reject(error);
985
+ }
986
+ else if (abortSignal) {
987
+ rpc.promise.reject(abortSignal.reason);
988
+ }
989
+ rpc.cancelled = true;
990
+ if (rpc.msgId) {
991
+ this._session.queuedCancelReq.push(rpc.msgId);
992
+ this._flushTimer.emitWhenIdle();
993
+ }
994
+ else {
995
+ // in case rpc wasn't sent yet (or had some error),
996
+ // we can simply remove it from queue
997
+ this._session.queuedRpc.remove(rpc);
998
+ }
999
+ }
1000
+ _onInactivityTimeout() {
1001
+ // we should send all pending acks and other service messages
1002
+ // before dropping the connection
1003
+ if (!this._session.hasPendingMessages) {
1004
+ this.log.debug('no pending service messages, closing connection');
1005
+ super._onInactivityTimeout();
1006
+ return;
1007
+ }
1008
+ this._inactivityPendingFlush = true;
1009
+ this._flush();
1010
+ }
1011
+ flushWhenIdle() {
1012
+ this._flushTimer.emitWhenIdle();
1013
+ }
1014
+ _flush() {
1015
+ if (!this._session._authKey.ready || this._isPfsBindingPending || this._session.current429Timeout) {
1016
+ this.log.debug('skipping flush, connection is not usable (auth key ready = %b, pfs binding pending = %b, 429 timeout = %b)', this._session._authKey.ready, this._isPfsBindingPending, Boolean(this._session.current429Timeout));
1017
+ // it will be flushed once connection is usable
1018
+ return;
1019
+ }
1020
+ try {
1021
+ this._doFlush();
1022
+ }
1023
+ catch (e) {
1024
+ this.log.error('flush error: %s', e.stack);
1025
+ // should not happen unless there's a bug in the code
1026
+ }
1027
+ // schedule next flush
1028
+ // if there are more queued requests, flush immediately
1029
+ // (they likely didn't fit into one message)
1030
+ if (this._session.hasPendingMessages) {
1031
+ // we schedule it on the next tick, so we can load-balance
1032
+ // between multiple connections using the same session
1033
+ this._flushTimer.emitWhenIdle();
1034
+ }
1035
+ else if (this._inactivityPendingFlush) {
1036
+ this.log.debug('pending messages sent, closing connection');
1037
+ this._flushTimer.reset();
1038
+ this._inactivityPendingFlush = false;
1039
+ super._onInactivityTimeout();
1040
+ }
1041
+ else {
1042
+ this._flushTimer.emitBefore(this._session.lastPingTime + 60000);
1043
+ }
1044
+ }
1045
+ _doFlush() {
1046
+ this.log.debug('flushing send queue. queued rpc: %d', this._session.queuedRpc.length);
1047
+ // oh bloody hell mate
1048
+ // total size & count
1049
+ let packetSize = 0;
1050
+ let messageCount = 0;
1051
+ // size & msg count that count towards container limit
1052
+ // these will be added to total later
1053
+ let containerMessageCount = 0;
1054
+ let containerSize = 0;
1055
+ let ackRequest = null;
1056
+ let ackMsgIds = null;
1057
+ let pingRequest = null;
1058
+ let pingId = null;
1059
+ let pingMsgId = null;
1060
+ let getStateRequest = null;
1061
+ let getStateMsgId = null;
1062
+ let getStateMsgIds = null;
1063
+ let resendRequest = null;
1064
+ let resendMsgId = null;
1065
+ let resendMsgIds = null;
1066
+ let cancelRpcs = null;
1067
+ let destroySessions = null;
1068
+ let rootMsgId = null;
1069
+ const now = Date.now();
1070
+ if (this._session.queuedAcks.length) {
1071
+ let acks = this._session.queuedAcks;
1072
+ if (acks.length > 8192) {
1073
+ this._session.queuedAcks = acks.slice(8192);
1074
+ acks = acks.slice(0, 8192);
1075
+ }
1076
+ else {
1077
+ this._session.queuedAcks = [];
1078
+ }
1079
+ const obj = {
1080
+ _: 'mt_msgs_ack',
1081
+ msgIds: acks,
1082
+ };
1083
+ ackMsgIds = obj.msgIds;
1084
+ ackRequest = TlBinaryWriter.serializeObject(this._writerMap, obj);
1085
+ packetSize += ackRequest.length + 16;
1086
+ messageCount += 1;
1087
+ }
1088
+ const getStateTime = now + 1500;
1089
+ if (now - this._session.lastPingTime > 60000) {
1090
+ if (!this._session.lastPingMsgId.isZero()) {
1091
+ this.log.warn("didn't receive pong for previous ping (msg_id = %l)", this._session.lastPingMsgId);
1092
+ this._session.pendingMessages.delete(this._session.lastPingMsgId);
1093
+ }
1094
+ pingId = randomLong();
1095
+ const obj = {
1096
+ _: 'mt_ping',
1097
+ pingId,
1098
+ };
1099
+ this._session.lastPingTime = Date.now();
1100
+ pingRequest = TlBinaryWriter.serializeObject(this._writerMap, obj);
1101
+ containerSize += pingRequest.length + 16;
1102
+ containerMessageCount += 1;
1103
+ }
1104
+ {
1105
+ if (this._session.queuedStateReq.length) {
1106
+ let ids = this._session.queuedStateReq;
1107
+ if (ids.length > 8192) {
1108
+ this._session.queuedStateReq = ids.slice(8192);
1109
+ ids = ids.slice(0, 8192);
1110
+ }
1111
+ else {
1112
+ this._session.queuedStateReq = [];
1113
+ }
1114
+ getStateMsgIds = ids;
1115
+ }
1116
+ const idx = this._session.getStateSchedule.index({ getState: now }, true);
1117
+ if (idx > 0) {
1118
+ const toGetState = this._session.getStateSchedule.raw.splice(0, idx);
1119
+ if (!getStateMsgIds)
1120
+ getStateMsgIds = [];
1121
+ toGetState.forEach((it) => getStateMsgIds.push(it.msgId));
1122
+ }
1123
+ if (getStateMsgIds) {
1124
+ const obj = {
1125
+ _: 'mt_msgs_state_req',
1126
+ msgIds: getStateMsgIds,
1127
+ };
1128
+ getStateRequest = TlBinaryWriter.serializeObject(this._writerMap, obj);
1129
+ packetSize += getStateRequest.length + 16;
1130
+ messageCount += 1;
1131
+ }
1132
+ }
1133
+ if (this._session.queuedResendReq.length) {
1134
+ resendMsgIds = this._session.queuedResendReq;
1135
+ if (resendMsgIds.length > 8192) {
1136
+ this._session.queuedResendReq = resendMsgIds.slice(8192);
1137
+ resendMsgIds = resendMsgIds.slice(0, 8192);
1138
+ }
1139
+ else {
1140
+ this._session.queuedResendReq = [];
1141
+ }
1142
+ const obj = {
1143
+ _: 'mt_msg_resend_req',
1144
+ msgIds: resendMsgIds,
1145
+ };
1146
+ resendRequest = TlBinaryWriter.serializeObject(this._writerMap, obj);
1147
+ packetSize += resendRequest.length + 16;
1148
+ messageCount += 1;
1149
+ }
1150
+ if (this._session.queuedCancelReq.length) {
1151
+ containerMessageCount += this._session.queuedCancelReq.length;
1152
+ containerSize += this._session.queuedCancelReq.length * 28;
1153
+ cancelRpcs = this._session.queuedCancelReq;
1154
+ this._session.queuedCancelReq = [];
1155
+ }
1156
+ if (this._queuedDestroySession.length) {
1157
+ containerMessageCount += this._queuedDestroySession.length;
1158
+ containerSize += this._queuedDestroySession.length * 28;
1159
+ destroySessions = this._queuedDestroySession;
1160
+ this._queuedDestroySession = [];
1161
+ }
1162
+ let forceContainer = false;
1163
+ const rpcToSend = [];
1164
+ while (this._session.queuedRpc.length &&
1165
+ containerSize < 32768 && // 2^15
1166
+ containerMessageCount < 1020) {
1167
+ const msg = this._session.queuedRpc.popFront();
1168
+ if (msg.cancelled)
1169
+ continue;
1170
+ // note: we don't check for <2^15 here
1171
+ // this is not documented, but large requests
1172
+ // (like upload.saveFilePart) *may* exceed that limit
1173
+ rpcToSend.push(msg);
1174
+ containerSize += msg.data.length + 16;
1175
+ if (msg.gzipOverhead)
1176
+ containerSize += msg.gzipOverhead;
1177
+ // if message was already assigned a msg_id,
1178
+ // we must wrap it in a container with a newer msg_id
1179
+ if (msg.msgId)
1180
+ forceContainer = true;
1181
+ // having >1 upload.getFile within a container seems to cause flood_wait errors
1182
+ // also a crutch for load-balancing
1183
+ if (msg.method === 'upload.getFile')
1184
+ break;
1185
+ }
1186
+ packetSize += containerSize;
1187
+ messageCount += containerMessageCount + rpcToSend.length;
1188
+ if (!messageCount) {
1189
+ this.log.debug('flush did not happen: nothing to flush');
1190
+ return;
1191
+ }
1192
+ const useContainer = forceContainer || messageCount > 1;
1193
+ if (useContainer)
1194
+ packetSize += 24; // 8 (msg_container) + 16 (mtproto header)
1195
+ const writer = TlBinaryWriter.alloc(this._writerMap, packetSize);
1196
+ if (useContainer) {
1197
+ // leave bytes for mtproto header (we'll write it later,
1198
+ // since we need seqno and msg_id to be larger than the content)
1199
+ writer.pos += 16;
1200
+ writer.uint(0x73f1f8dc); // msg_container
1201
+ writer.uint(messageCount);
1202
+ }
1203
+ const otherPendings = [];
1204
+ if (ackRequest) {
1205
+ this._registerOutgoingMsgId(this._session.writeMessage(writer, ackRequest));
1206
+ }
1207
+ if (pingRequest) {
1208
+ pingMsgId = this._registerOutgoingMsgId(this._session.writeMessage(writer, pingRequest));
1209
+ this._session.lastPingMsgId = pingMsgId;
1210
+ const pingPending = {
1211
+ _: 'ping',
1212
+ pingId: pingId,
1213
+ containerId: pingMsgId,
1214
+ };
1215
+ this._session.pendingMessages.set(pingMsgId, pingPending);
1216
+ otherPendings.push(pingPending);
1217
+ }
1218
+ if (getStateRequest) {
1219
+ getStateMsgId = this._registerOutgoingMsgId(this._session.writeMessage(writer, getStateRequest));
1220
+ const getStatePending = {
1221
+ _: 'state',
1222
+ msgIds: getStateMsgIds,
1223
+ containerId: getStateMsgId,
1224
+ };
1225
+ this._session.pendingMessages.set(getStateMsgId, getStatePending);
1226
+ otherPendings.push(getStatePending);
1227
+ }
1228
+ if (resendRequest) {
1229
+ resendMsgId = this._registerOutgoingMsgId(this._session.writeMessage(writer, resendRequest));
1230
+ const resendPending = {
1231
+ _: 'resend',
1232
+ msgIds: resendMsgIds,
1233
+ containerId: resendMsgId,
1234
+ };
1235
+ this._session.pendingMessages.set(resendMsgId, resendPending);
1236
+ otherPendings.push(resendPending);
1237
+ }
1238
+ if (cancelRpcs) {
1239
+ cancelRpcs.forEach((msgId) => {
1240
+ const cancelMsgId = this._registerOutgoingMsgId(this._session.writeMessage(writer, {
1241
+ _: 'mt_rpc_drop_answer',
1242
+ reqMsgId: msgId,
1243
+ }));
1244
+ const pending = {
1245
+ _: 'cancel',
1246
+ msgId,
1247
+ containerId: cancelMsgId,
1248
+ };
1249
+ this._session.pendingMessages.set(cancelMsgId, pending);
1250
+ otherPendings.push(pending);
1251
+ });
1252
+ }
1253
+ if (destroySessions) {
1254
+ destroySessions.forEach((sessionId) => {
1255
+ const msgId = this._registerOutgoingMsgId(this._session.writeMessage(writer, {
1256
+ _: 'mt_destroy_session',
1257
+ sessionId,
1258
+ }));
1259
+ const pending = {
1260
+ _: 'destroy_session',
1261
+ sessionId,
1262
+ containerId: msgId,
1263
+ };
1264
+ this._session.pendingMessages.set(msgId, pending);
1265
+ this._session.destroySessionIdToMsgId.set(sessionId, msgId);
1266
+ otherPendings.push(pending);
1267
+ });
1268
+ }
1269
+ for (let i = 0; i < rpcToSend.length; i++) {
1270
+ const msg = rpcToSend[i];
1271
+ // not using writeMessage here because we also need seqNo, and
1272
+ // i dont want to also return seqNo there because that would mean
1273
+ // extra object overhead
1274
+ if (!msg.msgId) {
1275
+ const msgId = this._session.getMessageId();
1276
+ const seqNo = this._session.getSeqNo();
1277
+ this.log.debug('%s: msg_id assigned %l, seqno: %d', msg.method, msgId, seqNo);
1278
+ msg.msgId = msgId;
1279
+ msg.seqNo = seqNo;
1280
+ this._session.pendingMessages.set(msgId, {
1281
+ _: 'rpc',
1282
+ rpc: msg,
1283
+ });
1284
+ }
1285
+ else {
1286
+ this.log.debug('%s: msg_id already assigned, reusing %l, seqno: %d', msg.method, msg.msgId, msg.seqNo);
1287
+ }
1288
+ // (re-)schedule get_state if needed
1289
+ if (msg.getState) {
1290
+ this._session.getStateSchedule.remove(msg);
1291
+ }
1292
+ if (!msg.acked) {
1293
+ msg.getState = getStateTime;
1294
+ this._session.getStateSchedule.insert(msg);
1295
+ }
1296
+ if (rootMsgId === null)
1297
+ rootMsgId = msg.msgId;
1298
+ writer.long(this._registerOutgoingMsgId(msg.msgId));
1299
+ writer.uint(msg.seqNo);
1300
+ if (msg.gzipOverhead) {
1301
+ writer.uint(msg.data.length + msg.gzipOverhead);
1302
+ writer.uint(0x3072cfa1); // gzip_packed#3072cfa1
1303
+ writer.bytes(msg.data);
1304
+ }
1305
+ else {
1306
+ writer.uint(msg.data.length);
1307
+ writer.raw(msg.data);
1308
+ }
1309
+ msg.sent = true;
1310
+ }
1311
+ if (useContainer) {
1312
+ // we now need to assign the container msg_id and seqno
1313
+ // we couldn't have assigned them earlier because mtproto
1314
+ // requires them to be >= than the contained messages
1315
+ // writer.pos is expected to be packetSize
1316
+ const containerId = this._session.getMessageId();
1317
+ writer.pos = 0;
1318
+ rootMsgId = containerId;
1319
+ writer.long(this._registerOutgoingMsgId(containerId));
1320
+ writer.uint(this._session.getSeqNo(false));
1321
+ writer.uint(packetSize - 16);
1322
+ writer.pos = packetSize;
1323
+ const msgIds = [];
1324
+ for (let i = 0; i < rpcToSend.length; i++) {
1325
+ const msg = rpcToSend[i];
1326
+ msg.containerId = containerId;
1327
+ msgIds.push(msg.msgId);
1328
+ }
1329
+ if (otherPendings.length) {
1330
+ otherPendings.forEach((msg) => {
1331
+ msgIds.push(msg.containerId);
1332
+ msg.containerId = containerId;
1333
+ });
1334
+ }
1335
+ this._session.pendingMessages.set(containerId, {
1336
+ _: 'container',
1337
+ msgIds,
1338
+ });
1339
+ }
1340
+ const result = writer.result();
1341
+ // probably the easiest way lol
1342
+ this.log.debug('sending %d messages: size = %db, acks = %d (msg_id = %s), ping = %s (msg_id = %s), state_req = %s (msg_id = %s), resend = %s (msg_id = %s), cancels = %s (msg_id = %s), rpc = %s, container = %s, root msg_id = %l', messageCount, packetSize, ackMsgIds?.length || 'false', ackMsgIds?.map((it) => it.toString()), Boolean(pingRequest), pingMsgId, getStateMsgIds?.map((it) => it.toString()) || 'false', getStateMsgId, resendMsgIds?.map((it) => it.toString()) || 'false', cancelRpcs, cancelRpcs?.map((it) => it.toString()) || 'false', resendMsgId, rpcToSend.map((it) => it.method), useContainer, rootMsgId);
1343
+ this._session
1344
+ .encryptMessage(result)
1345
+ .then((enc) => this.send(enc))
1346
+ .catch((err) => {
1347
+ this.log.error('error while sending pending messages (root msg_id = %l): %s', rootMsgId, err.stack);
1348
+ // put acks in the front so they are the first to be sent
1349
+ if (ackMsgIds) {
1350
+ this._session.queuedAcks.splice(0, 0, ...ackMsgIds);
1351
+ }
1352
+ this._onMessageFailed(rootMsgId, 'unknown error');
1353
+ });
1354
+ }
1355
+ }
1356
+ //# sourceMappingURL=session-connection.js.map