diff --git a/Postbox.xcodeproj/project.pbxproj b/Postbox.xcodeproj/project.pbxproj index a4560a3242..07300e8560 100644 --- a/Postbox.xcodeproj/project.pbxproj +++ b/Postbox.xcodeproj/project.pbxproj @@ -212,6 +212,8 @@ D0BC386C1E3FCEE50044D6FE /* MultiplePeersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC386B1E3FCEE50044D6FE /* MultiplePeersView.swift */; }; D0BC38721E409E670044D6FE /* RenderedPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38711E409E670044D6FE /* RenderedPeer.swift */; }; D0BC38731E409E670044D6FE /* RenderedPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BC38711E409E670044D6FE /* RenderedPeer.swift */; }; + D0BE3034206026C800FBE6D8 /* MessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE3033206026C800FBE6D8 /* MessagesView.swift */; }; + D0BE3035206026C800FBE6D8 /* MessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE3033206026C800FBE6D8 /* MessagesView.swift */; }; D0BE38391E7C1FD4000079AF /* ItemCollectionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE38381E7C1FD4000079AF /* ItemCollectionInfoView.swift */; }; D0BE383A1E7C1FD4000079AF /* ItemCollectionInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BE38381E7C1FD4000079AF /* ItemCollectionInfoView.swift */; }; D0BEAF631E54B2FA00BD963D /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BEAF621E54B2FA00BD963D /* AccountManager.swift */; }; @@ -480,6 +482,7 @@ D0B844501DAC04FE005F29E1 /* PeerPresence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerPresence.swift; sourceTree = ""; }; D0BC386B1E3FCEE50044D6FE /* MultiplePeersView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplePeersView.swift; sourceTree = ""; }; D0BC38711E409E670044D6FE /* RenderedPeer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RenderedPeer.swift; sourceTree = ""; }; + D0BE3033206026C800FBE6D8 /* MessagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagesView.swift; sourceTree = ""; }; D0BE38381E7C1FD4000079AF /* ItemCollectionInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemCollectionInfoView.swift; sourceTree = ""; }; D0BEAF621E54B2FA00BD963D /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = ""; }; D0BEAF661E54B33900BD963D /* AccountRecord.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountRecord.swift; sourceTree = ""; }; @@ -840,6 +843,7 @@ D0C26D801FE41323004ABF18 /* ChatListGroupReferenceUnreadCounters.swift */, D04614322004F2CC00EC0EF2 /* LocalMessageTagsView.swift */, D0FC19542020CB7700FEDBB2 /* PeerGroupStateView.swift */, + D0BE3033206026C800FBE6D8 /* MessagesView.swift */, ); name = Views; sourceTree = ""; @@ -1215,6 +1219,7 @@ D073CE7B1DCBF3B4007511FD /* PeerNameIndexRepresentation.swift in Sources */, D073CE7D1DCBF3B4007511FD /* PeerPresence.swift in Sources */, D0C26D821FE41323004ABF18 /* ChatListGroupReferenceUnreadCounters.swift in Sources */, + D0BE3035206026C800FBE6D8 /* MessagesView.swift in Sources */, D0B4184C1D7DFE20004562A4 /* ContactPeerIdsView.swift in Sources */, D0DA44491E4C7D1E005FDCA7 /* PostboxAccess.swift in Sources */, D0B167211F9EAAA900976B40 /* OrderedList.swift in Sources */, @@ -1384,6 +1389,7 @@ D0DA44481E4C7D1E005FDCA7 /* PostboxAccess.swift in Sources */, D0B167201F9EAAA900976B40 /* OrderedList.swift in Sources */, D0FC19552020CB7700FEDBB2 /* PeerGroupStateView.swift in Sources */, + D0BE3034206026C800FBE6D8 /* MessagesView.swift in Sources */, D0C26D721FE2E7A8004ABF18 /* GroupFeedReadStateTable.swift in Sources */, D0943AF11FD99DCD001522CC /* GroupChatListInclusion.swift in Sources */, D0E3A7841B28AE0900A402D9 /* Peer.swift in Sources */, diff --git a/Postbox.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist b/Postbox.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist index 6e406df74a..ef8b19e937 100644 --- a/Postbox.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Postbox.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,7 +12,7 @@ PostboxMac.xcscheme orderHint - 4 + 5 PostboxTests.xcscheme diff --git a/Postbox/MessagesView.swift b/Postbox/MessagesView.swift new file mode 100644 index 0000000000..6948717e26 --- /dev/null +++ b/Postbox/MessagesView.swift @@ -0,0 +1,69 @@ +import Foundation + + +import Foundation + +final class MutableMessagesView: MutablePostboxView { + fileprivate let ids: Set + private let peerIds: Set + fileprivate var messages: [MessageId: Message] = [:] + + init(postbox: Postbox, ids: Set) { + self.ids = ids + self.peerIds = Set(ids.map { $0.peerId }) + for id in ids { + if let message = postbox.getMessage(id) { + self.messages[message.id] = message + } + } + } + + func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { + var updatedIds = Set() + for peerId in self.peerIds { + if let operations = transaction.currentOperationsByPeerId[peerId] { + for operation in operations { + switch operation { + case let .InsertMessage(message): + if self.ids.contains(message.id) { + updatedIds.insert(message.id) + } + case let .Remove(indices): + for index in indices { + if self.ids.contains(index.0.id) { + updatedIds.insert(index.0.id) + } + } + default: + break + } + } + } + } + if !updatedIds.isEmpty { + for id in updatedIds { + if let message = postbox.getMessage(id) { + self.messages[message.id] = message + } else { + self.messages.removeValue(forKey: id) + } + } + + return true + } else { + return false + } + } + + func immutableView() -> PostboxView { + return MessagesView(self) + } +} + +public final class MessagesView: PostboxView { + public var messages: [MessageId: Message] = [:] + + init(_ view: MutableMessagesView) { + self.messages = view.messages + } +} diff --git a/Postbox/Postbox.swift b/Postbox/Postbox.swift index 69302805c4..68103e0c81 100644 --- a/Postbox/Postbox.swift +++ b/Postbox/Postbox.swift @@ -28,6 +28,16 @@ public final class Modifier { self.postbox = postbox } + public func keychainEntryForKey(_ key: String) -> Data? { + assert(!self.disposed) + return self.postbox?.keychainTable.get(key) + } + + public func setKeychainEntry(_ value: Data, forKey key: String) { + assert(!self.disposed) + self.postbox?.keychainTable.set(key, value: value) + } + public func addMessages(_ messages: [StoreMessage], location: AddMessagesLocation) -> [Int64: MessageId] { assert(!self.disposed) if let postbox = self.postbox { @@ -2117,17 +2127,35 @@ public final class Postbox { return result } - #if DEBUG - private let debugIsInTransactionValue = Atomic(value: false) - public var debugIsInTransaction: Bool { - return self.debugIsInTransactionValue.with { $0 } + private let canBeginTransactionsValue = Atomic(value: true) + public func setCanBeginTransactions(_ value: Bool) { + self.queue.async { + let previous = self.canBeginTransactionsValue.swap(value) + if previous != value && value { + let fs = self.queuedInternalTransactions.swap([]) + for f in fs { + f() + } + } + } + } + + private var queuedInternalTransactions = Atomic<[() -> Void]>(value: []) + + private func beginInternalTransaction(ignoreDisabled: Bool = false, _ f: @escaping () -> Void) { + assert(self.queue.isCurrent()) + if ignoreDisabled || self.canBeginTransactionsValue.with({ $0 }) { + f() + } else { + let _ = self.queuedInternalTransactions.modify { fs in + var fs = fs + fs.append(f) + return fs + } + } } - #endif private func internalTransaction(_ f: (Modifier) -> T) -> (result: T, updatedTransactionStateVersion: Int64?, updatedMasterClientId: Int64?) { - #if DEBUG - let _ = self.debugIsInTransactionValue.swap(true) - #endif self.valueBox.begin() self.afterBegin() let modifier = Modifier(postbox: self) @@ -2135,9 +2163,6 @@ public final class Postbox { modifier.disposed = true let (updatedTransactionState, updatedMasterClientId) = self.beforeCommit() self.valueBox.commit() - #if DEBUG - let _ = self.debugIsInTransactionValue.swap(false) - #endif if let currentUpdatedState = self.currentUpdatedState { self.statePipe.putNext(currentUpdatedState) @@ -2152,16 +2177,18 @@ public final class Postbox { let disposable = MetaDisposable() let f: () -> Void = { - let (_, updatedTransactionState, updatedMasterClientId) = self.internalTransaction({ modifier in - disposable.set(f(subscriber, modifier)) - }) - - if updatedTransactionState != nil || updatedMasterClientId != nil { - //self.pipeNotifier.notify() - } - - if let updatedMasterClientId = updatedMasterClientId { - self.masterClientId.set(.single(updatedMasterClientId)) + self.beginInternalTransaction { + let (_, updatedTransactionState, updatedMasterClientId) = self.internalTransaction({ modifier in + disposable.set(f(subscriber, modifier)) + }) + + if updatedTransactionState != nil || updatedMasterClientId != nil { + //self.pipeNotifier.notify() + } + + if let updatedMasterClientId = updatedMasterClientId { + self.masterClientId.set(.single(updatedMasterClientId)) + } } } if userInteractive { @@ -2174,23 +2201,25 @@ public final class Postbox { } } - public func modify(userInteractive: Bool = false, _ f: @escaping(Modifier) -> T) -> Signal { + public func modify(userInteractive: Bool = false, ignoreDisabled: Bool = false, _ f: @escaping(Modifier) -> T) -> Signal { return Signal { subscriber in let f: () -> Void = { - let (result, updatedTransactionState, updatedMasterClientId) = self.internalTransaction({ modifier in - return f(modifier) + self.beginInternalTransaction(ignoreDisabled: ignoreDisabled, { + let (result, updatedTransactionState, updatedMasterClientId) = self.internalTransaction({ modifier in + return f(modifier) + }) + + if updatedTransactionState != nil || updatedMasterClientId != nil { + //self.pipeNotifier.notify() + } + + if let updatedMasterClientId = updatedMasterClientId { + self.masterClientId.set(.single(updatedMasterClientId)) + } + + subscriber.putNext(result) + subscriber.putCompletion() }) - - if updatedTransactionState != nil || updatedMasterClientId != nil { - //self.pipeNotifier.notify() - } - - if let updatedMasterClientId = updatedMasterClientId { - self.masterClientId.set(.single(updatedMasterClientId)) - } - - subscriber.putNext(result) - subscriber.putCompletion() } if userInteractive { self.queue.justDispatchWithQoS(qos: DispatchQoS.userInteractive, f) diff --git a/Postbox/Views.swift b/Postbox/Views.swift index 6bdfae4b40..baf87f5912 100644 --- a/Postbox/Views.swift +++ b/Postbox/Views.swift @@ -23,6 +23,7 @@ public enum PostboxViewKey: Hashable { case chatListTopPeers(groupId: PeerGroupId) case groupFeedReadStateSyncOperations case localMessageTag(LocalMessageTags) + case messages(Set) public var hashValue: Int { switch self { @@ -70,6 +71,8 @@ public enum PostboxViewKey: Hashable { return 9 case let .localMessageTag(tag): return tag.hashValue + case .messages: + return 10 } } @@ -207,6 +210,12 @@ public enum PostboxViewKey: Hashable { } else { return false } + case let .messages(ids): + if case .messages(ids) = rhs { + return true + } else { + return false + } } } } @@ -257,5 +266,7 @@ func postboxViewForKey(postbox: Postbox, key: PostboxViewKey) -> MutablePostboxV return MutableGroupFeedReadStateSyncOperationsView(postbox: postbox) case let .localMessageTag(tag): return MutableLocalMessageTagsView(postbox: postbox, tag: tag) + case let .messages(ids): + return MutableMessagesView(postbox: postbox, ids: ids) } }