Utils.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. const {IS_NODE} = require('./Helpers')
  2. const { constructors } = require('./tl')
  3. const { requests } = require('./tl')
  4. const USERNAME_RE = new RegExp('@|(?:https?:\\/\\/)?(?:www\\.)?' +
  5. '(?:telegram\\.(?:me|dog)|t\\.me)\\/(@|joinchat\\/)?')
  6. const JPEG_HEADER = Buffer.from('ffd8ffe000104a46494600010100000100010000ffdb004300281c1e231e19282321232d2b28303c64413c37373c7b585d4964918099968f808c8aa0b4e6c3a0aadaad8a8cc8ffcbdaeef5ffffff9bc1fffffffaffe6fdfff8ffdb0043012b2d2d3c353c76414176f8a58ca5f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8ffc00011080000000003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00', 'hex')
  7. const JPEG_FOOTER = Buffer.from('ffd9', 'hex')
  8. const TG_JOIN_RE = new RegExp('tg:\\/\\/(join)\\?invite=')
  9. const VALID_USERNAME_RE = new RegExp('^([a-z]((?!__)[\\w\\d]){3,30}[a-z\\d]|gif|vid|' +
  10. 'pic|bing|wiki|imdb|bold|vote|like|coub)$')
  11. function _raiseCastFail(entity, target) {
  12. throw new Error(`Cannot cast ${entity.className} to any kind of ${target}`)
  13. }
  14. /**
  15. Gets the input peer for the given "entity" (user, chat or channel).
  16. A ``TypeError`` is raised if the given entity isn't a supported type
  17. or if ``check_hash is True`` but the entity's ``accessHash is None``
  18. *or* the entity contains ``min`` information. In this case, the hash
  19. cannot be used for general purposes, and thus is not returned to avoid
  20. any issues which can derive from invalid access hashes.
  21. Note that ``check_hash`` **is ignored** if an input peer is already
  22. passed since in that case we assume the user knows what they're doing.
  23. This is key to getting entities by explicitly passing ``hash = 0``.
  24. * @param entity
  25. * @param allowSelf
  26. * @param checkHash
  27. */
  28. function getInputPeer(entity, allowSelf = true, checkHash = true) {
  29. if (entity.SUBCLASS_OF_ID === undefined) {
  30. // e.g. custom.Dialog (can't cyclic import).
  31. if (allowSelf && 'inputEntity' in entity) {
  32. return entity.inputEntity
  33. } else if ('entity' in entity) {
  34. return getInputPeer(entity.entity)
  35. } else {
  36. _raiseCastFail(entity, 'InputPeer')
  37. }
  38. }
  39. if (entity.SUBCLASS_OF_ID === 0xc91c90b6) { // crc32(b'InputPeer')
  40. return entity
  41. }
  42. if (entity instanceof constructors.User) {
  43. if (entity.isSelf && allowSelf) {
  44. return new constructors.InputPeerSelf()
  45. } else if ((entity.accessHash !== undefined && !entity.min) || !checkHash) {
  46. return new constructors.InputPeerUser({
  47. userId: entity.id,
  48. accessHash: entity.accessHash,
  49. })
  50. } else {
  51. throw new Error('User without accessHash or min info cannot be input')
  52. }
  53. }
  54. if (entity instanceof constructors.Chat || entity instanceof constructors.ChatEmpty ||
  55. entity instanceof constructors.ChatForbidden) {
  56. return new constructors.InputPeerChat({ chatId: entity.id })
  57. }
  58. if (entity instanceof constructors.Channel) {
  59. if ((entity.accessHash !== undefined && !entity.min) || !checkHash) {
  60. return new constructors.InputPeerChannel({
  61. channelId: entity.id,
  62. accessHash: entity.accessHash,
  63. })
  64. } else {
  65. throw new TypeError('Channel without accessHash or min info cannot be input')
  66. }
  67. }
  68. if (entity instanceof constructors.ChannelForbidden) {
  69. // "channelForbidden are never min", and since their hash is
  70. // also not optional, we assume that this truly is the case.
  71. return new constructors.InputPeerChannel({
  72. channelId: entity.id,
  73. accessHash: entity.accessHash,
  74. })
  75. }
  76. if (entity instanceof constructors.InputUser) {
  77. return new constructors.InputPeerUser({
  78. userId: entity.userId,
  79. accessHash: entity.accessHash,
  80. })
  81. }
  82. if (entity instanceof constructors.InputChannel) {
  83. return new constructors.InputPeerChannel({
  84. channelId: entity.channelId,
  85. accessHash: entity.accessHash,
  86. })
  87. }
  88. if (entity instanceof constructors.UserEmpty) {
  89. return new constructors.InputPeerEmpty()
  90. }
  91. if (entity instanceof constructors.UserFull) {
  92. return getInputPeer(entity.user)
  93. }
  94. if (entity instanceof constructors.ChatFull) {
  95. return new constructors.InputPeerChat({ chatId: entity.id })
  96. }
  97. if (entity instanceof constructors.PeerChat) {
  98. return new constructors.InputPeerChat(entity.chatId)
  99. }
  100. _raiseCastFail(entity, 'InputPeer')
  101. }
  102. /**
  103. Similar to :meth:`get_input_peer`, but for :tl:`InputChannel`'s alone.
  104. .. important::
  105. This method does not validate for invalid general-purpose access
  106. hashes, unlike `get_input_peer`. Consider using instead:
  107. ``get_input_channel(get_input_peer(channel))``.
  108. * @param entity
  109. * @returns {InputChannel|*}
  110. */
  111. /*CONTEST
  112. function getInputChannel(entity) {
  113. if (entity.SUBCLASS_OF_ID === undefined) {
  114. _raiseCastFail(entity, 'InputChannel')
  115. }
  116. if (entity.SUBCLASS_OF_ID === 0x40f202fd) { // crc32(b'InputChannel')
  117. return entity
  118. }
  119. if (entity instanceof constructors.Channel || entity instanceof constructors.ChannelForbidden) {
  120. return new constructors.InputChannel({
  121. channelId: entity.id,
  122. accessHash: entity.accessHash || 0
  123. })
  124. }
  125. if (entity instanceof constructors.InputPeerChannel) {
  126. return new constructors.InputChannel({
  127. channelId: entity.channelId,
  128. accessHash: entity.accessHash
  129. })
  130. }
  131. _raiseCastFail(entity, 'InputChannel')
  132. }
  133. */
  134. /**
  135. Similar to :meth:`get_input_peer`, but for :tl:`InputUser`'s alone.
  136. .. important::
  137. This method does not validate for invalid general-purpose access
  138. hashes, unlike `get_input_peer`. Consider using instead:
  139. ``get_input_channel(get_input_peer(channel))``.
  140. * @param entity
  141. */
  142. /*CONTEST
  143. function getInputUser(entity) {
  144. if (entity.SUBCLASS_OF_ID === undefined) {
  145. _raiseCastFail(entity, 'InputUser')
  146. }
  147. if (entity.SUBCLASS_OF_ID === 0xe669bf46) { // crc32(b'InputUser')
  148. return entity
  149. }
  150. if (entity instanceof constructors.User) {
  151. if (entity.isSelf) {
  152. return new constructors.InputPeerSelf()
  153. } else {
  154. return new constructors.InputUser({
  155. userId: entity.id,
  156. accessHash: entity.accessHash || 0,
  157. })
  158. }
  159. }
  160. if (entity instanceof constructors.InputPeerSelf) {
  161. return new constructors.InputPeerSelf()
  162. }
  163. if (entity instanceof constructors.UserEmpty || entity instanceof constructors.InputPeerEmpty) {
  164. return new constructors.InputUserEmpty()
  165. }
  166. if (entity instanceof constructors.UserFull) {
  167. return getInputUser(entity.user)
  168. }
  169. if (entity instanceof constructors.InputPeerUser) {
  170. return new constructors.InputUser({
  171. userId: entity.userId,
  172. accessHash: entity.accessHash
  173. })
  174. }
  175. _raiseCastFail(entity, 'InputUser')
  176. }
  177. */
  178. /**
  179. Similar to :meth:`get_input_peer`, but for dialogs
  180. * @param dialog
  181. */
  182. /*CONTEST
  183. function getInputDialog(dialog) {
  184. try {
  185. if (dialog.SUBCLASS_OF_ID === 0xa21c9795) { // crc32(b'InputDialogPeer')
  186. return dialog
  187. }
  188. if (dialog.SUBCLASS_OF_ID === 0xc91c90b6) { // crc32(b'InputPeer')
  189. return new constructors.InputDialogPeer({ peer: dialog })
  190. }
  191. } catch (e) {
  192. _raiseCastFail(dialog, 'InputDialogPeer')
  193. }
  194. try {
  195. return new constructors.InputDialogPeer(getInputPeer(dialog))
  196. // eslint-disable-next-line no-empty
  197. } catch (e) {
  198. }
  199. _raiseCastFail(dialog, 'InputDialogPeer')
  200. }
  201. */
  202. /*CONTEST
  203. function getInputMessage(message) {
  204. try {
  205. if (typeof message == 'number') { // This case is really common too
  206. return new constructors.InputMessageID({
  207. id: message,
  208. })
  209. } else if (message.SUBCLASS_OF_ID === 0x54b6bcc5) { // crc32(b'InputMessage')
  210. return message
  211. } else if (message.SUBCLASS_OF_ID === 0x790009e3) { // crc32(b'Message')
  212. return new constructors.InputMessageID(message.id)
  213. }
  214. // eslint-disable-next-line no-empty
  215. } catch (e) {
  216. }
  217. _raiseCastFail(message, 'InputMessage')
  218. }
  219. */
  220. /**
  221. * Adds the JPG header and footer to a stripped image.
  222. * Ported from https://github.com/telegramdesktop/tdesktop/blob/bec39d89e19670eb436dc794a8f20b657cb87c71/Telegram/SourceFiles/ui/image/image.cpp#L225
  223. * @param stripped{Buffer}
  224. * @returns {Buffer}
  225. */
  226. function strippedPhotoToJpg(stripped) {
  227. // Note: Changes here should update _stripped_real_length
  228. if (stripped.length < 3 || stripped[0] !== 1) {
  229. return stripped
  230. }
  231. const header = Buffer.from(JPEG_HEADER)
  232. header[164] = stripped[1]
  233. header[166] = stripped[2]
  234. return Buffer.concat([header, stripped.slice(3), JPEG_FOOTER])
  235. }
  236. /*CONTEST
  237. function getInputLocation(location) {
  238. try {
  239. if (!location.SUBCLASS_OF_ID) {
  240. throw new Error()
  241. }
  242. if (location.SUBCLASS_OF_ID === 0x1523d462) {
  243. return {
  244. dcId: null,
  245. inputLocation: location
  246. }
  247. }
  248. } catch (e) {
  249. _raiseCastFail(location, 'InputFileLocation')
  250. }
  251. if (location instanceof constructors.Message) {
  252. location = location.media
  253. }
  254. if (location instanceof constructors.MessageMediaDocument) {
  255. location = location.document
  256. } else if (location instanceof constructors.MessageMediaPhoto) {
  257. location = location.photo
  258. }
  259. if (location instanceof constructors.Document) {
  260. return {
  261. dcId: location.dcId,
  262. inputLocation: new constructors.InputDocumentFileLocation({
  263. id: location.id,
  264. accessHash: location.accessHash,
  265. fileReference: location.fileReference,
  266. thumbSize: '', // Presumably to download one of its thumbnails
  267. }),
  268. }
  269. } else if (location instanceof constructors.Photo) {
  270. return {
  271. dcId: location.dcId,
  272. inputLocation: new constructors.InputPhotoFileLocation({
  273. id: location.id,
  274. accessHash: location.accessHash,
  275. fileReference: location.fileReference,
  276. thumbSize: location.sizes[location.sizes.length - 1].type,
  277. }),
  278. }
  279. }
  280. if (location instanceof constructors.FileLocationToBeDeprecated) {
  281. throw new Error('Unavailable location cannot be used as input')
  282. }
  283. _raiseCastFail(location, 'InputFileLocation')
  284. }
  285. */
  286. /**
  287. * Gets the appropriated part size when uploading or downloading files,
  288. * given an initial file size.
  289. * @param fileSize
  290. * @returns {Number}
  291. */
  292. function getAppropriatedPartSize(fileSize) {
  293. if (fileSize <= 104857600) { // 100MB
  294. return 128
  295. }
  296. if (fileSize <= 786432000) { // 750MB
  297. return 256
  298. }
  299. if (fileSize <= 1572864000) { // 1500MB
  300. return 512
  301. }
  302. throw new Error('File size too large')
  303. }
  304. /*CONTEST
  305. function getPeer(peer) {
  306. try {
  307. if (typeof peer === 'number') {
  308. const res = resolveId(peer)
  309. if (res[1] === constructors.PeerChannel) {
  310. return new res[1]({ channelId: res[0] })
  311. } else if (res[1] === constructors.PeerChat) {
  312. return new res[1]({ chatId: res[0] })
  313. } else {
  314. return new res[1]({ userId: res[0] })
  315. }
  316. }
  317. if (peer.SUBCLASS_OF_ID === undefined) {
  318. throw new Error()
  319. }
  320. if (peer.SUBCLASS_OF_ID === 0x2d45687) {
  321. return peer
  322. } else if (peer instanceof constructors.contacts.ResolvedPeer ||
  323. peer instanceof constructors.InputNotifyPeer || peer instanceof constructors.TopPeer ||
  324. peer instanceof constructors.Dialog || peer instanceof constructors.DialogPeer) {
  325. return peer.peer
  326. } else if (peer instanceof constructors.ChannelFull) {
  327. return new constructors.PeerChannel({ channelId: peer.id })
  328. }
  329. if (peer.SUBCLASS_OF_ID === 0x7d7c6f86 || peer.SUBCLASS_OF_ID === 0xd9c7fc18) {
  330. // ChatParticipant, ChannelParticipant
  331. return new constructors.PeerUser({ userId: peer.userId })
  332. }
  333. peer = getInputPeer(peer, false, false)
  334. if (peer instanceof constructors.InputPeerUser) {
  335. return new constructors.PeerUser({ userId: peer.userId })
  336. } else if (peer instanceof constructors.InputPeerChat) {
  337. return new constructors.PeerChat({ chatId: peer.chatId })
  338. } else if (peer instanceof constructors.InputPeerChannel) {
  339. return new constructors.PeerChannel({ channelId: peer.channelId })
  340. }
  341. // eslint-disable-next-line no-empty
  342. } catch (e) {
  343. console.log(e)
  344. }
  345. _raiseCastFail(peer, 'peer')
  346. }
  347. */
  348. /**
  349. Convert the given peer into its marked ID by default.
  350. This "mark" comes from the "bot api" format, and with it the peer type
  351. can be identified back. User ID is left unmodified, chat ID is negated,
  352. and channel ID is prefixed with -100:
  353. * ``userId``
  354. * ``-chatId``
  355. * ``-100channel_id``
  356. The original ID and the peer type class can be returned with
  357. a call to :meth:`resolve_id(marked_id)`.
  358. * @param peer
  359. * @param addMark
  360. */
  361. /*CONTEST
  362. function getPeerId(peer, addMark = true) {
  363. // First we assert it's a Peer TLObject, or early return for integers
  364. if (typeof peer == 'number') {
  365. return addMark ? peer : resolveId(peer)[0]
  366. }
  367. // Tell the user to use their client to resolve InputPeerSelf if we got one
  368. if (peer instanceof constructors.InputPeerSelf) {
  369. _raiseCastFail(peer, 'int (you might want to use client.get_peer_id)')
  370. }
  371. try {
  372. peer = getPeer(peer)
  373. } catch (e) {
  374. _raiseCastFail(peer, 'int')
  375. }
  376. if (peer instanceof constructors.PeerUser) {
  377. return peer.userId
  378. } else if (peer instanceof constructors.PeerChat) {
  379. // Check in case the user mixed things up to avoid blowing up
  380. if (!(0 < peer.chatId <= 0x7fffffff)) {
  381. peer.chatId = resolveId(peer.chatId)[0]
  382. }
  383. return addMark ? -(peer.chatId) : peer.chatId
  384. } else { // if (peer instanceof constructors.PeerChannel)
  385. // Check in case the user mixed things up to avoid blowing up
  386. if (!(0 < peer.channelId <= 0x7fffffff)) {
  387. peer.channelId = resolveId(peer.channelId)[0]
  388. }
  389. if (!addMark) {
  390. return peer.channelId
  391. }
  392. // Concat -100 through math tricks, .to_supergroup() on
  393. // Madeline IDs will be strictly positive -> log works.
  394. try {
  395. return -(peer.channelId + Math.pow(10, Math.floor(Math.log10(peer.channelId) + 3)))
  396. } catch (e) {
  397. throw new Error('Cannot get marked ID of a channel unless its ID is strictly positive')
  398. }
  399. }
  400. }
  401. */
  402. /**
  403. * Given a marked ID, returns the original ID and its :tl:`Peer` type.
  404. * @param markedId
  405. */
  406. /*CONTEST
  407. function resolveId(markedId) {
  408. if (markedId >= 0) {
  409. return [markedId, constructors.PeerUser]
  410. }
  411. // There have been report of chat IDs being 10000xyz, which means their
  412. // marked version is -10000xyz, which in turn looks like a channel but
  413. // it becomes 00xyz (= xyz). Hence, we must assert that there are only
  414. // two zeroes.
  415. const m = markedId.toString()
  416. .match(/-100([^0]\d*)/)
  417. if (m) {
  418. return [parseInt(m[1]), constructors.PeerChannel]
  419. }
  420. return [-markedId, constructors.PeerChat]
  421. }
  422. */
  423. /**
  424. * returns an entity pair
  425. * @param entityId
  426. * @param entities
  427. * @param cache
  428. * @param getInputPeer
  429. * @returns {{inputEntity: *, entity: *}}
  430. * @private
  431. */
  432. /*CONTEST
  433. function _getEntityPair(entityId, entities, cache, getInputPeer = getInputPeer) {
  434. const entity = entities.get(entityId)
  435. let inputEntity = cache[entityId]
  436. if (inputEntity === undefined) {
  437. try {
  438. inputEntity = getInputPeer(inputEntity)
  439. } catch (e) {
  440. inputEntity = null
  441. }
  442. }
  443. return {
  444. entity,
  445. inputEntity
  446. }
  447. }
  448. */
  449. function getMessageId(message) {
  450. if (message === null || message === undefined) {
  451. return null
  452. }
  453. if (typeof message == 'number') {
  454. return message
  455. }
  456. if (message.SUBCLASS_OF_ID === 0x790009e3) { // crc32(b'Message')
  457. return message.id
  458. }
  459. throw new Error(`Invalid message type: ${message.constructor.name}`)
  460. }
  461. /**
  462. * Parses the given phone, or returns `None` if it's invalid.
  463. * @param phone
  464. */
  465. function parsePhone(phone) {
  466. return phone.toString().replace(/[+()\s-]/gm, '')
  467. }
  468. /**
  469. Parses the given username or channel access hash, given
  470. a string, username or URL. Returns a tuple consisting of
  471. both the stripped, lowercase username and whether it is
  472. a joinchat/ hash (in which case is not lowercase'd).
  473. Returns ``(None, False)`` if the ``username`` or link is not valid.
  474. * @param username {string}
  475. */
  476. /*CONTEST
  477. function parseUsername(username) {
  478. username = username.trim()
  479. const m = username.match(USERNAME_RE) || username.match(TG_JOIN_RE)
  480. if (m) {
  481. username = username.replace(m[0], '')
  482. if (m[1]) {
  483. return {
  484. username: username,
  485. isInvite: true
  486. }
  487. } else {
  488. username = rtrim(username, '/')
  489. }
  490. }
  491. if (username.match(VALID_USERNAME_RE)) {
  492. return {
  493. username: username.toLowerCase(),
  494. isInvite: false
  495. }
  496. } else {
  497. return {
  498. username: null,
  499. isInvite: false
  500. }
  501. }
  502. }
  503. function rtrim(s, mask) {
  504. while (~mask.indexOf(s[s.length - 1])) {
  505. s = s.slice(0, -1)
  506. }
  507. return s
  508. }
  509. */
  510. /**
  511. * Gets the display name for the given :tl:`User`,
  512. :tl:`Chat` or :tl:`Channel`. Returns an empty string otherwise
  513. * @param entity
  514. */
  515. function getDisplayName(entity) {
  516. if (entity instanceof constructors.User) {
  517. if (entity.lastName && entity.firstName) {
  518. return `${entity.firstName} ${entity.lastName}`
  519. } else if (entity.firstName) {
  520. return entity.firstName
  521. } else if (entity.lastName) {
  522. return entity.lastName
  523. } else {
  524. return ''
  525. }
  526. } else if (entity instanceof constructors.Chat || entity instanceof constructors.Channel) {
  527. return entity.title
  528. }
  529. return ''
  530. }
  531. /**
  532. * check if a given item is an array like or not
  533. * @param item
  534. * @returns {boolean}
  535. */
  536. /*CONTEST
  537. Duplicate ?
  538. function isListLike(item) {
  539. return (
  540. Array.isArray(item) ||
  541. (!!item &&
  542. typeof item === 'object' &&
  543. typeof (item.length) === 'number' &&
  544. (item.length === 0 ||
  545. (item.length > 0 &&
  546. (item.length - 1) in item)
  547. )
  548. )
  549. )
  550. }
  551. */
  552. async function getDC(dcId,client, cdn = false) {
  553. if (!IS_NODE){
  554. switch (dcId) {
  555. case 1:
  556. return {
  557. id: 1,
  558. ipAddress: IS_NODE?'':'pluto.web.telegram.org',
  559. port: 443,
  560. }
  561. case 2:
  562. return {
  563. id: 2,
  564. ipAddress: 'venus.web.telegram.org',
  565. port: 443,
  566. }
  567. case 3:
  568. return {
  569. id: 3,
  570. ipAddress: 'aurora.web.telegram.org',
  571. port: 443,
  572. }
  573. case 4:
  574. return {
  575. id: 4,
  576. ipAddress: 'vesta.web.telegram.org',
  577. port: 443,
  578. }
  579. case 5:
  580. return {
  581. id: 5,
  582. ipAddress: 'flora.web.telegram.org',
  583. port: 443,
  584. }
  585. default:
  586. throw new Error(`Cannot find the DC with the ID of ${dcId}`)
  587. }
  588. }
  589. if (!client._config) {
  590. client._config = await client.invoke(new requests.help.GetConfig())
  591. }
  592. if (cdn) {
  593. throw new Error('CDNs are Not supported')
  594. }
  595. for (const DC of client._config.dcOptions) {
  596. if (DC.id === dcId && Boolean(DC.ipv6) === client._useIPV6 && Boolean(DC.cdn) === cdn) {
  597. return {
  598. id:DC.id,
  599. ipAddress:DC.ipAddress,
  600. port:443,
  601. }
  602. }
  603. }
  604. }
  605. module.exports = {
  606. getMessageId,
  607. //_getEntityPair,
  608. //getInputMessage,
  609. //getInputDialog,
  610. //getInputUser,
  611. //getInputChannel,
  612. getInputPeer,
  613. //parsePhone,
  614. //parseUsername,
  615. //getPeer,
  616. //getPeerId,
  617. getDisplayName,
  618. //resolveId,
  619. //isListLike,
  620. getAppropriatedPartSize,
  621. //getInputLocation,
  622. strippedPhotoToJpg,
  623. getDC,
  624. }