messageParse.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import { getPeerId, sanitizeParseMode } from "../Utils";
  2. import { Api } from "../tl";
  3. import type { EntityLike } from "../define";
  4. import type { TelegramClient } from "./TelegramClient";
  5. import { utils } from "../index";
  6. import { _EntityType, _entityType, isArrayLike } from "../Helpers";
  7. import bigInt from "big-integer";
  8. export type messageEntities =
  9. | typeof Api.MessageEntityBold
  10. | typeof Api.MessageEntityItalic
  11. | typeof Api.MessageEntityStrike
  12. | typeof Api.MessageEntityCode
  13. | typeof Api.MessageEntityPre;
  14. export const DEFAULT_DELIMITERS: {
  15. [key: string]: messageEntities;
  16. } = {
  17. "**": Api.MessageEntityBold,
  18. __: Api.MessageEntityItalic,
  19. "~~": Api.MessageEntityStrike,
  20. "`": Api.MessageEntityCode,
  21. "```": Api.MessageEntityPre,
  22. };
  23. export interface ParseInterface {
  24. parse: (message: string) => [string, Api.TypeMessageEntity[]];
  25. unparse: (text: string, entities: Api.TypeMessageEntity[]) => string;
  26. }
  27. /** @hidden */
  28. export async function _replaceWithMention(
  29. client: TelegramClient,
  30. entities: Api.TypeMessageEntity[],
  31. i: number,
  32. user: EntityLike
  33. ) {
  34. try {
  35. entities[i] = new Api.InputMessageEntityMentionName({
  36. offset: entities[i].offset,
  37. length: entities[i].length,
  38. userId: (await client.getInputEntity(
  39. user
  40. )) as unknown as Api.TypeInputUser,
  41. });
  42. return true;
  43. } catch (e) {
  44. return false;
  45. }
  46. }
  47. /** @hidden */
  48. export async function _parseMessageText(
  49. client: TelegramClient,
  50. message: string,
  51. parseMode: false | string | ParseInterface
  52. ): Promise<[string, Api.TypeMessageEntity[]]> {
  53. if (parseMode == false) {
  54. return [message, []];
  55. }
  56. if (parseMode == undefined) {
  57. if (client.parseMode == undefined) {
  58. return [message, []];
  59. }
  60. parseMode = client.parseMode;
  61. } else if (typeof parseMode === "string") {
  62. parseMode = sanitizeParseMode(parseMode);
  63. }
  64. const [rawMessage, msgEntities] = parseMode.parse(message);
  65. for (let i = msgEntities.length - 1; i >= 0; i--) {
  66. const e = msgEntities[i];
  67. if (e instanceof Api.MessageEntityTextUrl) {
  68. const m = /^@|\+|tg:\/\/user\?id=(\d+)/.exec(e.url);
  69. if (m) {
  70. const userIdOrUsername = m[1] ? Number(m[1]) : e.url;
  71. const isMention = await _replaceWithMention(
  72. client,
  73. msgEntities,
  74. i,
  75. userIdOrUsername
  76. );
  77. if (!isMention) {
  78. msgEntities.splice(i, 1);
  79. }
  80. }
  81. }
  82. }
  83. return [rawMessage, msgEntities];
  84. }
  85. /** @hidden */
  86. export function _getResponseMessage(
  87. client: TelegramClient,
  88. request: any,
  89. result: any,
  90. inputChat: any
  91. ) {
  92. let updates = [];
  93. let entities = new Map();
  94. if (result instanceof Api.UpdateShort) {
  95. updates = [result.update];
  96. } else if (
  97. result instanceof Api.Updates ||
  98. result instanceof Api.UpdatesCombined
  99. ) {
  100. updates = result.updates;
  101. for (const x of [...result.users, ...result.chats]) {
  102. entities.set(utils.getPeerId(x), x);
  103. }
  104. } else {
  105. return;
  106. }
  107. const randomToId = new Map<string, number>();
  108. const idToMessage = new Map<number, Api.Message>();
  109. const schedToMessage = new Map<number, Api.Message>();
  110. for (const update of updates) {
  111. if (update instanceof Api.UpdateMessageID) {
  112. randomToId.set(update.randomId.toString(), update.id);
  113. } else if (
  114. update instanceof Api.UpdateNewChannelMessage ||
  115. update instanceof Api.UpdateNewMessage
  116. ) {
  117. (update.message as unknown as Api.Message)._finishInit(
  118. client,
  119. entities,
  120. inputChat
  121. );
  122. if ("randomId" in request || isArrayLike(request)) {
  123. idToMessage.set(
  124. update.message.id,
  125. update.message as unknown as Api.Message
  126. );
  127. } else {
  128. return update.message as unknown as Api.Message;
  129. }
  130. } else if (
  131. update instanceof Api.UpdateEditMessage &&
  132. "peer" in request &&
  133. _entityType(request.peer) != _EntityType.CHANNEL
  134. ) {
  135. (update.message as unknown as Api.Message)._finishInit(
  136. client,
  137. entities,
  138. inputChat
  139. );
  140. if ("randomId" in request) {
  141. idToMessage.set(
  142. update.message.id,
  143. update.message as unknown as Api.Message
  144. );
  145. } else if ("id" in request && request.id === update.message.id) {
  146. return update.message;
  147. }
  148. } else if (
  149. update instanceof Api.UpdateEditChannelMessage &&
  150. "peer" in request &&
  151. getPeerId(request.peer) ==
  152. getPeerId((update.message as unknown as Api.Message).peerId!)
  153. ) {
  154. if (request.id == update.message.id) {
  155. (update.message as unknown as Api.Message)._finishInit(
  156. client,
  157. entities,
  158. inputChat
  159. );
  160. return update.message;
  161. }
  162. } else if (update instanceof Api.UpdateNewScheduledMessage) {
  163. (update.message as unknown as Api.Message)._finishInit(
  164. client,
  165. entities,
  166. inputChat
  167. );
  168. schedToMessage.set(
  169. update.message.id,
  170. update.message as unknown as Api.Message
  171. );
  172. } else if (update instanceof Api.UpdateMessagePoll) {
  173. if (request.media.poll.id == update.pollId) {
  174. const m = new Api.Message({
  175. id: request.id,
  176. peerId: utils.getPeerId(request.peer),
  177. media: new Api.MessageMediaPoll({
  178. poll: update.poll!,
  179. results: update.results,
  180. }),
  181. message: "",
  182. date: 0,
  183. });
  184. m._finishInit(client, entities, inputChat);
  185. return m;
  186. }
  187. }
  188. }
  189. if (request == undefined) {
  190. return idToMessage;
  191. }
  192. let mapping: Map<number, Api.Message>;
  193. let opposite = new Map<number, Api.Message>();
  194. if ("scheduleDate" in request && request.scheduleDate != undefined) {
  195. mapping = schedToMessage;
  196. opposite = idToMessage;
  197. } else {
  198. mapping = idToMessage;
  199. }
  200. let randomId =
  201. isArrayLike(request) ||
  202. typeof request == "number" ||
  203. bigInt.isInstance(request)
  204. ? request
  205. : request.randomId.toString();
  206. if (!randomId) {
  207. client._log.warn(
  208. `No randomId in ${request} to map to. returning undefined for ${result}`
  209. );
  210. return undefined;
  211. }
  212. if (!isArrayLike(randomId)) {
  213. let msg = mapping.get(randomToId.get(randomId)!);
  214. if (!msg) {
  215. msg = opposite.get(randomToId.get(randomId)!);
  216. }
  217. if (!msg) {
  218. client._log.warn(
  219. `Request ${request.className} had missing message mapping ${result.className}`
  220. );
  221. }
  222. return msg;
  223. } else {
  224. const mappingToReturn = [];
  225. let warned = false;
  226. for (let i = 0; i < randomId.length; i++) {
  227. const rnd = randomId[i] + "";
  228. const msg = mapping.get(randomToId.get(rnd)!);
  229. if (!msg) {
  230. warned = true;
  231. break;
  232. } else {
  233. mappingToReturn.push(msg);
  234. }
  235. }
  236. if (!warned) {
  237. return mappingToReturn;
  238. }
  239. const oppositeToReturn = [];
  240. warned = false;
  241. for (let i = 0; i < randomId.length; i++) {
  242. const rnd = randomId[i] + "";
  243. const msg = opposite.get(randomToId.get(rnd)!);
  244. if (!msg) {
  245. client._log.warn(
  246. `Request ${request} had missing message mapping ${result}`
  247. );
  248. warned = true;
  249. break;
  250. } else {
  251. oppositeToReturn.push(msg);
  252. }
  253. }
  254. if (!warned) {
  255. return mappingToReturn;
  256. }
  257. }
  258. const finalToReturn = [];
  259. for (let i = 0; i < randomId.length; i++) {
  260. const rnd = randomId[i] + "";
  261. if (randomToId.has(rnd)) {
  262. finalToReturn.push(
  263. mapping.get(randomToId.get(rnd)!) ||
  264. opposite.get(randomToId.get(rnd)!)
  265. );
  266. }
  267. }
  268. return finalToReturn;
  269. }