From ba0a07aefaad5fbff9dba7938be5e3334e06d42a Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 8 Nov 2022 13:38:56 +0400 Subject: [PATCH] Fetch reply messages with a dedicated method --- .../Account/AccountIntermediateState.swift | 71 ++++++++++---- .../ApiUtils/StoreMessage_Telegram.swift | 16 +++- .../State/AccountStateManagementUtils.swift | 93 ++++++++++++------- .../TelegramCore/Sources/State/Holes.swift | 52 +++++++++-- .../Sources/State/UpdatesApiUtils.swift | 2 +- .../Sources/Utils/MessageUtils.swift | 11 +++ 6 files changed, 185 insertions(+), 60 deletions(-) diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 950622bcb8..137d236ee8 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -143,6 +143,38 @@ enum StateResetForumTopics { case error(PeerId) } +struct ReferencedReplyMessageIds { + var targetIdsBySourceId: [MessageId: MessageId] = [:] + + var isEmpty: Bool { + return self.targetIdsBySourceId.isEmpty + } + + mutating func add(sourceId: MessageId, targetId: MessageId) { + if self.targetIdsBySourceId[targetId] == nil { + self.targetIdsBySourceId[targetId] = sourceId + } + } + + mutating func formUnion(_ other: ReferencedReplyMessageIds) { + for (targetId, sourceId) in other.targetIdsBySourceId { + if self.targetIdsBySourceId[targetId] == nil { + self.targetIdsBySourceId[targetId] = sourceId + } + } + } + + func subtractingStoredIds(_ ids: Set) -> ReferencedReplyMessageIds { + var result = ReferencedReplyMessageIds() + for (targetId, sourceId) in self.targetIdsBySourceId { + if !ids.contains(targetId) { + result.add(sourceId: sourceId, targetId: targetId) + } + } + return result + } +} + struct AccountMutableState { let initialState: AccountInitialState let branchOperationIndex: Int @@ -153,7 +185,8 @@ struct AccountMutableState { var peers: [PeerId: Peer] var channelStates: [PeerId: AccountStateChannelState] var peerChatInfos: [PeerId: PeerChatInfo] - var referencedMessageIds: Set + var referencedReplyMessageIds: ReferencedReplyMessageIds + var referencedGeneralMessageIds: Set var storedMessages: Set var readInboxMaxIds: [PeerId: MessageId] var namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]] @@ -176,11 +209,12 @@ struct AccountMutableState { var authorizationListUpdated: Bool = false - init(initialState: AccountInitialState, initialPeers: [PeerId: Peer], initialReferencedMessageIds: Set, initialStoredMessages: Set, initialReadInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set]) { + init(initialState: AccountInitialState, initialPeers: [PeerId: Peer], initialReferencedReplyMessageIds: ReferencedReplyMessageIds, initialReferencedGeneralMessageIds: Set, initialStoredMessages: Set, initialReadInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set]) { self.initialState = initialState self.state = initialState.state self.peers = initialPeers - self.referencedMessageIds = initialReferencedMessageIds + self.referencedReplyMessageIds = initialReferencedReplyMessageIds + self.referencedGeneralMessageIds = initialReferencedGeneralMessageIds self.storedMessages = initialStoredMessages self.readInboxMaxIds = initialReadInboxMaxIds self.channelStates = initialState.channelStates @@ -191,13 +225,14 @@ struct AccountMutableState { self.updatedOutgoingUniqueMessageIds = [:] } - init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedMessageIds: Set, storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], dismissBotWebViews: [Int64], branchOperationIndex: Int) { + init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedReplyMessageIds: ReferencedReplyMessageIds, referencedGeneralMessageIds: Set, storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], dismissBotWebViews: [Int64], branchOperationIndex: Int) { self.initialState = initialState self.operations = operations self.state = state self.peers = peers self.channelStates = channelStates - self.referencedMessageIds = referencedMessageIds + self.referencedReplyMessageIds = referencedReplyMessageIds + self.referencedGeneralMessageIds = referencedGeneralMessageIds self.storedMessages = storedMessages self.peerChatInfos = peerChatInfos self.readInboxMaxIds = readInboxMaxIds @@ -210,11 +245,13 @@ struct AccountMutableState { } func branch() -> AccountMutableState { - return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, channelStates: self.channelStates, peerChatInfos: self.peerChatInfos, referencedMessageIds: self.referencedMessageIds, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, updatedOutgoingUniqueMessageIds: self.updatedOutgoingUniqueMessageIds, displayAlerts: self.displayAlerts, dismissBotWebViews: self.dismissBotWebViews, branchOperationIndex: self.operations.count) + return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, channelStates: self.channelStates, peerChatInfos: self.peerChatInfos, referencedReplyMessageIds: self.referencedReplyMessageIds, referencedGeneralMessageIds: self.referencedGeneralMessageIds, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, updatedOutgoingUniqueMessageIds: self.updatedOutgoingUniqueMessageIds, displayAlerts: self.displayAlerts, dismissBotWebViews: self.dismissBotWebViews, branchOperationIndex: self.operations.count) } mutating func merge(_ other: AccountMutableState) { - self.referencedMessageIds.formUnion(other.referencedMessageIds) + self.referencedReplyMessageIds.formUnion(other.referencedReplyMessageIds) + self.referencedGeneralMessageIds.formUnion(other.referencedGeneralMessageIds) + for i in other.branchOperationIndex ..< other.operations.count { self.addOperation(other.operations[i]) } @@ -567,11 +604,11 @@ struct AccountMutableState { } } } - } - inner: for attribute in message.attributes { - if let attribute = attribute as? ReplyMessageAttribute { - self.referencedMessageIds.insert(attribute.messageId) - break inner + inner: for attribute in message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + self.referencedReplyMessageIds.add(sourceId: id, targetId: attribute.messageId) + break inner + } } } } @@ -579,11 +616,11 @@ struct AccountMutableState { for message in messages { if case let .Id(id) = message.id { self.storedMessages.insert(id) - } - inner: for attribute in message.attributes { - if let attribute = attribute as? ReplyMessageAttribute { - self.referencedMessageIds.insert(attribute.messageId) - break inner + inner: for attribute in message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + self.referencedReplyMessageIds.add(sourceId: id, targetId: attribute.messageId) + break inner + } } } } diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 4385ed3812..2d5f32b142 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -236,24 +236,30 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { } } -func apiMessageAssociatedMessageIds(_ message: Api.Message) -> [MessageId]? { +func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? { switch message { - case let .message(_, _, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .message(_, id, _, chatPeerId, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _): if let replyTo = replyTo { let peerId: PeerId = chatPeerId.peerId switch replyTo { case let .messageReplyHeader(_, replyToMsgId, replyToPeerId, _): - return [MessageId(peerId: replyToPeerId?.peerId ?? peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId)] + let targetId = MessageId(peerId: replyToPeerId?.peerId ?? peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId) + var replyIds = ReferencedReplyMessageIds() + replyIds.add(sourceId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id), targetId: targetId) + return (replyIds, []) } } case .messageEmpty: break - case let .messageService(_, _, _, chatPeerId, replyHeader, _, _, _): + case let .messageService(_, id, _, chatPeerId, replyHeader, _, _, _): if let replyHeader = replyHeader { switch replyHeader { case let .messageReplyHeader(_, replyToMsgId, replyToPeerId, _): - return [MessageId(peerId: replyToPeerId?.peerId ?? chatPeerId.peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId)] + let targetId = MessageId(peerId: replyToPeerId?.peerId ?? chatPeerId.peerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId) + var replyIds = ReferencedReplyMessageIds() + replyIds.add(sourceId: MessageId(peerId: chatPeerId.peerId, namespace: Namespaces.Message.Cloud, id: id), targetId: targetId) + return (replyIds, []) } } } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index b83d450fd5..41ed72fd10 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -88,20 +88,20 @@ private func activeChannelsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set Set { - var messageIds = Set() +private func associatedMessageIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> (replyIds: ReferencedReplyMessageIds, generalIds: Set) { + var replyIds = ReferencedReplyMessageIds() + var generalIds = Set() for group in groups { for update in group.updates { if let associatedMessageIds = update.associatedMessageIds { - for messageId in associatedMessageIds { - messageIds.insert(messageId) - } + replyIds.formUnion(associatedMessageIds.replyIds) + generalIds.formUnion(associatedMessageIds.generalIds) } } } - return messageIds + return (replyIds, generalIds) } private func peerIdsRequiringLocalChatStateFromUpdates(_ updates: [Api.Update]) -> Set { @@ -282,23 +282,22 @@ private func activeChannelsFromDifference(_ difference: Api.updates.Difference) return peerIds } -private func associatedMessageIdsFromDifference(_ difference: Api.updates.Difference) -> Set { - var messageIds = Set() +private func associatedMessageIdsFromDifference(_ difference: Api.updates.Difference) -> (replyIds: ReferencedReplyMessageIds, generalIds: Set) { + var replyIds = ReferencedReplyMessageIds() + var generalIds = Set() switch difference { case let .difference(newMessages, _, otherUpdates, _, _, _): for message in newMessages { if let associatedMessageIds = apiMessageAssociatedMessageIds(message) { - for messageId in associatedMessageIds { - messageIds.insert(messageId) - } + replyIds.formUnion(associatedMessageIds.replyIds) + generalIds.formUnion(associatedMessageIds.generalIds) } } for update in otherUpdates { if let associatedMessageIds = update.associatedMessageIds { - for messageId in associatedMessageIds { - messageIds.insert(messageId) - } + replyIds.formUnion(associatedMessageIds.replyIds) + generalIds.formUnion(associatedMessageIds.generalIds) } } case .differenceEmpty: @@ -306,24 +305,22 @@ private func associatedMessageIdsFromDifference(_ difference: Api.updates.Differ case let .differenceSlice(newMessages, _, otherUpdates, _, _, _): for message in newMessages { if let associatedMessageIds = apiMessageAssociatedMessageIds(message) { - for messageId in associatedMessageIds { - messageIds.insert(messageId) - } + replyIds.formUnion(associatedMessageIds.replyIds) + generalIds.formUnion(associatedMessageIds.generalIds) } } for update in otherUpdates { if let associatedMessageIds = update.associatedMessageIds { - for messageId in associatedMessageIds { - messageIds.insert(messageId) - } + replyIds.formUnion(associatedMessageIds.replyIds) + generalIds.formUnion(associatedMessageIds.generalIds) } } case .differenceTooLong: break } - return messageIds + return (replyIds, generalIds) } private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.updates.Difference) -> Set { @@ -424,7 +421,7 @@ private func locallyGeneratedMessageTimestampsFromDifference(_ difference: Api.u return messageTimestamps } -private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set, activeChannelIds: Set, associatedMessageIds: Set, peerIdsRequiringLocalChatState: Set, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> AccountMutableState { +private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set, activeChannelIds: Set, referencedReplyMessageIds: ReferencedReplyMessageIds, referencedGeneralMessageIds: Set, peerIdsRequiringLocalChatState: Set, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> AccountMutableState { var peers: [PeerId: Peer] = [:] var channelStates: [PeerId: AccountStateChannelState] = [:] @@ -454,7 +451,8 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set] = [:] if !locallyGeneratedMessageTimestamps.isEmpty { for (peerId, namespacesAndTimestamps) in locallyGeneratedMessageTimestamps { @@ -517,7 +515,7 @@ private func initialStateWithPeerIds(_ transaction: Transaction, peerIds: Set Si let associatedMessageIds = associatedMessageIdsFromUpdateGroups(groups) let peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatStateFromUpdateGroups(groups) - return initialStateWithPeerIds(transaction, peerIds: peerIds, activeChannelIds: activeChannelIds, associatedMessageIds: associatedMessageIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestampsFromUpdateGroups(groups)) + return initialStateWithPeerIds(transaction, peerIds: peerIds, activeChannelIds: activeChannelIds, referencedReplyMessageIds: associatedMessageIds.replyIds, referencedGeneralMessageIds: associatedMessageIds.generalIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestampsFromUpdateGroups(groups)) } } @@ -538,7 +536,7 @@ func initialStateWithDifference(postbox: Postbox, difference: Api.updates.Differ let activeChannelIds = activeChannelsFromDifference(difference) let associatedMessageIds = associatedMessageIdsFromDifference(difference) let peerIdsRequiringLocalChatState = peerIdsRequiringLocalChatStateFromDifference(difference) - return initialStateWithPeerIds(transaction, peerIds: peerIds, activeChannelIds: activeChannelIds, associatedMessageIds: associatedMessageIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestampsFromDifference(difference)) + return initialStateWithPeerIds(transaction, peerIds: peerIds, activeChannelIds: activeChannelIds, referencedReplyMessageIds: associatedMessageIds.replyIds, referencedGeneralMessageIds: associatedMessageIds.generalIds, peerIdsRequiringLocalChatState: peerIdsRequiringLocalChatState, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestampsFromDifference(difference)) } } @@ -2058,8 +2056,10 @@ private func reactionsFromState(_ state: AccountMutableState) -> [MessageReactio } private func resolveAssociatedMessages(postbox: Postbox, network: Network, state: AccountMutableState) -> Signal { - let missingMessageIds = state.referencedMessageIds.subtracting(state.storedMessages) - if missingMessageIds.isEmpty { + let missingReplyMessageIds = state.referencedReplyMessageIds.subtractingStoredIds(state.storedMessages) + let missingGeneralMessageIds = state.referencedGeneralMessageIds.subtracting(state.storedMessages) + + if missingReplyMessageIds.isEmpty && missingGeneralMessageIds.isEmpty { return resolveUnknownEmojiFiles(postbox: postbox, source: .network(network), messages: messagesFromOperations(state: state), reactions: reactionsFromState(state), result: state) |> mapToSignal { state in return resolveForumThreads(postbox: postbox, network: network, state: state) @@ -2069,7 +2069,38 @@ private func resolveAssociatedMessages(postbox: Postbox, network: Network, state let _ = missingPeers var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] - for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingMessageIds) { + for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingReplyMessageIds) { + if let peer = state.peers[peerId] { + var signal: Signal? + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + signal = network.request(Api.functions.messages.getMessages(id: messageIds.targetIdsBySourceId.values.map({ Api.InputMessage.inputMessageReplyTo(id: $0.id) }))) + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + signal = network.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.targetIdsBySourceId.values.map({ Api.InputMessage.inputMessageReplyTo(id: $0.id) }))) + } + } + if let signal = signal { + signals.append(signal |> map { result in + switch result { + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, _, _, _, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users): + let _ = apiTopics + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) + } + } |> `catch` { _ in + return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + }) + } + } else { + missingPeers = true + } + } + for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingGeneralMessageIds) { if let peer = state.peers[peerId] { var signal: Signal? if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { @@ -2290,7 +2321,7 @@ func pollChannelOnce(accountPeerId: PeerId, postbox: Postbox, network: Network, peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings) } } - let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) + let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedReplyMessageIds: ReferencedReplyMessageIds(), initialReferencedGeneralMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) return pollChannel(accountPeerId: accountPeerId, postbox: postbox, network: network, peer: peer, state: initialState) |> mapToSignal { (finalState, _, timeout) -> Signal in return resolveAssociatedMessages(postbox: postbox, network: network, state: finalState) @@ -2344,7 +2375,7 @@ public func standalonePollChannelOnce(accountPeerId: PeerId, postbox: Postbox, n peerChatInfos[peerId] = PeerChatInfo(notificationSettings: notificationSettings) } } - let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) + let initialState = AccountMutableState(initialState: AccountInitialState(state: accountState, peerIds: Set(), peerIdsRequiringLocalChatState: Set(), channelStates: channelStates, peerChatInfos: peerChatInfos, locallyGeneratedMessageTimestamps: [:], cloudReadStates: [:], channelsToPollExplicitely: Set()), initialPeers: initialPeers, initialReferencedReplyMessageIds: ReferencedReplyMessageIds(), initialReferencedGeneralMessageIds: Set(), initialStoredMessages: Set(), initialReadInboxMaxIds: [:], storedMessagesByPeerIdAndTimestamp: [:]) return pollChannel(accountPeerId: accountPeerId, postbox: postbox, network: network, peer: peer, state: initialState) |> mapToSignal { (finalState, _, timeout) -> Signal in return resolveAssociatedMessages(postbox: postbox, network: network, state: finalState) diff --git a/submodules/TelegramCore/Sources/State/Holes.swift b/submodules/TelegramCore/Sources/State/Holes.swift index dcbab5ae5b..1b38507b70 100644 --- a/submodules/TelegramCore/Sources/State/Holes.swift +++ b/submodules/TelegramCore/Sources/State/Holes.swift @@ -103,20 +103,29 @@ func resolveUnknownEmojiFiles(postbox: Postbox, source: FetchMessageHistoryHo private func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMessageHistoryHoleSource, peers: [PeerId: Peer], storeMessages: [StoreMessage], _ f: @escaping (Transaction, [Peer], [StoreMessage]) -> T) -> Signal { return postbox.transaction { transaction -> Signal in var storedIds = Set() - var referencedIds = Set() + var referencedReplyIds = ReferencedReplyMessageIds() + var referencedGeneralIds = Set() for message in storeMessages { guard case let .Id(id) = message.id else { continue } storedIds.insert(id) for attribute in message.attributes { - referencedIds.formUnion(attribute.associatedMessageIds) + if let attribute = attribute as? ReplyMessageAttribute { + referencedReplyIds.add(sourceId: id, targetId: attribute.messageId) + } else { + referencedGeneralIds.formUnion(attribute.associatedMessageIds) + } } } - referencedIds.subtract(storedIds) - referencedIds.subtract(transaction.filterStoredMessageIds(referencedIds)) - if referencedIds.isEmpty { + let allPossiblyStoredReferencedIds = storedIds.union(referencedGeneralIds).union(referencedReplyIds.targetIdsBySourceId.keys) + let allStoredReferencedIds = transaction.filterStoredMessageIds(allPossiblyStoredReferencedIds) + + referencedReplyIds = referencedReplyIds.subtractingStoredIds(allStoredReferencedIds) + referencedGeneralIds.subtract(allStoredReferencedIds) + + if referencedReplyIds.isEmpty && referencedGeneralIds.isEmpty { return resolveUnknownEmojiFiles(postbox: postbox, source: source, messages: storeMessages, reactions: [], result: Void()) |> mapToSignal { _ -> Signal in return postbox.transaction { transaction -> T in @@ -125,7 +134,38 @@ private func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMe } } else { var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] - for (peerId, messageIds) in messagesIdsGroupedByPeerId(referencedIds) { + for (peerId, messageIds) in messagesIdsGroupedByPeerId(referencedReplyIds) { + if let peer = transaction.getPeer(peerId) ?? peers[peerId] { + var signal: Signal? + if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { + signal = source.request(Api.functions.messages.getMessages(id: messageIds.targetIdsBySourceId.values.map({ Api.InputMessage.inputMessageReplyTo(id: $0.id) }))) + } else if peerId.namespace == Namespaces.Peer.CloudChannel { + if let inputChannel = apiInputChannel(peer) { + signal = source.request(Api.functions.channels.getMessages(channel: inputChannel, id: messageIds.targetIdsBySourceId.values.map({ Api.InputMessage.inputMessageReplyTo(id: $0.id) }))) + } + } + if let signal = signal { + signals.append(signal + |> map { result in + switch result { + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, _, _, _, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users): + let _ = apiTopics + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) + } + } + |> `catch` { _ in + return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + }) + } + } + } + for (peerId, messageIds) in messagesIdsGroupedByPeerId(referencedGeneralIds) { if let peer = transaction.getPeer(peerId) ?? peers[peerId] { var signal: Signal? if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { diff --git a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift index 2c00487e9a..f5f4064547 100644 --- a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift +++ b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift @@ -305,7 +305,7 @@ extension Api.Update { } } - var associatedMessageIds: [MessageId]? { + var associatedMessageIds: (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? { switch self { case let .updateNewMessage(message, _, _): return apiMessageAssociatedMessageIds(message) diff --git a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift index c64078714a..e18032c41f 100644 --- a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift @@ -156,6 +156,17 @@ func messagesIdsGroupedByPeerId(_ ids: [MessageId]) -> [PeerId: [MessageId]] { return dict } +func messagesIdsGroupedByPeerId(_ ids: ReferencedReplyMessageIds) -> [PeerId: ReferencedReplyMessageIds] { + var dict: [PeerId: ReferencedReplyMessageIds] = [:] + + for (targetId, sourceId) in ids.targetIdsBySourceId { + let peerId = sourceId.peerId + dict[peerId, default: ReferencedReplyMessageIds()].add(sourceId: sourceId, targetId: targetId) + } + + return dict +} + func locallyRenderedMessage(message: StoreMessage, peers: [PeerId: Peer]) -> Message? { guard case let .Id(id) = message.id else { return nil