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