no message

This commit is contained in:
Peter 2017-06-27 19:27:25 +03:00
parent 034531e433
commit aa5346e28a
8 changed files with 355 additions and 48 deletions

View File

@ -28,6 +28,8 @@
D01BAA561ED1D70C00295217 /* ManagedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01BAA541ED1D70C00295217 /* ManagedFile.swift */; }; D01BAA561ED1D70C00295217 /* ManagedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01BAA541ED1D70C00295217 /* ManagedFile.swift */; };
D01C7EDE1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; }; D01C7EDE1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
D01C7EDF1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; }; D01C7EDF1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */; };
D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */; };
D01C7F081EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */; };
D01F7D9B1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */; }; D01F7D9B1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */; };
D01F7D9D1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */; }; D01F7D9D1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */; };
D021E0D41DB4FAE100C6B04F /* ItemCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */; }; D021E0D41DB4FAE100C6B04F /* ItemCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */; };
@ -304,6 +306,7 @@
D019B1CE1E2E770700F80DB3 /* MessageGloballyUniqueIdTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageGloballyUniqueIdTable.swift; sourceTree = "<group>"; }; D019B1CE1E2E770700F80DB3 /* MessageGloballyUniqueIdTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageGloballyUniqueIdTable.swift; sourceTree = "<group>"; };
D01BAA541ED1D70C00295217 /* ManagedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedFile.swift; sourceTree = "<group>"; }; D01BAA541ED1D70C00295217 /* ManagedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedFile.swift; sourceTree = "<group>"; };
D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryTextIndexTable.swift; sourceTree = "<group>"; }; D01C7EDD1EF73F71008305F1 /* MessageHistoryTextIndexTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryTextIndexTable.swift; sourceTree = "<group>"; };
D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnorderedItemListTable.swift; sourceTree = "<group>"; };
D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryInvalidatedReadStateTable.swift; sourceTree = "<group>"; }; D01F7D9A1CBEC390008765C9 /* MessageHistoryInvalidatedReadStateTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryInvalidatedReadStateTable.swift; sourceTree = "<group>"; };
D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadStatesView.swift; sourceTree = "<group>"; }; D01F7D9C1CBF8586008765C9 /* SynchronizePeerReadStatesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadStatesView.swift; sourceTree = "<group>"; };
D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCollection.swift; sourceTree = "<group>"; }; D021E0D31DB4FAE100C6B04F /* ItemCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCollection.swift; sourceTree = "<group>"; };
@ -597,6 +600,7 @@
D08774FF1E3E3D9F00A97350 /* PreferencesTable.swift */, D08774FF1E3E3D9F00A97350 /* PreferencesTable.swift */,
D0F82CFC1E4345D7007E499C /* OrderedItemListTable.swift */, D0F82CFC1E4345D7007E499C /* OrderedItemListTable.swift */,
D0F82D0E1E43A024007E499C /* OrderedItemListIndexTable.swift */, D0F82D0E1E43A024007E499C /* OrderedItemListIndexTable.swift */,
D01C7F061EFC1ED3008305F1 /* UnorderedItemListTable.swift */,
); );
name = Tables; name = Tables;
sourceTree = "<group>"; sourceTree = "<group>";
@ -932,6 +936,7 @@
files = ( files = (
D050F2661E4A5B5A00988324 /* MessageGloballyUniqueIdTable.swift in Sources */, D050F2661E4A5B5A00988324 /* MessageGloballyUniqueIdTable.swift in Sources */,
D03229EF1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */, D03229EF1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
D01C7F081EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */,
D050F2671E4A5B5A00988324 /* TimestampBasedMessageAttributesTable.swift in Sources */, D050F2671E4A5B5A00988324 /* TimestampBasedMessageAttributesTable.swift in Sources */,
D050F2681E4A5B5A00988324 /* TimestampBasedMessageAttributesIndexTable.swift in Sources */, D050F2681E4A5B5A00988324 /* TimestampBasedMessageAttributesIndexTable.swift in Sources */,
D050F2691E4A5B5A00988324 /* MultiplePeersView.swift in Sources */, D050F2691E4A5B5A00988324 /* MultiplePeersView.swift in Sources */,
@ -1062,6 +1067,7 @@
files = ( files = (
D08775061E3E3F2100A97350 /* PreferencesView.swift in Sources */, D08775061E3E3F2100A97350 /* PreferencesView.swift in Sources */,
D03229EE1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */, D03229EE1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */,
D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */,
D0F9E8631C579F0200037222 /* MediaCleanupTable.swift in Sources */, D0F9E8631C579F0200037222 /* MediaCleanupTable.swift in Sources */,
D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */, D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */,
D08D451F1D5D2CA700A7428A /* RatingTable.swift in Sources */, D08D451F1D5D2CA700A7428A /* RatingTable.swift in Sources */,

View File

@ -63,13 +63,13 @@ public func <(lhs: ChatListEntry, rhs: ChatListEntry) -> Bool {
} }
enum MutableChatListEntry: Equatable { enum MutableChatListEntry: Equatable {
case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?) case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerChatListEmbeddedInterfaceState?)
case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer) case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer)
case HoleEntry(ChatListHole) case HoleEntry(ChatListHole)
var index: ChatListIndex { var index: ChatListIndex {
switch self { switch self {
case let .IntermediateMessageEntry(index, _, _, _, _): case let .IntermediateMessageEntry(index, _, _, _):
return index return index
case let .MessageEntry(index, _, _, _, _, _): case let .MessageEntry(index, _, _, _, _, _):
return index return index
@ -119,6 +119,50 @@ final class MutableChatListViewReplayContext {
} }
} }
private func updateMessagePeers(_ message: Message, updatedPeers: [PeerId: Peer]) -> Message? {
var updated = false
for (peerId, currentPeer) in message.peers {
if let updatedPeer = updatedPeers[peerId], !arePeersEqual(currentPeer, updatedPeer) {
updated = true
break
}
}
if updated {
var peers = SimpleDictionary<PeerId, Peer>()
for (peerId, currentPeer) in message.peers {
if let updatedPeer = updatedPeers[peerId] {
peers[peerId] = updatedPeer
} else {
peers[peerId] = currentPeer
}
}
return Message(stableId: message.stableId, stableVersion: message.stableVersion, id: message.id, globallyUniqueId: message.globallyUniqueId, timestamp: message.timestamp, flags: message.flags, tags: message.tags, globalTags: message.globalTags, forwardInfo: message.forwardInfo, author: message.author, text: message.text, attributes: message.attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: message.associatedMessageIds)
}
return nil
}
private func updatedRenderedPeer(_ renderedPeer: RenderedPeer, updatedPeers: [PeerId: Peer]) -> RenderedPeer? {
var updated = false
for (peerId, currentPeer) in renderedPeer.peers {
if let updatedPeer = updatedPeers[peerId], !arePeersEqual(currentPeer, updatedPeer) {
updated = true
break
}
}
if updated {
var peers = SimpleDictionary<PeerId, Peer>()
for (peerId, currentPeer) in renderedPeer.peers {
if let updatedPeer = updatedPeers[peerId] {
peers[peerId] = updatedPeer
} else {
peers[peerId] = currentPeer
}
}
return RenderedPeer(peerId: renderedPeer.peerId, peers: peers)
}
return nil
}
final class MutableChatListView { final class MutableChatListView {
fileprivate var earlier: MutableChatListEntry? fileprivate var earlier: MutableChatListEntry?
fileprivate var later: MutableChatListEntry? fileprivate var later: MutableChatListEntry?
@ -150,12 +194,12 @@ final class MutableChatListView {
} }
} }
func replay(_ operations: [ChatListOperation], updatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], context: MutableChatListViewReplayContext) -> Bool { func replay(_ operations: [ChatListOperation], updatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], updatedPeers: [PeerId: Peer], context: MutableChatListViewReplayContext) -> Bool {
var hasChanges = false var hasChanges = false
for operation in operations { for operation in operations {
switch operation { switch operation {
case let .InsertEntry(index, message, combinedReadState, embeddedState): case let .InsertEntry(index, message, combinedReadState, embeddedState):
if self.add(.IntermediateMessageEntry(index, message, combinedReadState, nil, embeddedState)) { if self.add(.IntermediateMessageEntry(index, message, combinedReadState, embeddedState)) {
hasChanges = true hasChanges = true
} }
case let .InsertHole(index): case let .InsertHole(index):
@ -175,14 +219,31 @@ final class MutableChatListView {
if !updatedPeerNotificationSettings.isEmpty { if !updatedPeerNotificationSettings.isEmpty {
for i in 0 ..< self.entries.count { for i in 0 ..< self.entries.count {
switch self.entries[i] { switch self.entries[i] {
case let .IntermediateMessageEntry(index, message, readState, _, embeddedState): case let .MessageEntry(index, message, readState, _, embeddedState, peer):
if let settings = updatedPeerNotificationSettings[index.messageIndex.id.peerId] { var notificationSettingsPeerId = peer.peerId
self.entries[i] = .IntermediateMessageEntry(index, message, readState, settings, embeddedState) if let peer = peer.peers[peer.peerId], let associatedPeerId = peer.associatedPeerId {
notificationSettingsPeerId = associatedPeerId
}
if let settings = updatedPeerNotificationSettings[notificationSettingsPeerId] {
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer)
hasChanges = true hasChanges = true
} }
case let .MessageEntry(index, message, readState, _, embeddedState, peer): default:
if let settings = updatedPeerNotificationSettings[index.messageIndex.id.peerId] { continue
self.entries[i] = .MessageEntry(index, message, readState, settings, embeddedState, peer) }
}
}
if !updatedPeers.isEmpty {
for i in 0 ..< self.entries.count {
switch self.entries[i] {
case let .MessageEntry(index, message, readState, settings, embeddedState, peer):
var updatedMessage: Message?
if let message = message {
updatedMessage = updateMessagePeers(message, updatedPeers: updatedPeers)
}
let updatedPeer = updatedRenderedPeer(peer, updatedPeers: updatedPeers)
if updatedMessage != nil || updatedPeer != nil {
self.entries[i] = .MessageEntry(index, updatedMessage ?? message, readState, settings, embeddedState, updatedPeer ?? peer)
hasChanges = true hasChanges = true
} }
default: default:
@ -403,38 +464,10 @@ final class MutableChatListView {
return nil return nil
} }
func updatePeers(_ peers: [PeerId: Peer]) -> Bool {
let hasChanges = false
/*for i in 0 ..< self.entries.count {
switch self.entries[i] {
case let .MessageEntry(message):
var updatedAuthor: Peer?
if let author = message.author, let peer = peers[author.id] {
updatedAuthor = peer
}
for peer in message.peers {
}
break
default:
break
}
}*/
return hasChanges
}
func render(_ renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?) { func render(_ renderMessage: (IntermediateMessage) -> Message, getPeer: (PeerId) -> Peer?, getPeerNotificationSettings: (PeerId) -> PeerNotificationSettings?) {
for i in 0 ..< self.entries.count { for i in 0 ..< self.entries.count {
switch self.entries[i] { switch self.entries[i] {
case let .IntermediateMessageEntry(index, message, combinedReadState, notificationSettings, embeddedState): case let .IntermediateMessageEntry(index, message, combinedReadState, embeddedState):
let updatedNotificationSettings: PeerNotificationSettings?
if let notificationSettings = notificationSettings {
updatedNotificationSettings = notificationSettings
} else {
updatedNotificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
}
let renderedMessage: Message? let renderedMessage: Message?
if let message = message { if let message = message {
renderedMessage = renderMessage(message) renderedMessage = renderMessage(message)
@ -442,15 +475,20 @@ final class MutableChatListView {
renderedMessage = nil renderedMessage = nil
} }
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var notificationSettings: PeerNotificationSettings?
if let peer = getPeer(index.messageIndex.id.peerId) { if let peer = getPeer(index.messageIndex.id.peerId) {
peers[peer.id] = peer peers[peer.id] = peer
if let associatedPeerId = peer.associatedPeerId { if let associatedPeerId = peer.associatedPeerId {
if let associatedPeer = getPeer(associatedPeerId) { if let associatedPeer = getPeer(associatedPeerId) {
peers[associatedPeer.id] = associatedPeer peers[associatedPeer.id] = associatedPeer
} }
notificationSettings = getPeerNotificationSettings(associatedPeerId)
} else {
notificationSettings = getPeerNotificationSettings(index.messageIndex.id.peerId)
} }
} }
self.entries[i] = .MessageEntry(index, renderedMessage, combinedReadState, updatedNotificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers))
self.entries[i] = .MessageEntry(index, renderedMessage, combinedReadState, notificationSettings, embeddedState, RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers))
default: default:
break break
} }

View File

@ -108,3 +108,19 @@ public func arePeersEqual(_ lhs: Peer?, _ rhs: Peer?) -> Bool {
return (lhs != nil) == (rhs != nil) return (lhs != nil) == (rhs != nil)
} }
} }
public func arePeerDictionariesEqual(_ lhs: SimpleDictionary<PeerId, Peer>, _ rhs: SimpleDictionary<PeerId, Peer>) -> Bool {
if lhs.count != rhs.count {
return false
}
for (id, lhsPeer) in lhs {
if let rhsPeer = rhs[id] {
if !lhsPeer.isEqual(rhsPeer) {
return false
}
} else {
return false
}
}
return true
}

View File

@ -589,6 +589,24 @@ public final class Modifier {
return [] return []
} }
} }
public func unorderedItemListDifference(tag: UnorderedItemListEntryTag, updatedEntryInfos: [ValueBoxKey: UnorderedItemListEntryInfo]) -> (metaInfo: UnorderedItemListTagMetaInfo?, added: [ValueBoxKey], removed: [UnorderedItemListEntry], updated: [UnorderedItemListEntry]) {
assert(!self.disposed)
if let postbox = self.postbox {
return postbox.unorderedItemListTable.difference(tag: tag, updatedEntryInfos: updatedEntryInfos)
} else {
return (nil, [], [], [])
}
}
public func unorderedItemListApplyDifference(tag: UnorderedItemListEntryTag, previousInfo: UnorderedItemListTagMetaInfo?, updatedInfo: UnorderedItemListTagMetaInfo, setItems: [UnorderedItemListEntry], removeItemIds: [ValueBoxKey]) -> Bool {
assert(!self.disposed)
if let postbox = self.postbox {
return postbox.unorderedItemListTable.applyDifference(tag: tag, previousInfo: previousInfo, updatedInfo: updatedInfo, setItems: setItems, removeItemIds: removeItemIds)
} else {
return false
}
}
} }
fileprivate class PipeNotifier: NSObject { fileprivate class PipeNotifier: NSObject {
@ -778,6 +796,7 @@ public final class Postbox {
let orderedItemListTable: OrderedItemListTable let orderedItemListTable: OrderedItemListTable
let orderedItemListIndexTable: OrderedItemListIndexTable let orderedItemListIndexTable: OrderedItemListIndexTable
let textIndexTable: MessageHistoryTextIndexTable let textIndexTable: MessageHistoryTextIndexTable
let unorderedItemListTable: UnorderedItemListTable
//temporary //temporary
let peerRatingTable: RatingTable<PeerId> let peerRatingTable: RatingTable<PeerId>
@ -851,6 +870,7 @@ public final class Postbox {
self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35)) self.preferencesTable = PreferencesTable(valueBox: self.valueBox, table: PreferencesTable.tableSpec(35))
self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37)) self.orderedItemListIndexTable = OrderedItemListIndexTable(valueBox: self.valueBox, table: OrderedItemListIndexTable.tableSpec(37))
self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), indexTable: self.orderedItemListIndexTable) self.orderedItemListTable = OrderedItemListTable(valueBox: self.valueBox, table: OrderedItemListTable.tableSpec(38), indexTable: self.orderedItemListIndexTable)
self.unorderedItemListTable = UnorderedItemListTable(valueBox: self.valueBox, table: UnorderedItemListTable.tableSpec(42))
var tables: [Table] = [] var tables: [Table] = []
tables.append(self.metadataTable) tables.append(self.metadataTable)
@ -893,6 +913,7 @@ public final class Postbox {
tables.append(self.preferencesTable) tables.append(self.preferencesTable)
tables.append(self.orderedItemListTable) tables.append(self.orderedItemListTable)
tables.append(self.orderedItemListIndexTable) tables.append(self.orderedItemListIndexTable)
tables.append(self.unorderedItemListTable)
self.tables = tables self.tables = tables
@ -1221,7 +1242,7 @@ public final class Postbox {
for entry in intermediateEntries { for entry in intermediateEntries {
switch entry { switch entry {
case let .Message(index, message, embeddedState): case let .Message(index, message, embeddedState):
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)) entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
case let .Hole(hole): case let .Hole(hole):
entries.append(.HoleEntry(hole)) entries.append(.HoleEntry(hole))
} }
@ -1230,7 +1251,7 @@ public final class Postbox {
if let intermediateLower = intermediateLower { if let intermediateLower = intermediateLower {
switch intermediateLower { switch intermediateLower {
case let .Message(index, message, embeddedState): case let .Message(index, message, embeddedState):
lower = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState) lower = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState)
case let .Hole(hole): case let .Hole(hole):
lower = .HoleEntry(hole) lower = .HoleEntry(hole)
} }
@ -1239,7 +1260,7 @@ public final class Postbox {
if let intermediateUpper = intermediateUpper { if let intermediateUpper = intermediateUpper {
switch intermediateUpper { switch intermediateUpper {
case let .Message(index, message, embeddedState): case let .Message(index, message, embeddedState):
upper = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState) upper = .IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState)
case let .Hole(hole): case let .Hole(hole):
upper = .HoleEntry(hole) upper = .HoleEntry(hole)
} }
@ -1254,7 +1275,7 @@ public final class Postbox {
for entry in intermediateEntries { for entry in intermediateEntries {
switch entry { switch entry {
case let .Message(index, message, embeddedState): case let .Message(index, message, embeddedState):
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)) entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
case let .Hole(hole): case let .Hole(hole):
entries.append(.HoleEntry(hole)) entries.append(.HoleEntry(hole))
} }
@ -1268,7 +1289,7 @@ public final class Postbox {
for entry in intermediateEntries { for entry in intermediateEntries {
switch entry { switch entry {
case let .Message(index, message, embeddedState): case let .Message(index, message, embeddedState):
entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), self.peerNotificationSettingsTable.get(index.messageIndex.id.peerId), embeddedState)) entries.append(.IntermediateMessageEntry(index, message, self.readStateTable.getCombinedState(index.messageIndex.id.peerId), embeddedState))
case let .Hole(index): case let .Hole(index):
entries.append(.HoleEntry(index)) entries.append(.HoleEntry(index))
} }

View File

@ -95,4 +95,3 @@ public struct SimpleDictionary<K: Hashable, V>: Sequence {
return true return true
} }
} }

View File

@ -0,0 +1,219 @@
import Foundation
public struct UnorderedItemListEntryInfo {
public let hashValue: Int64
public init(hashValue: Int64) {
self.hashValue = hashValue
}
}
public struct UnorderedItemListEntry {
public let id: ValueBoxKey
public let info: UnorderedItemListEntryInfo
public let contents: Coding
public init(id: ValueBoxKey, info: UnorderedItemListEntryInfo, contents: Coding) {
self.id = id
self.info = info
self.contents = contents
}
}
public struct UnorderedItemListEntryTag {
public let value: ValueBoxKey
public init(value: ValueBoxKey) {
self.value = value
}
}
public protocol UnorderedItemListTagMetaInfo: Coding {
func isEqual(to: UnorderedItemListTagMetaInfo) -> Bool
}
private enum UnorderedItemListTableKeyspace: UInt8 {
case metaInfo = 0
case entries = 1
}
private func extractEntryKey(tagLength: Int, key: ValueBoxKey) -> ValueBoxKey {
let result = ValueBoxKey(length: key.length - tagLength - 1)
memcpy(result.memory, key.memory.advanced(by: 1 + tagLength), result.length)
return result
}
private func extractEntryInfo(_ value: ReadBuffer) -> UnorderedItemListEntryInfo {
var hashValue: Int64 = 0
value.read(&hashValue, offset: 0, length: 8)
return UnorderedItemListEntryInfo(hashValue: hashValue)
}
final class UnorderedItemListTable: Table {
static func tableSpec(_ id: Int32) -> ValueBoxTable {
return ValueBoxTable(id: id, keyType: .binary)
}
private func metaInfoKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
let tagValue = tag.value
let key = ValueBoxKey(length: 1 + tagValue.length)
key.setUInt8(0, value: UnorderedItemListTableKeyspace.metaInfo.rawValue)
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
return key
}
private func entryKey(tag: UnorderedItemListEntryTag, id: ValueBoxKey) -> ValueBoxKey {
let tagValue = tag.value
let key = ValueBoxKey(length: 1 + tagValue.length + id.length)
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
memcpy(key.memory.advanced(by: 1 + tagValue.length), id.memory, id.length)
return key
}
private func entryLowerBoundKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
let tagValue = tag.value
let key = ValueBoxKey(length: 1 + tagValue.length)
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
return key
}
private func entryUpperBoundKey(tag: UnorderedItemListEntryTag) -> ValueBoxKey {
let tagValue = tag.value.successor
let key = ValueBoxKey(length: 1 + tagValue.length)
key.setUInt8(0, value: UnorderedItemListTableKeyspace.entries.rawValue)
memcpy(key.memory.advanced(by: 1), tagValue.memory, tagValue.length)
return key
}
private func getMetaInfo(tag: UnorderedItemListEntryTag) -> UnorderedItemListTagMetaInfo? {
if let value = self.valueBox.get(self.table, key: self.metaInfoKey(tag: tag)), let info = Decoder(buffer: value).decodeRootObject() as? UnorderedItemListTagMetaInfo {
return info
} else {
return nil
}
}
private func setMetaInfo(tag: UnorderedItemListEntryTag, info: UnorderedItemListTagMetaInfo) {
let encoder = Encoder()
encoder.encodeRootObject(info)
self.valueBox.set(self.table, key: self.metaInfoKey(tag: tag), value: encoder.readBufferNoCopy())
}
private func getEntryInfos(tag: UnorderedItemListEntryTag) -> [ValueBoxKey: UnorderedItemListEntryInfo] {
var result: [ValueBoxKey: UnorderedItemListEntryInfo] = [:]
let tagLength = tag.value.length
self.valueBox.range(self.table, start: self.entryLowerBoundKey(tag: tag), end: self.entryUpperBoundKey(tag: tag), values: { key, value in
result[extractEntryKey(tagLength: tagLength, key: key)] = extractEntryInfo(value)
return true
}, limit: 0)
return result
}
private func getEntry(tag: UnorderedItemListEntryTag, id: ValueBoxKey) -> UnorderedItemListEntry? {
if let value = self.valueBox.get(self.table, key: self.entryKey(tag: tag, id: id)) {
var hashValue: Int64 = 0
value.read(&hashValue, offset: 0, length: 8)
let tempBuffer = MemoryBuffer(memory: value.memory.advanced(by: 8), capacity: value.length - 8, length: value.length - 8, freeWhenDone: false)
let contents = withExtendedLifetime(tempBuffer, {
return Decoder(buffer: tempBuffer).decodeRootObject()
})
if let contents = contents {
let entry = UnorderedItemListEntry(id: id, info: UnorderedItemListEntryInfo(hashValue: hashValue), contents: contents)
return entry
} else {
assertionFailure()
return nil
}
} else {
return nil
}
}
private func setEntry(tag: UnorderedItemListEntryTag, entry: UnorderedItemListEntry, sharedBuffer: WriteBuffer, sharedEncoder: Encoder) {
sharedBuffer.reset()
sharedEncoder.reset()
var hashValue: Int64 = entry.info.hashValue
sharedBuffer.write(&hashValue, offset: 0, length: 8)
sharedEncoder.encodeRootObject(entry.contents)
let tempBuffer = sharedEncoder.readBufferNoCopy()
withExtendedLifetime(tempBuffer, {
sharedBuffer.write(tempBuffer.memory, offset: 0, length: tempBuffer.length)
})
self.valueBox.set(self.table, key: self.entryKey(tag: tag, id: entry.id), value: sharedBuffer)
}
func difference(tag: UnorderedItemListEntryTag, updatedEntryInfos: [ValueBoxKey: UnorderedItemListEntryInfo]) -> (metaInfo: UnorderedItemListTagMetaInfo?, added: [ValueBoxKey], removed: [UnorderedItemListEntry], updated: [UnorderedItemListEntry]) {
let currentEntryInfos = self.getEntryInfos(tag: tag)
var currentInfoIds = Set<ValueBoxKey>()
for key in currentEntryInfos.keys {
currentInfoIds.insert(key)
}
var updatedInfoIds = Set<ValueBoxKey>()
for key in updatedEntryInfos.keys {
updatedInfoIds.insert(key)
}
let addedKeys = updatedInfoIds.subtracting(currentInfoIds)
let added: [ValueBoxKey] = Array(addedKeys)
let removedKeys = currentInfoIds.subtracting(updatedInfoIds)
var removed: [UnorderedItemListEntry] = []
for key in removedKeys {
if let entry = self.getEntry(tag: tag, id: key) {
removed.append(entry)
} else {
assertionFailure()
}
}
var updated: [UnorderedItemListEntry] = []
for (key, info) in updatedEntryInfos {
if !addedKeys.contains(key) {
if let currentInfo = currentEntryInfos[key] {
if info.hashValue != currentInfo.hashValue {
if let entry = self.getEntry(tag: tag, id: key) {
updated.append(entry)
} else {
assertionFailure()
}
}
} else {
assertionFailure()
}
}
}
return (self.getMetaInfo(tag: tag), added, removed, updated)
}
func applyDifference(tag: UnorderedItemListEntryTag, previousInfo: UnorderedItemListTagMetaInfo?, updatedInfo: UnorderedItemListTagMetaInfo, setItems: [UnorderedItemListEntry], removeItemIds: [ValueBoxKey]) -> Bool {
let currentInfo = self.getMetaInfo(tag: tag)
if let currentInfo = currentInfo, let previousInfo = previousInfo {
if !currentInfo.isEqual(to: previousInfo) {
return false
}
} else if (currentInfo != nil) != (previousInfo != nil) {
return false
}
self.setMetaInfo(tag: tag, info: updatedInfo)
let sharedBuffer = WriteBuffer()
let sharedEncoder = Encoder()
for entry in setItems {
self.setEntry(tag: tag, entry: entry, sharedBuffer: sharedBuffer, sharedEncoder: sharedEncoder)
}
for id in removeItemIds {
self.valueBox.remove(self.table, key: self.entryKey(tag: tag, id: id))
}
return true
}
}

View File

@ -190,6 +190,14 @@ public struct ValueBoxKey: Hashable, CustomStringConvertible, Comparable {
return string as String return string as String
} }
public var stringValue: String {
if let string = String(data: Data(bytes: self.memory, count: self.length), encoding: .utf8) {
return string
} else {
return "<unavailable>"
}
}
public var hashValue: Int { public var hashValue: Int {
var hash = 37 var hash = 37
let bytes = self.memory.assumingMemoryBound(to: Int8.self) let bytes = self.memory.assumingMemoryBound(to: Int8.self)

View File

@ -400,10 +400,10 @@ final class ViewTracker {
} }
} }
if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty { if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty || !transaction.currentUpdatedPeers.isEmpty {
for (mutableView, pipe) in self.chatListViews.copyItems() { for (mutableView, pipe) in self.chatListViews.copyItems() {
let context = MutableChatListViewReplayContext() let context = MutableChatListViewReplayContext()
if mutableView.replay(transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, context: context) { if mutableView.replay(transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, context: context) {
mutableView.complete(context: context, fetchEarlier: self.fetchEarlierChatEntries, fetchLater: self.fetchLaterChatEntries) mutableView.complete(context: context, fetchEarlier: self.fetchEarlierChatEntries, fetchLater: self.fetchLaterChatEntries)
mutableView.render(self.renderMessage, getPeer: { id in mutableView.render(self.renderMessage, getPeer: { id in
return self.getPeer(id) return self.getPeer(id)