From d93a30380ea4a116b338d8096412256ffc5012eb Mon Sep 17 00:00:00 2001 From: Peter Iakovlev Date: Fri, 12 Jan 2018 15:32:00 +0400 Subject: [PATCH] no message --- .../xcschemes/xcschememanagement.plist | 4 +- .../HistoryViewChannelStateValidation.swift | 241 ++++++++---------- 2 files changed, 104 insertions(+), 141 deletions(-) diff --git a/TelegramCore.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist b/TelegramCore.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist index 0b14839407..7678cfa759 100644 --- a/TelegramCore.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/TelegramCore.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,12 +7,12 @@ TelegramCore.xcscheme orderHint - 4 + 0 TelegramCoreMac.xcscheme orderHint - 6 + 2 SuppressBuildableAutocreation diff --git a/TelegramCore/HistoryViewChannelStateValidation.swift b/TelegramCore/HistoryViewChannelStateValidation.swift index a844d2505e..93bd960078 100644 --- a/TelegramCore/HistoryViewChannelStateValidation.swift +++ b/TelegramCore/HistoryViewChannelStateValidation.swift @@ -44,7 +44,7 @@ final class HistoryViewChannelStateValidationContexts { func updateView(id: Int32, view: MessageHistoryView?) { assert(self.queue.isCurrent()) - if let view = view { + if let view = view, view.tagMask == nil { var channelState: ChannelState? for entry in view.additionalData { if case let .peerChatState(_, chatState) = entry { @@ -56,8 +56,20 @@ final class HistoryViewChannelStateValidationContexts { } if let invalidatedPts = channelState?.invalidatedPts { - var invalidatedMessageIds: [MessageId] = [] - var minValidatedPts: Int32? + var rangesToInvalidate: [[MessageId]] = [] + let addToRange: (MessageId, inout [[MessageId]]) -> Void = { id, ranges in + if ranges.isEmpty { + ranges = [[id]] + } else { + ranges[rangesToInvalidate.count - 1].append(id) + } + } + + let addRangeBreak: (inout [[MessageId]]) -> Void = { ranges in + if ranges.last?.count != 0 { + ranges.append([]) + } + } for entry in view.entries { switch entry { @@ -70,23 +82,35 @@ final class HistoryViewChannelStateValidationContexts { break inner } } + var requiresValidation = false if let messagePts = messagePts { if messagePts < invalidatedPts { - if minValidatedPts == nil || minValidatedPts! > messagePts { - minValidatedPts = messagePts - } - invalidatedMessageIds.append(message.id) + requiresValidation = true } } else { - invalidatedMessageIds.append(message.id) + requiresValidation = true + } + + if requiresValidation { + addToRange(message.id, &rangesToInvalidate) + } else { + addRangeBreak(&rangesToInvalidate) } } - default: - break + case let .HoleEntry(hole, _): + if hole.maxIndex.id.namespace == Namespaces.Message.Cloud { + addRangeBreak(&rangesToInvalidate) + } } } - if !invalidatedMessageIds.isEmpty { + if !rangesToInvalidate.isEmpty && rangesToInvalidate[rangesToInvalidate.count - 1].isEmpty { + rangesToInvalidate.removeLast() + } + + var invalidatedMessageIds = Set() + + if !rangesToInvalidate.isEmpty { let context: ChannelStateValidationContext if let current = self.contexts[id] { context = current @@ -94,7 +118,46 @@ final class HistoryViewChannelStateValidationContexts { context = ChannelStateValidationContext() self.contexts[id] = context } - var messageIdsForBatch: [MessageId] = [] + + var addedRanges: [[MessageId]] = [] + for messages in rangesToInvalidate { + for id in messages { + if context.batchReferences[id] != nil { + addRangeBreak(&addedRanges) + } else { + addToRange(id, &addedRanges) + } + } + } + + if !addedRanges.isEmpty && addedRanges[rangesToInvalidate.count - 1].isEmpty { + addedRanges.removeLast() + } + + for messages in addedRanges { + let disposable = MetaDisposable() + let batch = ChannelStateValidationBatch(disposable: disposable, invalidatedPts: invalidatedPts) + for messageId in messages { + context.batchReferences[messageId] = batch + } + + disposable.set((validateBatch(postbox: self.postbox, network: self.network, messageIds: messages) + |> 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] = [] + for (messageId, messageBatch) in context.batchReferences { + if messageBatch === batch { + completedMessageIds.append(messageId) + } + } + for messageId in completedMessageIds { + context.batchReferences.removeValue(forKey: messageId) + } + } + })) + } + + /*var messageIdsForBatch: [MessageId] = [] for messageId in invalidatedMessageIds { if let batch = context.batchReferences[messageId] { if batch.invalidatedPts < invalidatedPts { @@ -126,15 +189,14 @@ final class HistoryViewChannelStateValidationContexts { } } })) - } + }*/ } if let context = self.contexts[id] { - let messageIds = Set(invalidatedMessageIds) var removeIds: [MessageId] = [] for batchMessageId in context.batchReferences.keys { - if !messageIds.contains(batchMessageId) { + if !invalidatedMessageIds.contains(batchMessageId) { removeIds.append(batchMessageId) } } @@ -150,136 +212,37 @@ final class HistoryViewChannelStateValidationContexts { } } -private func validateBatch(postbox: Postbox, network: Network, messageIds: [MessageId], minValidatedPts: Int32?) -> Signal { +private func hashForMessages(_ messages: [Message]) -> Int32 { + var acc: UInt32 = 0 + + for message in messages { + acc = (acc &* 20261) &+ message.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) &+ timestamp + } + return Int32(bitPattern: acc & UInt32(0x7FFFFFFF)) +} + +private func validateBatch(postbox: Postbox, network: Network, messageIds: [MessageId]) -> Signal { guard let peerId = messageIds.first?.peerId else { return .never() } return postbox.modify { modifier -> Signal in - if let peer = modifier.getPeer(peerId), let inputChannel = apiInputChannel(peer) { - var ranges: [Api.MessageRange] = [] - var currentRange: (Int32, Int32)? - for id in messageIds.sorted() { - if let (minId, maxId) = currentRange { - if maxId == id.id - 1 { - currentRange = (minId, id.id) - } else { - ranges.append(Api.MessageRange.messageRange(minId: minId - 1, maxId: maxId + 1)) - currentRange = (id.id, id.id) - } - } else { - currentRange = (id.id, id.id) + if let peer = modifier.getPeer(peerId), let inputPeer = apiInputPeer(peer) { + var messages: [Message] = [] + for messageId in messageIds { + if let message = modifier.getMessage(messageId) { + messages.append(message) } } - if let (minId, maxId) = currentRange { - ranges.append(Api.MessageRange.messageRange(minId: minId, maxId: maxId)) - } - return network.request(Api.functions.updates.getChannelDifference(flags: 0, channel: inputChannel, filter: .channelMessagesFilter(flags: 1 << 1, ranges: ranges), pts: minValidatedPts ?? 1, limit: 100)) - |> `catch` { _ -> Signal in - return .never() - } - |> mapToSignal { result -> Signal in - return postbox.modify { modifier -> Void in - let finalPts: Int32 - var deletedMessageIds: [MessageId] = [] - var updatedMessages: [MessageId: StoreMessage] = [:] - - var apiChats: [Api.Chat] = [] - var apiUsers: [Api.User] = [] - - switch result { - case let .channelDifference(_, pts, _, newMessages, otherUpdates, chats, users): - finalPts = pts - apiChats = chats - apiUsers = users - - for message in newMessages { - if let message = StoreMessage(apiMessage: message), case let .Id(id) = message.id { - updatedMessages[id] = message - } - } - for update in otherUpdates { - switch update { - case let .updateDeleteChannelMessages(_, messages, _, _): - for messageId in messages { - deletedMessageIds.append(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: messageId)) - } - case let .updateNewChannelMessage(message, _, _): - if let message = StoreMessage(apiMessage: message), case let .Id(id) = message.id { - updatedMessages[id] = message - } - case let .updateEditChannelMessage(message, _, _): - if let message = StoreMessage(apiMessage: message), case let .Id(id) = message.id { - updatedMessages[id] = message - } - default: - break - } - } - case let .channelDifferenceEmpty(_, pts, _): - finalPts = pts - case let .channelDifferenceTooLong(_, pts, _, _, _, _, _, _, _, _, _): - finalPts = pts - } - - var peers: [Peer] = [] - var peerPresences: [PeerId: PeerPresence] = [:] - for chat in apiChats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers.append(groupOrChannel) - } - } - for user in apiUsers { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - if let presence = TelegramUserPresence(apiUser: user) { - peerPresences[telegramUser.id] = presence - } - } - - updatePeers(modifier: modifier, peers: peers, update: { _, updated -> Peer in - return updated - }) - modifier.updatePeerPresences(peerPresences) - - if !deletedMessageIds.isEmpty { - modifier.deleteMessages(deletedMessageIds) - } - - for (messageId, message) in updatedMessages { - modifier.updateMessage(messageId, update: { _ in - var attributes = message.attributes - for j in 0 ..< attributes.count { - if let _ = attributes[j] as? ChannelMessageStateVersionAttribute { - attributes.remove(at: j) - break - } - } - attributes.append(ChannelMessageStateVersionAttribute(pts: finalPts)) - return .update(StoreMessage(id: message.id, globallyUniqueId: message.globallyUniqueId, groupingKey: message.groupingKey, timestamp: message.timestamp, flags: message.flags, tags: message.tags, globalTags: message.globalTags, localTags: message.localTags, forwardInfo: message.forwardInfo, authorId: message.authorId, text: message.text, attributes: attributes, media: message.media)) - }) - } - - for messageId in messageIds { - if updatedMessages[messageId] == nil { - modifier.updateMessage(messageId, 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 - for j in 0 ..< attributes.count { - if let _ = attributes[j] as? ChannelMessageStateVersionAttribute { - attributes.remove(at: j) - break - } - } - attributes.append(ChannelMessageStateVersionAttribute(pts: finalPts)) - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - }) - } - } - } - } + 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)) } else { return .never() }