diff --git a/TelegramCore/AccountStateManagementUtils.swift b/TelegramCore/AccountStateManagementUtils.swift index fee2cf2f08..91e10dafb8 100644 --- a/TelegramCore/AccountStateManagementUtils.swift +++ b/TelegramCore/AccountStateManagementUtils.swift @@ -1157,6 +1157,8 @@ private func resolveAssociatedMessages(account: Account, state: AccountMutableSt return (messages, chats, users) case let .channelMessages(_, _, _, messages, chats, users): return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) } } |> `catch` { _ in return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) diff --git a/TelegramCore/AccountViewTracker.swift b/TelegramCore/AccountViewTracker.swift index 5f0a7d15a2..8d39ebcf73 100644 --- a/TelegramCore/AccountViewTracker.swift +++ b/TelegramCore/AccountViewTracker.swift @@ -77,6 +77,10 @@ private func fetchWebpage(account: Account, messageId: MessageId) -> Signal Void in diff --git a/TelegramCore/ApiGroupOrChannel.swift b/TelegramCore/ApiGroupOrChannel.swift index 5f4c0abcd0..2bdb6db61a 100644 --- a/TelegramCore/ApiGroupOrChannel.swift +++ b/TelegramCore/ApiGroupOrChannel.swift @@ -108,7 +108,7 @@ func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? { case .chat, .chatEmpty, .chatForbidden, .channelForbidden: return parseTelegramGroupOrChannel(chat: rhs) case let .channel(flags, _, accessHash, title, username, photo, date, version, restrictionReason, adminRights, bannedRights, _, feedId): - if let _ = accessHash { + if accessHash != nil && (flags & (1 << 12)) == 0 { return parseTelegramGroupOrChannel(chat: rhs) } else if let lhs = lhs as? TelegramChannel { var channelFlags = lhs.flags @@ -128,7 +128,7 @@ func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? { } info = .group(TelegramChannelGroupInfo(flags: infoFlags)) } - return TelegramChannel(id: lhs.id, accessHash: lhs.accessHash, title: title, username: username, photo: imageRepresentationsForApiChatPhoto(photo), creationDate: lhs.creationDate, version: lhs.version, participationStatus: lhs.participationStatus, info: info, flags: channelFlags, restrictionInfo: lhs.restrictionInfo, adminRights: lhs.adminRights, bannedRights: lhs.bannedRights, peerGroupId: feedId.flatMap { PeerGroupId(rawValue: $0) }) + return TelegramChannel(id: lhs.id, accessHash: lhs.accessHash, title: title, username: username, photo: imageRepresentationsForApiChatPhoto(photo), creationDate: lhs.creationDate, version: lhs.version, participationStatus: lhs.participationStatus, info: info, flags: channelFlags, restrictionInfo: lhs.restrictionInfo, adminRights: lhs.adminRights, bannedRights: lhs.bannedRights, peerGroupId: lhs.peerGroupId) } else { return nil } diff --git a/TelegramCore/HistoryViewChannelStateValidation.swift b/TelegramCore/HistoryViewChannelStateValidation.swift index 8e5954a4fc..6fad7c9873 100644 --- a/TelegramCore/HistoryViewChannelStateValidation.swift +++ b/TelegramCore/HistoryViewChannelStateValidation.swift @@ -61,7 +61,7 @@ final class HistoryViewChannelStateValidationContexts { if ranges.isEmpty { ranges = [[id]] } else { - ranges[rangesToInvalidate.count - 1].append(id) + ranges[ranges.count - 1].append(id) } } @@ -122,6 +122,8 @@ final class HistoryViewChannelStateValidationContexts { var addedRanges: [[MessageId]] = [] for messages in rangesToInvalidate { for id in messages { + invalidatedMessageIds.insert(id) + if context.batchReferences[id] != nil { addRangeBreak(&addedRanges) } else { @@ -141,7 +143,7 @@ final class HistoryViewChannelStateValidationContexts { context.batchReferences[messageId] = batch } - disposable.set((validateBatch(postbox: self.postbox, network: self.network, messageIds: messages) + disposable.set((validateBatch(postbox: self.postbox, network: self.network, messageIds: messages, validatePts: invalidatedPts) |> deliverOn(self.queue)).start(completed: { [weak self, weak batch] in if let strongSelf = self, let context = strongSelf.contexts[id], let batch = batch { var completedMessageIds: [MessageId] = [] @@ -215,8 +217,10 @@ final class HistoryViewChannelStateValidationContexts { private func hashForMessages(_ messages: [Message]) -> Int32 { var acc: UInt32 = 0 - for message in messages { - acc = (acc &* 20261) &+ message.id.id + let sorted = messages.sorted(by: { $0.id > $1.id }) + + for message in sorted { + acc = (acc &* 20261) &+ UInt32(message.id.id) var timestamp = message.timestamp inner: for attribute in message.attributes { if let attribute = attribute as? EditedMessageAttribute { @@ -224,35 +228,169 @@ private func hashForMessages(_ messages: [Message]) -> Int32 { break inner } } - acc = (acc &* 20261) &+ timestamp + acc = (acc &* 20261) &+ UInt32(timestamp) } return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) } -private func validateBatch(postbox: Postbox, network: Network, messageIds: [MessageId]) -> Signal { +private func hashForMessages(_ messages: [StoreMessage]) -> Int32 { + var acc: UInt32 = 0 + + for message in messages { + if case let .Id(id) = message.id { + acc = (acc &* 20261) &+ UInt32(id.id) + var timestamp = message.timestamp + inner: for attribute in message.attributes { + if let attribute = attribute as? EditedMessageAttribute { + timestamp = attribute.date + break inner + } + } + acc = (acc &* 20261) &+ UInt32(timestamp) + } + } + return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) +} + +private func validateBatch(postbox: Postbox, network: Network, messageIds: [MessageId], validatePts: Int32) -> Signal { guard let peerId = messageIds.first?.peerId else { return .never() } return postbox.modify { modifier -> Signal in if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) { var messages: [Message] = [] + var previous: [MessageId: Message] = [:] for messageId in messageIds { if let message = modifier.getMessage(messageId) { messages.append(message) + previous[message.id] = message } } let hash = hashForMessages(messages) - return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: messageIds[messageIds.count - 1].id, offsetDate: 0, addOffset: 0, limit: 100, maxId: messageIds[messageIds.cout - 1].id, minId: messageIds[0].id, hash: hash)) + return network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: messageIds[messageIds.count - 1].id + 1, offsetDate: 0, addOffset: 0, limit: Int32(messageIds.count), maxId: messageIds[messageIds.count - 1].id + 1, minId: messageIds[0].id - 1, hash: hash)) + |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) } |> mapToSignal { result -> Signal in return postbox.modify { modifier -> Void in if let result = result { + let messages: [Api.Message] + let chats: [Api.Chat] + let users: [Api.User] + var channelPts: Int32? + switch result { + case let .messages(messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messagesSlice(_, messages: apiMessages, chats: apiChats, users: apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .channelMessages(_, pts, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + channelPts = pts case .messagesNotModified: - break - + for id in previous.keys { + modifier.updateMessage(id, update: { currentMessage in + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + /*if let channelPts = channelPts { + for i in 0 ..< attributes.count { + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + break + } + } + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + }*/ + for i in 0 ..< attributes.count { + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + break + } + } + attributes.append(ChannelMessageStateVersionAttribute(pts: validatePts)) + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + return + } + + var storeMessages: [StoreMessage] = [] + + for message in messages { + if let storeMessage = StoreMessage(apiMessage: message) { + if let channelPts = channelPts { + var attributes = storeMessage.attributes + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + storeMessages.append(storeMessage.withUpdatedAttributes(attributes)) + } else { + storeMessages.append(storeMessage) + } + } + } + + //let updatedHash = hashForMessages(storeMessages) + + var validMessageIds = Set() + for message in storeMessages { + if case let .Id(id) = message.id { + validMessageIds.insert(id) + + if let previousMessage = previous[id] { + var updatedTimestamp = message.timestamp + inner: for attribute in message.attributes { + if let attribute = attribute as? EditedMessageAttribute { + updatedTimestamp = attribute.date + break inner + } + } + + var timestamp = previousMessage.timestamp + inner: for attribute in previousMessage.attributes { + if let attribute = attribute as? EditedMessageAttribute { + timestamp = attribute.date + break inner + } + } + + modifier.updateMessage(id, update: { currentMessage in + if updatedTimestamp != timestamp { + return .update(message) + } else { + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature) + } + var attributes = currentMessage.attributes + if let channelPts = channelPts { + for i in 0 ..< attributes.count { + if let _ = attributes[i] as? ChannelMessageStateVersionAttribute { + attributes.remove(at: i) + break + } + } + attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) + } + return .update(StoreMessage(id: message.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: [.Failed], tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + } + }) + } + } + } + + for id in previous.keys { + if !validMessageIds.contains(id) { + modifier.deleteMessages([id]) + } } } } diff --git a/TelegramCore/Holes.swift b/TelegramCore/Holes.swift index baf08ffa7b..b5d7964171 100644 --- a/TelegramCore/Holes.swift +++ b/TelegramCore/Holes.swift @@ -183,6 +183,10 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos chats = apiChats users = apiUsers channelPts = pts + case .messagesNotModified: + messages = [] + chats = [] + users = [] } var updatedMaxIndex: MessageIndex? if let maxIndexResult = maxIndexResult { @@ -194,6 +198,8 @@ func fetchMessageHistoryHole(source: FetchMessageHistoryHoleSource, postbox: Pos maxIndexMessages = apiMessages case let .channelMessages(_, _, _, apiMessages, _, _): maxIndexMessages = apiMessages + case .messagesNotModified: + maxIndexMessages = [] } if !maxIndexMessages.isEmpty { assert(maxIndexMessages.count == 1) @@ -520,6 +526,10 @@ func fetchCallListHole(network: Network, postbox: Postbox, holeIndex: MessageInd messages = apiMessages chats = apiChats users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] } return postbox.modify { modifier -> Void in var storeMessages: [StoreMessage] = [] diff --git a/TelegramCore/LoadMessagesIfNecessary.swift b/TelegramCore/LoadMessagesIfNecessary.swift index fe5a872aea..68982f8ff3 100644 --- a/TelegramCore/LoadMessagesIfNecessary.swift +++ b/TelegramCore/LoadMessagesIfNecessary.swift @@ -60,12 +60,14 @@ public func getMessagesLoadIfNecessary(_ messageIds:[MessageId], postbox:Postbox 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, chats, users): - return (messages, chats, users) + case let .messages(messages, chats, users): + return (messages, chats, users) + case let .messagesSlice(_, messages, chats, users): + return (messages, chats, users) + case let .channelMessages(_, _, _, messages, chats, users): + return (messages, chats, users) + case .messagesNotModified: + return ([], [], []) } } |> `catch` { _ in return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) diff --git a/TelegramCore/LoadedPeerFromMessage.swift b/TelegramCore/LoadedPeerFromMessage.swift index b59e415e89..d38e3cf2d4 100644 --- a/TelegramCore/LoadedPeerFromMessage.swift +++ b/TelegramCore/LoadedPeerFromMessage.swift @@ -43,6 +43,8 @@ public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: M apiUsers = users case let .channelMessages(_, _, _, _, _, users): apiUsers = users + case .messagesNotModified: + apiUsers = [] } for user in apiUsers { diff --git a/TelegramCore/RequestUserPhotos.swift b/TelegramCore/RequestUserPhotos.swift index 4f94afeeb9..5792bf0722 100644 --- a/TelegramCore/RequestUserPhotos.swift +++ b/TelegramCore/RequestUserPhotos.swift @@ -75,18 +75,22 @@ public func requestPeerPhotos(account:Account, peerId:PeerId) -> Signal<[Telegra let chats: [Api.Chat] let users: [Api.User] switch result { - case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let .messages(apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case let.messagesSlice(_, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers + case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let .messages(apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case let.messagesSlice(_, apiMessages, apiChats, apiUsers): + messages = apiMessages + chats = apiChats + users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] } return account.postbox.modify { modifier -> [Message] in diff --git a/TelegramCore/SearchMessages.swift b/TelegramCore/SearchMessages.swift index 25f4732250..c26ce2d6e6 100644 --- a/TelegramCore/SearchMessages.swift +++ b/TelegramCore/SearchMessages.swift @@ -117,6 +117,10 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q messages = apiMessages chats = apiChats users = apiUsers + case .messagesNotModified: + messages = [] + chats = [] + users = [] } return account.postbox.modify { modifier -> [Message] in @@ -183,18 +187,22 @@ public func downloadMessage(account: Account, messageId: MessageId) -> Signal Message? in @@ -249,6 +257,8 @@ public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, timesta messages = apiMessages case let.messagesSlice(_, apiMessages, _, _): messages = apiMessages + case .messagesNotModified: + messages = [] } for message in messages { if let message = StoreMessage(apiMessage: message), case let .Id(id) = message.id { diff --git a/TelegramCore/SingleMessageView.swift b/TelegramCore/SingleMessageView.swift index af32738512..b3cea87cf5 100644 --- a/TelegramCore/SingleMessageView.swift +++ b/TelegramCore/SingleMessageView.swift @@ -64,6 +64,10 @@ private func fetchMessage(modifier: Modifier, account: Account, messageId: Messa apiMessages = messages apiChats = chats apiUsers = users + case .messagesNotModified: + apiMessages = [] + apiChats = [] + apiUsers = [] } var peers: [PeerId: Peer] = [:] diff --git a/TelegramCore/SynchronizePeerReadState.swift b/TelegramCore/SynchronizePeerReadState.swift index bf54f69765..1f858f1ff0 100644 --- a/TelegramCore/SynchronizePeerReadState.swift +++ b/TelegramCore/SynchronizePeerReadState.swift @@ -53,6 +53,8 @@ private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId apiMessages = messages case let .messagesSlice(_, messages, _, _): apiMessages = messages + case .messagesNotModified: + apiMessages = [] } if let message = apiMessages.first, let timestamp = message.timestamp { return .single((message.rawId, timestamp))