From 6b78eb5c2d655ac3164be9ff5471cb3a189658eb Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 22 Dec 2016 03:18:02 +0300 Subject: [PATCH] no message --- Postbox.xcodeproj/project.pbxproj | 12 +- Postbox/Message.swift | 6 + Postbox/MessageHistoryView.swift | 70 ++++++++++- Postbox/PeerChatTopIndexableMessageIds.swift | 116 +++++++++++++++++++ Postbox/PeerChatTopTaggedMessageIds.swift | 19 --- Postbox/Postbox.swift | 39 +++++-- 6 files changed, 224 insertions(+), 38 deletions(-) create mode 100644 Postbox/PeerChatTopIndexableMessageIds.swift delete mode 100644 Postbox/PeerChatTopTaggedMessageIds.swift diff --git a/Postbox.xcodeproj/project.pbxproj b/Postbox.xcodeproj/project.pbxproj index dcf5db850e..40b6e0bbdd 100644 --- a/Postbox.xcodeproj/project.pbxproj +++ b/Postbox.xcodeproj/project.pbxproj @@ -147,7 +147,7 @@ D0E3A7A21B28B7DC00A402D9 /* Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E3A7A11B28B7DC00A402D9 /* Media.swift */; }; D0F3CC721DDE1CDC008148FA /* ItemCacheTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC711DDE1CDC008148FA /* ItemCacheTable.swift */; }; D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC731DDE1EB9008148FA /* ItemCacheMetaTable.swift */; }; - D0F7AB321DCFAB18009AD9A1 /* PeerChatTopTaggedMessageIds.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB311DCFAB18009AD9A1 /* PeerChatTopTaggedMessageIds.swift */; }; + D0F7AB321DCFAB18009AD9A1 /* PeerChatTopIndexableMessageIds.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB311DCFAB18009AD9A1 /* PeerChatTopIndexableMessageIds.swift */; }; D0F7B1C01E045C62007EB8A5 /* StringIndexTokens.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827C01E0079CB00071108 /* StringIndexTokens.swift */; }; D0F7B1C31E045C6A007EB8A5 /* Table.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03BCCF71C73561C0097A291 /* Table.swift */; }; D0F7B1C41E045C6A007EB8A5 /* GlobalMessageIdsTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F9E8721C5A1EE500037222 /* GlobalMessageIdsTable.swift */; }; @@ -176,7 +176,7 @@ D0F7B1DB1E045C6A007EB8A5 /* ItemCollectionInfoTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D51DB4FCFC00C6B04F /* ItemCollectionInfoTable.swift */; }; D0F7B1DC1E045C6A007EB8A5 /* ItemCollectionItemTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D71DB4FD1300C6B04F /* ItemCollectionItemTable.swift */; }; D0F7B1DD1E045C6A007EB8A5 /* PeerChatInterfaceStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07CFF821DCA909100761F81 /* PeerChatInterfaceStateTable.swift */; }; - D0F7B1DE1E045C6A007EB8A5 /* PeerChatTopTaggedMessageIds.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB311DCFAB18009AD9A1 /* PeerChatTopTaggedMessageIds.swift */; }; + D0F7B1DE1E045C6A007EB8A5 /* PeerChatTopIndexableMessageIds.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F7AB311DCFAB18009AD9A1 /* PeerChatTopIndexableMessageIds.swift */; }; D0F7B1DF1E045C6A007EB8A5 /* ItemCacheMetaTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC731DDE1EB9008148FA /* ItemCacheMetaTable.swift */; }; D0F7B1E01E045C6A007EB8A5 /* ItemCacheTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC711DDE1CDC008148FA /* ItemCacheTable.swift */; }; D0F7B1E11E045C6A007EB8A5 /* PeerNameTokenIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827C21E008F7300071108 /* PeerNameTokenIndexTable.swift */; }; @@ -299,7 +299,7 @@ D0E3A7A11B28B7DC00A402D9 /* Media.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Media.swift; sourceTree = ""; }; D0F3CC711DDE1CDC008148FA /* ItemCacheTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCacheTable.swift; sourceTree = ""; }; D0F3CC731DDE1EB9008148FA /* ItemCacheMetaTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCacheMetaTable.swift; sourceTree = ""; }; - D0F7AB311DCFAB18009AD9A1 /* PeerChatTopTaggedMessageIds.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerChatTopTaggedMessageIds.swift; sourceTree = ""; }; + D0F7AB311DCFAB18009AD9A1 /* PeerChatTopIndexableMessageIds.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerChatTopIndexableMessageIds.swift; sourceTree = ""; }; D0F9E85A1C565EBB00037222 /* MessageMediaTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageMediaTable.swift; sourceTree = ""; }; D0F9E8601C57766A00037222 /* MessageHistoryTableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryTableTests.swift; sourceTree = ""; }; D0F9E8621C579F0200037222 /* MediaCleanupTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaCleanupTable.swift; sourceTree = ""; }; @@ -429,7 +429,7 @@ D021E0D51DB4FCFC00C6B04F /* ItemCollectionInfoTable.swift */, D021E0D71DB4FD1300C6B04F /* ItemCollectionItemTable.swift */, D07CFF821DCA909100761F81 /* PeerChatInterfaceStateTable.swift */, - D0F7AB311DCFAB18009AD9A1 /* PeerChatTopTaggedMessageIds.swift */, + D0F7AB311DCFAB18009AD9A1 /* PeerChatTopIndexableMessageIds.swift */, D0F3CC731DDE1EB9008148FA /* ItemCacheMetaTable.swift */, D0F3CC711DDE1CDC008148FA /* ItemCacheTable.swift */, D07827C21E008F7300071108 /* PeerNameTokenIndexTable.swift */, @@ -791,7 +791,7 @@ D073CE7C1DCBF3B4007511FD /* CachedPeerData.swift in Sources */, D0F7B1DA1E045C6A007EB8A5 /* RatingTable.swift in Sources */, D073CE9F1DCBF3C1007511FD /* InitialMessageHistoryData.swift in Sources */, - D0F7B1DE1E045C6A007EB8A5 /* PeerChatTopTaggedMessageIds.swift in Sources */, + D0F7B1DE1E045C6A007EB8A5 /* PeerChatTopIndexableMessageIds.swift in Sources */, D0B4184A1D7DFE20004562A4 /* UnsentMessageHistoryView.swift in Sources */, D0B418231D7DFE0C004562A4 /* SimpleDictionary.swift in Sources */, D0B4185C1D7DFE2F004562A4 /* MurMurHash32.m in Sources */, @@ -898,7 +898,7 @@ D00EED1E1C81F28D00341DFF /* MessageHistoryTagsTable.swift in Sources */, D044CA2C1C617E2D002160FF /* MessageHistoryMetadataTable.swift in Sources */, D03120FC1DA55427006A2A60 /* PeerNotificationSettings.swift in Sources */, - D0F7AB321DCFAB18009AD9A1 /* PeerChatTopTaggedMessageIds.swift in Sources */, + D0F7AB321DCFAB18009AD9A1 /* PeerChatTopIndexableMessageIds.swift in Sources */, D03BCCF81C73561C0097A291 /* Table.swift in Sources */, D021E0DC1DB5237C00C6B04F /* ItemCollectionsView.swift in Sources */, D0C735281C864DF300BB3149 /* PeerChatStateTable.swift in Sources */, diff --git a/Postbox/Message.swift b/Postbox/Message.swift index 3b03f86136..886401447c 100644 --- a/Postbox/Message.swift +++ b/Postbox/Message.swift @@ -205,6 +205,10 @@ public struct MessageFlags: OptionSet { rawValue |= MessageFlags.Personal.rawValue } + if flags.contains(StoreMessageFlags.TopIndexable) { + rawValue |= MessageFlags.TopIndexable.rawValue + } + self.rawValue = rawValue } @@ -212,6 +216,7 @@ public struct MessageFlags: OptionSet { public static let Failed = MessageFlags(rawValue: 2) public static let Incoming = MessageFlags(rawValue: 4) public static let Personal = MessageFlags(rawValue: 8) + public static let TopIndexable = MessageFlags(rawValue: 16) } public struct StoreMessageForwardInfo { @@ -320,6 +325,7 @@ public struct StoreMessageFlags: OptionSet { public static let Failed = StoreMessageFlags(rawValue: 2) public static let Incoming = StoreMessageFlags(rawValue: 4) public static let Personal = StoreMessageFlags(rawValue: 8) + public static let TopIndexable = StoreMessageFlags(rawValue: 16) } public enum StoreMessageId { diff --git a/Postbox/MessageHistoryView.swift b/Postbox/MessageHistoryView.swift index d82a30d75a..a7f8988516 100644 --- a/Postbox/MessageHistoryView.swift +++ b/Postbox/MessageHistoryView.swift @@ -137,6 +137,20 @@ final class MutableMessageHistoryViewReplayContext { } } +enum MessageHistoryTopTaggedMessage { + case message(Message) + case intermediate(IntermediateMessage) + + var id: MessageId { + switch self { + case let .message(message): + return message.id + case let .intermediate(message): + return message.id + } + } +} + final class MutableMessageHistoryView { private(set) var id: MessageHistoryViewId let tagMask: MessageTags? @@ -148,7 +162,9 @@ final class MutableMessageHistoryView { fileprivate var entries: [MutableMessageHistoryEntry] fileprivate let fillCount: Int - init(id: MessageHistoryViewId, anchorIndex: MessageHistoryAnchorIndex, combinedReadState: CombinedPeerReadState?, earlier: MutableMessageHistoryEntry?, entries: [MutableMessageHistoryEntry], later: MutableMessageHistoryEntry?, tagMask: MessageTags?, count: Int) { + fileprivate var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] + + init(id: MessageHistoryViewId, anchorIndex: MessageHistoryAnchorIndex, combinedReadState: CombinedPeerReadState?, earlier: MutableMessageHistoryEntry?, entries: [MutableMessageHistoryEntry], later: MutableMessageHistoryEntry?, tagMask: MessageTags?, count: Int, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?]) { self.id = id self.anchorIndex = anchorIndex self.combinedReadState = combinedReadState @@ -158,6 +174,7 @@ final class MutableMessageHistoryView { self.later = later self.tagMask = tagMask self.fillCount = count + self.topTaggedMessages = topTaggedMessages } func incrementVersion() { @@ -246,9 +263,6 @@ final class MutableMessageHistoryView { self.earlier = earlier self.later = later - /*let (entries, earlier, later) = self.fetchAroundHistoryEntries(index, count: count, tagMask: tagMask) - - let mutableView = MutableMessageHistoryView(id: MessageHistoryViewId(peerId: peerId, id: self.takeNextViewId()), anchorIndex: anchorIndex, combinedReadState: fixedCombinedReadState ?? self.readStateTable.getCombinedState(peerId), earlier: earlier, entries: entries, later: later, tagMask: tagMask, count: count)*/ return true } @@ -380,6 +394,31 @@ final class MutableMessageHistoryView { } } + for operation in operations { + switch operation { + case let .InsertMessage(message): + if message.flags.contains(.TopIndexable) { + if let currentTopMessage = self.topTaggedMessages[message.id.namespace] { + if currentTopMessage == nil || currentTopMessage!.id < message.id { + self.topTaggedMessages[message.id.namespace] = MessageHistoryTopTaggedMessage.intermediate(message) + hasChanges = true + } + } + } + case let .Remove(indices): + if !self.topTaggedMessages.isEmpty { + for index in indices { + if let maybeCurrentTopMessage = self.topTaggedMessages[index.id.namespace], let currentTopMessage = maybeCurrentTopMessage, index.id == currentTopMessage.id { + let item: MessageHistoryTopTaggedMessage? = nil + self.topTaggedMessages[index.id.namespace] = item + } + } + } + default: + break + } + } + return hasChanges } @@ -548,11 +587,18 @@ final class MutableMessageHistoryView { self.later = .MessageEntry(renderIntermediateMessage(intermediateMessage), location) } - for i in 0 ..< self.entries.count { + for i in 0 ..< self.entries.count { if case let .IntermediateMessageEntry(intermediateMessage, location) = self.entries[i] { self.entries[i] = .MessageEntry(renderIntermediateMessage(intermediateMessage), location) } } + + for namespace in self.topTaggedMessages.keys { + if let entry = self.topTaggedMessages[namespace]!, case let .intermediate(message) = entry { + let item: MessageHistoryTopTaggedMessage? = .message(renderIntermediateMessage(message)) + self.topTaggedMessages[namespace] = item + } + } } func firstHole() -> (MessageHistoryHole, HoleFillDirection)? { @@ -616,6 +662,7 @@ public final class MessageHistoryView { public let entries: [MessageHistoryEntry] public let maxReadIndex: MessageIndex? public let combinedReadState: CombinedPeerReadState? + public let topTaggedMessages: [Message] init(_ mutableView: MutableMessageHistoryView) { self.id = mutableView.id @@ -653,6 +700,19 @@ public final class MessageHistoryView { } self.entries = entries + var topTaggedMessages: [Message] = [] + for (namespace, message) in mutableView.topTaggedMessages { + if let message = message { + switch message { + case let .message(message): + topTaggedMessages.append(message) + default: + assertionFailure("unexpected intermediate tagged message entry in MessageHistoryView.init()") + } + } + } + self.topTaggedMessages = topTaggedMessages + self.earlierId = mutableView.earlier?.index self.laterId = mutableView.later?.index diff --git a/Postbox/PeerChatTopIndexableMessageIds.swift b/Postbox/PeerChatTopIndexableMessageIds.swift new file mode 100644 index 0000000000..9f4bf66eab --- /dev/null +++ b/Postbox/PeerChatTopIndexableMessageIds.swift @@ -0,0 +1,116 @@ +import Foundation + +private struct PeerChatTopTaggedUpdateRecord: Hashable { + let peerId: PeerId + let namespace: MessageId.Namespace + + static func ==(lhs: PeerChatTopTaggedUpdateRecord, rhs: PeerChatTopTaggedUpdateRecord) -> Bool { + return lhs.peerId == rhs.peerId && lhs.namespace == rhs.namespace + } + + var hashValue: Int { + return self.peerId.hashValue + } +} + +final class PeerChatTopTaggedMessageIdsTable: Table { + static func tableSpec(_ id: Int32) -> ValueBoxTable { + return ValueBoxTable(id: id, keyType: .binary) + } + + private var cachedTopIds: [PeerId: [MessageId.Namespace: MessageId?]] = [:] + private var updatedPeerIds = Set() + + private let sharedKey = ValueBoxKey(length: 8 + 4 + 4) + + private func key(peerId: PeerId, namespace: MessageId.Namespace) -> ValueBoxKey { + self.sharedKey.setInt64(0, value: peerId.toInt64()) + self.sharedKey.setInt32(8, value: namespace) + return self.sharedKey + } + + func get(peerId: PeerId, namespace: MessageId.Namespace) -> MessageId? { + if let cachedDict = self.cachedTopIds[peerId] { + if let maybeCachedId = cachedDict[namespace] { + return maybeCachedId + } else { + if let value = self.valueBox.get(self.table, key: self.key(peerId: peerId, namespace: namespace)) { + var messageIdId: Int32 = 0 + value.read(&messageIdId, offset: 0, length: 4) + self.cachedTopIds[peerId]![namespace] = MessageId(peerId: peerId, namespace: namespace, id: messageIdId) + return MessageId(peerId: peerId, namespace: namespace, id: messageIdId) + } else { + let item: MessageId? = nil + self.cachedTopIds[peerId]![namespace] = item + return nil + } + } + } else { + if let value = self.valueBox.get(self.table, key: self.key(peerId: peerId, namespace: namespace)) { + var messageIdId: Int32 = 0 + value.read(&messageIdId, offset: 0, length: 4) + self.cachedTopIds[peerId] = [namespace: MessageId(peerId: peerId, namespace: namespace, id: messageIdId)] + return MessageId(peerId: peerId, namespace: namespace, id: messageIdId) + } else { + let item: MessageId? = nil + self.cachedTopIds[peerId] = [namespace: item] + return nil + } + } + } + + private func set(peerId: PeerId, namespace: MessageId.Namespace, id: MessageId?) { + if let _ = self.cachedTopIds[peerId] { + self.cachedTopIds[peerId]![namespace] = id + } else { + self.cachedTopIds[peerId] = [namespace: id] + } + self.updatedPeerIds.insert(PeerChatTopTaggedUpdateRecord(peerId: peerId, namespace: namespace)) + } + + func replay(historyOperationsByPeerId: [PeerId : [MessageHistoryOperation]]) { + var updatedRecords = Set() + for (peerId, operations) in historyOperationsByPeerId { + for operation in operations { + switch operation { + case let .InsertMessage(message): + if message.flags.contains(.TopIndexable) { + let currentTopMessageId = self.get(peerId: message.id.peerId, namespace: message.id.namespace) + if currentTopMessageId == nil || currentTopMessageId! < message.id { + self.set(peerId: message.id.peerId, namespace: message.id.namespace, id: message.id) + } + } + case let .Remove(indices): + for index in indices { + if let _ = self.get(peerId: index.id.peerId, namespace: index.id.namespace) { + self.set(peerId: index.id.peerId, namespace: index.id.namespace, id: nil) + } + } + default: + break + } + } + } + } + + override func clearMemoryCache() { + assert(self.updatedPeerIds.isEmpty) + self.cachedTopIds.removeAll() + } + + override func beforeCommit() { + if !self.updatedPeerIds.isEmpty { + for record in self.updatedPeerIds { + if let cachedDict = self.cachedTopIds[record.peerId], let maybeMessageId = cachedDict[record.namespace] { + if let maybeMessageId = maybeMessageId { + var messageIdId: Int32 = maybeMessageId.id + self.valueBox.set(self.table, key: self.key(peerId: record.peerId, namespace: record.namespace), value: MemoryBuffer(memory: &messageIdId, capacity: 4, length: 4, freeWhenDone: false)) + } else { + self.valueBox.remove(self.table, key: self.key(peerId: record.peerId, namespace: record.namespace)) + } + } + } + self.updatedPeerIds.removeAll() + } + } +} diff --git a/Postbox/PeerChatTopTaggedMessageIds.swift b/Postbox/PeerChatTopTaggedMessageIds.swift deleted file mode 100644 index 2b3d3a9c7b..0000000000 --- a/Postbox/PeerChatTopTaggedMessageIds.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -final class PeerChatTopTaggedMessageIdsTable: Table { - static func tableSpec(_ id: Int32) -> ValueBoxTable { - return ValueBoxTable(id: id, keyType: .binary) - } - - private var cachedTopIds: [PeerId: [MessageId.Namespace: MessageId?]] = [:] - private var updatedPeerIds = Set() - - private let sharedKey = ValueBoxKey(length: 8 + 4 + 4) - - override func beforeCommit() { - for peerId in self.updatedPeerIds { - - } - self.updatedPeerIds.removeAll() - } -} diff --git a/Postbox/Postbox.swift b/Postbox/Postbox.swift index f3981b51db..948f7db184 100644 --- a/Postbox/Postbox.swift +++ b/Postbox/Postbox.swift @@ -268,6 +268,7 @@ public final class Postbox { var itemCacheTable: ItemCacheTable! var peerNameTokenIndexTable: PeerNameTokenIndexTable! var peerNameIndexTable: PeerNameIndexTable! + var peerChatTopTaggedMessageIdsTable: PeerChatTopTaggedMessageIdsTable! //temporary var peerRatingTable: RatingTable! @@ -383,6 +384,7 @@ public final class Postbox { self.peerNameIndexTable = PeerNameIndexTable(valueBox: self.valueBox, table: PeerNameIndexTable.tableSpec(27), peerTable: self.peerTable, peerNameTokenIndexTable: self.peerNameTokenIndexTable) self.chatListIndexTable = ChatListIndexTable(valueBox: self.valueBox, table: ChatListIndexTable.tableSpec(8), peerNameIndexTable: self.peerNameIndexTable) self.chatListTable = ChatListTable(valueBox: self.valueBox, table: ChatListTable.tableSpec(9), indexTable: self.chatListIndexTable, metadataTable: self.messageHistoryMetadataTable, seedConfiguration: self.seedConfiguration) + self.peerChatTopTaggedMessageIdsTable = PeerChatTopTaggedMessageIdsTable(valueBox: self.valueBox, table: PeerChatTopTaggedMessageIdsTable.tableSpec(28)) self.tables.append(self.keychainTable) self.tables.append(self.peerTable) @@ -410,6 +412,7 @@ public final class Postbox { self.tables.append(self.itemCacheTable) self.tables.append(self.peerNameIndexTable) self.tables.append(self.peerNameTokenIndexTable) + self.tables.append(self.peerChatTopTaggedMessageIdsTable) self.transactionStateVersion = self.metadataTable.transactionStateVersion() @@ -786,6 +789,8 @@ public final class Postbox { self.chatListTable.replaceHole(index, hole: hole, operations: &chatListOperations) } + self.peerChatTopTaggedMessageIdsTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId) + let transaction = PostboxTransaction(currentOperationsByPeerId: self.currentOperationsByPeerId, peerIdsWithFilledHoles: self.currentFilledHolesByPeerId, removedHolesByPeerId: self.currentRemovedHolesByPeerId, chatListOperations: chatListOperations, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, updatedMedia: self.currentUpdatedMedia, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentUpdatedMasterClientId: currentUpdatedMasterClientId) var updatedTransactionState: Int64? var updatedMasterClientId: Int64? @@ -974,29 +979,29 @@ public final class Postbox { } } - public func aroundUnreadMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundUnreadMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { return self.modify(userInteractive: true, { modifier -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in var index = MessageHistoryAnchorIndex(index: MessageIndex.upperBound(peerId: peerId), exact: true) if let maxReadIndex = self.messageHistoryTable.maxReadIndex(peerId) { index = maxReadIndex } - return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, tagMask: tagMask) + return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask) }) |> switchToLatest } - public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { return self.modify { modifier -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in var index = MessageHistoryAnchorIndex(index: MessageIndex.upperBound(peerId: peerId), exact: true) if let anchorIndex = self.messageHistoryTable.anchorIndex(messageId) { index = anchorIndex } - return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, tagMask: tagMask) + return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask) } |> switchToLatest } - public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { return self.modify { modifier -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in - return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: MessageHistoryAnchorIndex(index: anchorIndex, exact: true), unreadIndex: nil, fixedCombinedReadState: fixedCombinedReadState, tagMask: tagMask) + return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: MessageHistoryAnchorIndex(index: anchorIndex, exact: true), unreadIndex: nil, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask) } |> switchToLatest } @@ -1026,12 +1031,30 @@ public final class Postbox { } } - private func syncAroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageHistoryAnchorIndex, unreadIndex: MessageIndex?, fixedCombinedReadState: CombinedPeerReadState?, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + private func syncAroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageHistoryAnchorIndex, unreadIndex: MessageIndex?, fixedCombinedReadState: CombinedPeerReadState?, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { let startTime = CFAbsoluteTimeGetCurrent() let (entries, earlier, later) = self.fetchAroundHistoryEntries(index, count: count, tagMask: tagMask) print("aroundMessageHistoryViewForPeerId fetchAroundHistoryEntries \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") - let mutableView = MutableMessageHistoryView(id: MessageHistoryViewId(peerId: peerId, id: self.takeNextViewId()), anchorIndex: anchorIndex, combinedReadState: fixedCombinedReadState ?? self.readStateTable.getCombinedState(peerId), earlier: earlier, entries: entries, later: later, tagMask: tagMask, count: count) + var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:] + for namespace in topTaggedMessageIdNamespaces { + if let messageId = self.peerChatTopTaggedMessageIdsTable.get(peerId: peerId, namespace: namespace) { + if let indexEntry = self.messageHistoryIndexTable.get(messageId), case let .Message(index) = indexEntry { + if let message = self.messageHistoryTable.getMessage(index) { + topTaggedMessages[namespace] = MessageHistoryTopTaggedMessage.intermediate(message) + } else { + assertionFailure() + } + } else { + assertionFailure() + } + } else { + let item: MessageHistoryTopTaggedMessage? = nil + topTaggedMessages[namespace] = item + } + } + + let mutableView = MutableMessageHistoryView(id: MessageHistoryViewId(peerId: peerId, id: self.takeNextViewId()), anchorIndex: anchorIndex, combinedReadState: fixedCombinedReadState ?? self.readStateTable.getCombinedState(peerId), earlier: earlier, entries: entries, later: later, tagMask: tagMask, count: count, topTaggedMessages: topTaggedMessages) mutableView.render(self.renderIntermediateMessage) let initialUpdateType: ViewUpdateType