feat: per-method disabling of no-dispatch

This commit is contained in:
alina 🌸 2023-10-09 23:15:23 +03:00 committed by Alina Tumanova
parent e01c876690
commit 3e5b2af7c0
17 changed files with 225 additions and 39 deletions

View file

@ -1050,6 +1050,12 @@ export interface TelegramClient extends BaseTelegramClient {
* This can be useful when fixing mistakes or banning cheaters * This can be useful when fixing mistakes or banning cheaters
*/ */
force?: boolean force?: boolean
/**
* Whether to dispatch the edit message event
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> ): Promise<Message>
/** /**
@ -1161,8 +1167,15 @@ export interface TelegramClient extends BaseTelegramClient {
banChatMember(params: { banChatMember(params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
/** ID of the user/channel to ban */ /** ID of the user/channel to ban */
participantId: InputPeerLike participantId: InputPeerLike
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message | null> }): Promise<Message | null>
/** /**
* Create a new broadcast channel * Create a new broadcast channel
@ -2314,6 +2327,12 @@ export interface TelegramClient extends BaseTelegramClient {
* Send as a specific channel * Send as a specific channel
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message> }): Promise<Message>
/** /**
* Delete a forum topic and all its history * Delete a forum topic and all its history
@ -2354,6 +2373,12 @@ export interface TelegramClient extends BaseTelegramClient {
* and use static color instead * and use static color instead
*/ */
icon?: tl.Long | null icon?: tl.Long | null
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message> }): Promise<Message>
/** /**
* Get a single forum topic by its ID * Get a single forum topic by its ID
@ -2457,6 +2482,12 @@ export interface TelegramClient extends BaseTelegramClient {
/** Whether the topic should be closed */ /** Whether the topic should be closed */
closed: boolean closed: boolean
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message> }): Promise<Message>
/** /**
* Toggle whether a topic in a forum is pinned * Toggle whether a topic in a forum is pinned
@ -2491,11 +2522,20 @@ export interface TelegramClient extends BaseTelegramClient {
* *
* **Available**: both users and bots * **Available**: both users and bots
* *
* @param chatId Chat ID or username
* @param hidden Whether the topic should be hidden
* @returns Service message about the modification * @returns Service message about the modification
*/ */
toggleGeneralTopicHidden(chatId: InputPeerLike, hidden: boolean): Promise<Message> toggleGeneralTopicHidden(params: {
/** Chat ID or username */
chatId: InputPeerLike
/** Whether the topic should be hidden */
hidden: boolean
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}): Promise<Message>
/** /**
* Create an additional invite link for the chat. * Create an additional invite link for the chat.
* *
@ -2794,7 +2834,15 @@ export interface TelegramClient extends BaseTelegramClient {
* **Available**: both users and bots * **Available**: both users and bots
* *
*/ */
closePoll(params: InputMessageId): Promise<Poll> closePoll(
params: InputMessageId & {
/**
* Whether to dispatch the edit message event
* to the client's update handler.
*/
shouldDispatch?: true
},
): Promise<Poll>
/** /**
* Delete messages by their IDs * Delete messages by their IDs
* *
@ -2952,10 +3000,16 @@ export interface TelegramClient extends BaseTelegramClient {
* @param total Total file size in bytes * @param total Total file size in bytes
*/ */
progressCallback?: (uploaded: number, total: number) => void progressCallback?: (uploaded: number, total: number) => void
/**
* Whether to dispatch the edit message event
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> ): Promise<Message>
_findMessageInUpdate(res: tl.TypeUpdates, isEdit?: boolean): Message _findMessageInUpdate(res: tl.TypeUpdates, isEdit?: boolean, noDispatch?: boolean): Message
/** /**
* Forward one or more messages by their IDs. * Forward one or more messages by their IDs.
* You can forward no more than 100 messages at once. * You can forward no more than 100 messages at once.
@ -3310,8 +3364,10 @@ export interface TelegramClient extends BaseTelegramClient {
* *
* For supergroups/channels, you must have appropriate permissions, * For supergroups/channels, you must have appropriate permissions,
* either as an admin, or as default permissions * either as an admin, or as default permissions
*
* **Available**: both users and bots * **Available**: both users and bots
* *
* @returns Service message about pinned message, if one was generated.
*/ */
pinMessage( pinMessage(
params: InputMessageId & { params: InputMessageId & {
@ -3319,8 +3375,14 @@ export interface TelegramClient extends BaseTelegramClient {
notify?: boolean notify?: boolean
/** Whether to pin for both sides (only for private chats) */ /** Whether to pin for both sides (only for private chats) */
bothSides?: boolean bothSides?: boolean
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<void> ): Promise<Message | null>
/** /**
* Mark chat history as read. * Mark chat history as read.
* *
@ -3741,6 +3803,12 @@ export interface TelegramClient extends BaseTelegramClient {
* Peer to use when sending the message. * Peer to use when sending the message.
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the returned message
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> ): Promise<Message>
/** /**
@ -3756,6 +3824,12 @@ export interface TelegramClient extends BaseTelegramClient {
emoji?: InputReaction | null emoji?: InputReaction | null
/** Whether to use a big reaction */ /** Whether to use a big reaction */
big?: boolean big?: boolean
/**
* Whether to dispatch the returned edit message event
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> ): Promise<Message>
/** /**
@ -3871,6 +3945,12 @@ export interface TelegramClient extends BaseTelegramClient {
* Peer to use when sending the message. * Peer to use when sending the message.
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the returned message
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> ): Promise<Message>
/** /**

View file

@ -32,9 +32,15 @@ export async function setGameScore(
* This can be useful when fixing mistakes or banning cheaters * This can be useful when fixing mistakes or banning cheaters
*/ */
force?: boolean force?: boolean
/**
* Whether to dispatch the edit message event
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { userId, score, noEdit, force } = params const { userId, score, noEdit, force, shouldDispatch } = params
const { chatId, message } = normalizeInputMessageId(params) const { chatId, message } = normalizeInputMessageId(params)
const user = normalizeToInputUser(await resolvePeer(client, userId), userId) const user = normalizeToInputUser(await resolvePeer(client, userId), userId)
@ -50,7 +56,7 @@ export async function setGameScore(
force, force,
}) })
return _findMessageInUpdate(client, res, true) return _findMessageInUpdate(client, res, true, !shouldDispatch)
} }
/** /**

View file

@ -25,12 +25,20 @@ export async function banChatMember(
params: { params: {
/** Chat ID */ /** Chat ID */
chatId: InputPeerLike chatId: InputPeerLike
/** ID of the user/channel to ban */ /** ID of the user/channel to ban */
participantId: InputPeerLike participantId: InputPeerLike
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message | null> { ): Promise<Message | null> {
const chat = await resolvePeer(client, params.chatId) const { chatId, participantId, shouldDispatch } = params
const peer = await resolvePeer(client, params.participantId) const chat = await resolvePeer(client, chatId)
const peer = await resolvePeer(client, participantId)
let res let res
if (isInputPeerChannel(chat)) { if (isInputPeerChannel(chat)) {
@ -51,10 +59,10 @@ export async function banChatMember(
chatId: chat.chatId, chatId: chat.chatId,
userId: normalizeToInputUser(peer), userId: normalizeToInputUser(peer),
}) })
} else throw new MtInvalidPeerTypeError(params.chatId, 'chat or channel') } else throw new MtInvalidPeerTypeError(chatId, 'chat or channel')
try { try {
return _findMessageInUpdate(client, res) return _findMessageInUpdate(client, res, false, !shouldDispatch)
} catch (e) { } catch (e) {
if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') { if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') {
// no service message // no service message

View file

@ -38,9 +38,15 @@ export async function createForumTopic(
* Send as a specific channel * Send as a specific channel
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { chatId, title, icon, sendAs } = params const { chatId, title, icon, sendAs, shouldDispatch } = params
const res = await client.call({ const res = await client.call({
_: 'channels.createForumTopic', _: 'channels.createForumTopic',
@ -52,5 +58,5 @@ export async function createForumTopic(
randomId: randomLong(), randomId: randomLong(),
}) })
return _findMessageInUpdate(client, res) return _findMessageInUpdate(client, res, false, !shouldDispatch)
} }

View file

@ -35,9 +35,15 @@ export async function editForumTopic(
* and use static color instead * and use static color instead
*/ */
icon?: tl.Long | null icon?: tl.Long | null
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { chatId, topicId, title, icon } = params const { chatId, topicId, title, icon, shouldDispatch } = params
const res = await client.call({ const res = await client.call({
_: 'channels.editForumTopic', _: 'channels.editForumTopic',
@ -47,5 +53,5 @@ export async function editForumTopic(
iconEmojiId: icon ? icon ?? Long.ZERO : undefined, iconEmojiId: icon ? icon ?? Long.ZERO : undefined,
}) })
return _findMessageInUpdate(client, res) return _findMessageInUpdate(client, res, false, shouldDispatch)
} }

View file

@ -23,9 +23,15 @@ export async function toggleForumTopicClosed(
/** Whether the topic should be closed */ /** Whether the topic should be closed */
closed: boolean closed: boolean
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { chatId, topicId, closed } = parmas const { chatId, topicId, closed, shouldDispatch } = parmas
const res = await client.call({ const res = await client.call({
_: 'channels.editForumTopic', _: 'channels.editForumTopic',
@ -34,5 +40,5 @@ export async function toggleForumTopicClosed(
closed, closed,
}) })
return _findMessageInUpdate(client, res) return _findMessageInUpdate(client, res, false, shouldDispatch)
} }

View file

@ -10,15 +10,24 @@ import { resolvePeer } from '../users/resolve-peer'
* *
* Only admins with `manageTopics` permission can do this. * Only admins with `manageTopics` permission can do this.
* *
* @param chatId Chat ID or username
* @param hidden Whether the topic should be hidden
* @returns Service message about the modification * @returns Service message about the modification
*/ */
export async function toggleGeneralTopicHidden( export async function toggleGeneralTopicHidden(
client: BaseTelegramClient, client: BaseTelegramClient,
chatId: InputPeerLike, params: {
hidden: boolean, /** Chat ID or username */
chatId: InputPeerLike
/** Whether the topic should be hidden */
hidden: boolean
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
},
): Promise<Message> { ): Promise<Message> {
const { chatId, hidden, shouldDispatch } = params
const res = await client.call({ const res = await client.call({
_: 'channels.editForumTopic', _: 'channels.editForumTopic',
channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId), channel: normalizeToInputChannel(await resolvePeer(client, chatId), chatId),
@ -26,5 +35,5 @@ export async function toggleGeneralTopicHidden(
hidden, hidden,
}) })
return _findMessageInUpdate(client, res) return _findMessageInUpdate(client, res, false, shouldDispatch)
} }

View file

@ -11,7 +11,16 @@ import { resolvePeer } from '../users/resolve-peer'
* Once closed, poll can't be re-opened, and nobody * Once closed, poll can't be re-opened, and nobody
* will be able to vote in it * will be able to vote in it
*/ */
export async function closePoll(client: BaseTelegramClient, params: InputMessageId): Promise<Poll> { export async function closePoll(
client: BaseTelegramClient,
params: InputMessageId & {
/**
* Whether to dispatch the edit message event
* to the client's update handler.
*/
shouldDispatch?: true
},
): Promise<Poll> {
const { chatId, message } = normalizeInputMessageId(params) const { chatId, message } = normalizeInputMessageId(params)
const res = await client.call({ const res = await client.call({
@ -32,7 +41,7 @@ export async function closePoll(client: BaseTelegramClient, params: InputMessage
assertIsUpdatesGroup('messages.editMessage', res) assertIsUpdatesGroup('messages.editMessage', res)
client.network.handleUpdate(res, true) client.network.handleUpdate(res, !params.shouldDispatch)
const upd = res.updates[0] const upd = res.updates[0]
assertTypeIs('messages.editMessage (@ .updates[0])', upd, 'updateMessagePoll') assertTypeIs('messages.editMessage (@ .updates[0])', upd, 'updateMessagePoll')

View file

@ -78,6 +78,12 @@ export async function editMessage(
* @param total Total file size in bytes * @param total Total file size in bytes
*/ */
progressCallback?: (uploaded: number, total: number) => void progressCallback?: (uploaded: number, total: number) => void
/**
* Whether to dispatch the edit message event
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { chatId, message } = normalizeInputMessageId(params) const { chatId, message } = normalizeInputMessageId(params)
@ -115,5 +121,5 @@ export async function editMessage(
media, media,
}) })
return _findMessageInUpdate(client, res, true) return _findMessageInUpdate(client, res, true, !params.shouldDispatch)
} }

View file

@ -5,10 +5,15 @@ import { PeersIndex } from '../../types/peers'
import { assertIsUpdatesGroup } from '../../utils/updates-utils' import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** @internal */ /** @internal */
export function _findMessageInUpdate(client: BaseTelegramClient, res: tl.TypeUpdates, isEdit = false): Message { export function _findMessageInUpdate(
client: BaseTelegramClient,
res: tl.TypeUpdates,
isEdit = false,
noDispatch = true,
): Message {
assertIsUpdatesGroup('_findMessageInUpdate', res) assertIsUpdatesGroup('_findMessageInUpdate', res)
client.network.handleUpdate(res, true) client.network.handleUpdate(res, noDispatch)
for (const u of res.updates) { for (const u of res.updates) {
if ( if (

View file

@ -89,6 +89,12 @@ export interface ForwardMessageOptions {
* Peer to use when sending the message. * Peer to use when sending the message.
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the forwarded messages
* to the client's update handler.
*/
shouldDispatch?: true
} }
/** /**
@ -139,7 +145,7 @@ export async function forwardMessagesById(
assertIsUpdatesGroup('messages.forwardMessages', res) assertIsUpdatesGroup('messages.forwardMessages', res)
client.network.handleUpdate(res, true) client.network.handleUpdate(res, !params.shouldDispatch)
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)

View file

@ -1,13 +1,16 @@
import { BaseTelegramClient } from '@mtcute/core' import { BaseTelegramClient, MtTypeAssertionError } from '@mtcute/core'
import { InputMessageId, normalizeInputMessageId } from '../../types' import { InputMessageId, Message, normalizeInputMessageId } from '../../types'
import { resolvePeer } from '../users/resolve-peer' import { resolvePeer } from '../users/resolve-peer'
import { _findMessageInUpdate } from './find-in-update'
/** /**
* Pin a message in a group, supergroup, channel or PM. * Pin a message in a group, supergroup, channel or PM.
* *
* For supergroups/channels, you must have appropriate permissions, * For supergroups/channels, you must have appropriate permissions,
* either as an admin, or as default permissions * either as an admin, or as default permissions
*
* @returns Service message about pinned message, if one was generated.
*/ */
export async function pinMessage( export async function pinMessage(
client: BaseTelegramClient, client: BaseTelegramClient,
@ -16,9 +19,15 @@ export async function pinMessage(
notify?: boolean notify?: boolean
/** Whether to pin for both sides (only for private chats) */ /** Whether to pin for both sides (only for private chats) */
bothSides?: boolean bothSides?: boolean
/**
* Whether to dispatch the returned service message (if any)
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<void> { ): Promise<Message | null> {
const { notify, bothSides } = params ?? {} const { notify, bothSides, shouldDispatch } = params ?? {}
const { chatId, message } = normalizeInputMessageId(params) const { chatId, message } = normalizeInputMessageId(params)
const res = await client.call({ const res = await client.call({
@ -29,5 +38,14 @@ export async function pinMessage(
pmOneside: !bothSides, pmOneside: !bothSides,
}) })
client.network.handleUpdate(res) try {
return _findMessageInUpdate(client, res, false, !shouldDispatch)
} catch (e) {
if (e instanceof MtTypeAssertionError && e.context === '_findInUpdate (@ .updates[*])') {
// no service message
return null
}
throw e
}
} }

View file

@ -193,7 +193,7 @@ export async function sendMediaGroup(
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined, sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
}) })
assertIsUpdatesGroup('_findMessageInUpdate', res) assertIsUpdatesGroup('sendMediaGroup', res)
client.network.handleUpdate(res, true) client.network.handleUpdate(res, true)
const peers = PeersIndex.from(res) const peers = PeersIndex.from(res)

View file

@ -131,6 +131,12 @@ export async function sendMedia(
* Peer to use when sending the message. * Peer to use when sending the message.
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the returned message
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
if (!params) params = {} if (!params) params = {}
@ -196,7 +202,7 @@ export async function sendMedia(
sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined, sendAs: params.sendAs ? await resolvePeer(client, params.sendAs) : undefined,
}) })
const msg = _findMessageInUpdate(client, res) const msg = _findMessageInUpdate(client, res, false, !params.shouldDispatch)
return msg return msg
} }

View file

@ -17,6 +17,12 @@ export async function sendReaction(
emoji?: InputReaction | null emoji?: InputReaction | null
/** Whether to use a big reaction */ /** Whether to use a big reaction */
big?: boolean big?: boolean
/**
* Whether to dispatch the returned edit message event
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
const { emoji, big } = params const { emoji, big } = params
@ -40,5 +46,5 @@ export async function sendReaction(
// idk why, they contain literally the same data // idk why, they contain literally the same data
// so we can just return the message from the first one // so we can just return the message from the first one
return _findMessageInUpdate(client, res, true) return _findMessageInUpdate(client, res, true, !params.shouldDispatch)
} }

View file

@ -115,6 +115,12 @@ export async function sendText(
* Peer to use when sending the message. * Peer to use when sending the message.
*/ */
sendAs?: InputPeerLike sendAs?: InputPeerLike
/**
* Whether to dispatch the returned message
* to the client's update handler.
*/
shouldDispatch?: true
}, },
): Promise<Message> { ): Promise<Message> {
if (!params) params = {} if (!params) params = {}
@ -238,7 +244,7 @@ export async function sendText(
return ret return ret
} }
const msg = _findMessageInUpdate(client, res) const msg = _findMessageInUpdate(client, res, false, !params.shouldDispatch)
return msg return msg
} }

View file

@ -21,7 +21,7 @@ export interface UpdatesManagerParams {
/** /**
* **ADVANCED** * **ADVANCED**
* *
* Whether to disable no-dispatch mechanism. * Whether to globally disable no-dispatch mechanism.
* *
* No-dispatch is a mechanism that allows you to call methods * No-dispatch is a mechanism that allows you to call methods
* that return updates and correctly handle them, without * that return updates and correctly handle them, without
@ -39,6 +39,9 @@ export interface UpdatesManagerParams {
* *
* Disabling it may also improve performance, but it's not guaranteed. * Disabling it may also improve performance, but it's not guaranteed.
* *
* > **Note**: you can disable this on per-request basis by passing
* > `shouldDispatch: true` to the method call that accepts it.
*
* @default false * @default false
*/ */
disableNoDispatch?: boolean disableNoDispatch?: boolean