From e97ec38930d111c5d44a8b9704c3a5a77f6f204c Mon Sep 17 00:00:00 2001 From: zubiden <19638254+zubiden@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:20:28 +0100 Subject: [PATCH] Support `reportMessageDelivery` (#5440) --- src/api/gramjs/apiBuilders/messages.ts | 1 + src/api/gramjs/methods/messages.ts | 12 +++++++++++ src/api/types/messages.ts | 1 + src/global/actions/api/messages.ts | 25 ++++++++++++++++++++++ src/global/actions/apiUpdaters/messages.ts | 5 +++++ src/global/types/actions.ts | 5 +++++ src/lib/gramjs/tl/apiTl.js | 5 +++-- src/lib/gramjs/tl/static/api.json | 1 + 8 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/api/gramjs/apiBuilders/messages.ts b/src/api/gramjs/apiBuilders/messages.ts index 966fd0c4b..4dfea457e 100644 --- a/src/api/gramjs/apiBuilders/messages.ts +++ b/src/api/gramjs/apiBuilders/messages.ts @@ -267,6 +267,7 @@ export function buildApiMessageWithChatId( effectId: mtpMessage.effect?.toString(), isInvertedMedia, isVideoProcessingPending, + reportDeliveryUntilDate: mtpMessage.reportDeliveryUntilDate, }); } diff --git a/src/api/gramjs/methods/messages.ts b/src/api/gramjs/methods/messages.ts index 42a934558..b64c0f731 100644 --- a/src/api/gramjs/methods/messages.ts +++ b/src/api/gramjs/methods/messages.ts @@ -1121,6 +1121,18 @@ export function fetchPaidReactionPrivacy() { return invokeRequest(new GramJs.messages.GetPaidReactionPrivacy(), { shouldReturnTrue: true }); } +export function reportMessagesDelivery({ + chat, messageIds, +}: { + chat: ApiChat; + messageIds: number[]; +}) { + return invokeRequest(new GramJs.messages.ReportMessagesDelivery({ + peer: buildInputPeer(chat.id, chat.accessHash), + id: messageIds, + })); +} + export async function fetchDiscussionMessage({ chat, messageId, }: { diff --git a/src/api/types/messages.ts b/src/api/types/messages.ts index 540031573..826aeccf3 100644 --- a/src/api/types/messages.ts +++ b/src/api/types/messages.ts @@ -773,6 +773,7 @@ export interface ApiMessage { isInvertedMedia?: true; isVideoProcessingPending?: true; areReactionsPossible?: true; + reportDeliveryUntilDate?: number; } export interface ApiReactions { diff --git a/src/global/actions/api/messages.ts b/src/global/actions/api/messages.ts index 7f81c91f1..8b96690ed 100644 --- a/src/global/actions/api/messages.ts +++ b/src/global/actions/api/messages.ts @@ -2284,6 +2284,31 @@ addActionHandler('copyMessageLink', async (global, actions, payload): Promise(); +let reportDeliveryTimeout: number | undefined; +addActionHandler('reportMessageDelivery', (global, actions, payload): ActionReturnType => { + const { chatId, messageId } = payload; + const currentIds = MESSAGES_TO_REPORT_DELIVERY.get(chatId) || []; + currentIds.push(messageId); + MESSAGES_TO_REPORT_DELIVERY.set(chatId, currentIds); + + if (!reportDeliveryTimeout) { + // Slightly unsafe in the multitab environment, but there is no better way to do it now. + // Not critical if user manages to close the tab in a show window before the report is sent. + reportDeliveryTimeout = window.setTimeout(() => { + reportDeliveryTimeout = undefined; + + MESSAGES_TO_REPORT_DELIVERY.forEach((messageIds, cId) => { + const chat = selectChat(global, cId); + if (!chat) return; + + callApi('reportMessagesDelivery', { chat, messageIds }); + }); + MESSAGES_TO_REPORT_DELIVERY.clear(); + }, 500); + } +}); + function countSortedIds(ids: number[], from: number, to: number) { // If ids are outside viewport, we cannot get correct count if (ids.length === 0 || from < ids[0] || to > ids[ids.length - 1]) return undefined; diff --git a/src/global/actions/apiUpdaters/messages.ts b/src/global/actions/apiUpdaters/messages.ts index 88c9a3a6f..ee5730409 100644 --- a/src/global/actions/apiUpdaters/messages.ts +++ b/src/global/actions/apiUpdaters/messages.ts @@ -18,6 +18,7 @@ import { import { getMessageKey, isLocalMessageId } from '../../../util/keys/messageKey'; import { notifyAboutMessage } from '../../../util/notifications'; import { onTickEnd } from '../../../util/schedulers'; +import { getServerTime } from '../../../util/serverTime'; import { addPaidReaction, checkIfHasUnreadReactions, getIsSavedDialog, getMessageContent, getMessageText, isActionMessage, @@ -163,6 +164,10 @@ addActionHandler('apiUpdate', (global, actions, update): ActionReturnType => { global = updatePoll(global, poll.id, poll); } + if (message.reportDeliveryUntilDate && message.reportDeliveryUntilDate > getServerTime()) { + actions.reportMessageDelivery({ chatId, messageId: id }); + } + setGlobal(global); // Reload dialogs if chat is not present in the list diff --git a/src/global/types/actions.ts b/src/global/types/actions.ts index a3540856b..86d26c27c 100644 --- a/src/global/types/actions.ts +++ b/src/global/types/actions.ts @@ -2443,6 +2443,11 @@ export interface ActionPayloads { botId: string; isAccessGranted: boolean; }; + + reportMessageDelivery: { + chatId: string; + messageId: number; + }; } export interface RequiredActionPayloads { diff --git a/src/lib/gramjs/tl/apiTl.js b/src/lib/gramjs/tl/apiTl.js index 8b8b4b36a..d20f52491 100644 --- a/src/lib/gramjs/tl/apiTl.js +++ b/src/lib/gramjs/tl/apiTl.js @@ -1616,6 +1616,7 @@ messages.viewSponsoredMessage#673ad8f1 peer:InputPeer random_id:bytes = Bool; messages.clickSponsoredMessage#f093465 flags:# media:flags.0?true fullscreen:flags.1?true peer:InputPeer random_id:bytes = Bool; messages.reportSponsoredMessage#1af3dbb8 peer:InputPeer random_id:bytes option:bytes = channels.SponsoredMessageReportResult; messages.getSponsoredMessages#9bd2f439 peer:InputPeer = messages.SponsoredMessages; +messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; @@ -1685,8 +1686,8 @@ bots.allowSendMessage#f132e3ef bot:InputUser = Updates; bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; +bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; @@ -1777,4 +1778,4 @@ premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset: premium.getMyBoosts#be77b4a = premium.MyBoosts; premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;`; +fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;`; \ No newline at end of file diff --git a/src/lib/gramjs/tl/static/api.json b/src/lib/gramjs/tl/static/api.json index f5d0d346d..d0b080c0a 100644 --- a/src/lib/gramjs/tl/static/api.json +++ b/src/lib/gramjs/tl/static/api.json @@ -217,6 +217,7 @@ "messages.clickSponsoredMessage", "messages.reportSponsoredMessage", "messages.getSponsoredMessages", + "messages.reportMessagesDelivery", "updates.getState", "updates.getDifference", "updates.getChannelDifference",