diff --git a/Signal/src/Loki/Shelved/LokiRSSFeedPoller.swift b/Signal/src/Loki/Shelved/LokiRSSFeedPoller.swift index 62a0d0341..f29e3a884 100644 --- a/Signal/src/Loki/Shelved/LokiRSSFeedPoller.swift +++ b/Signal/src/Loki/Shelved/LokiRSSFeedPoller.swift @@ -63,7 +63,7 @@ public final class LokiRSSFeedPoller : NSObject { envelope.setSource(NSLocalizedString("Loki", comment: "")) envelope.setSourceDevice(OWSDevicePrimaryDeviceId) envelope.setContent(try! content.build().serializedData()) - OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction, serverID: 0) } } diff --git a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift index b35c590a6..5aa389ca1 100644 --- a/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift +++ b/Signal/src/Loki/View Controllers/DeviceLinkingModal.swift @@ -186,7 +186,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { SSKEnvironment.shared.messageSender.send(linkingAuthorizationMessage, success: { let storage = OWSPrimaryStorage.shared() let slaveHexEncodedPublicKey = deviceLink.slave.hexEncodedPublicKey - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in let thread = TSContactThread.getOrCreateThread(withContactId: slaveHexEncodedPublicKey, transaction: transaction) thread.save(with: transaction) } @@ -196,7 +196,7 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { let _ = SSKEnvironment.shared.syncManager.syncAllContacts() } let _ = SSKEnvironment.shared.syncManager.syncAllOpenGroups() - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in storage.setFriendRequestStatus(.friends, for: slaveHexEncodedPublicKey, transaction: transaction) } DispatchQueue.main.async { @@ -251,9 +251,8 @@ final class DeviceLinkingModal : Modal, DeviceLinkingSessionDelegate { session.markLinkingRequestAsProcessed() // Only relevant in master mode delegate?.handleDeviceLinkingModalDismissed() // Only relevant in slave mode if let deviceLink = deviceLink { - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - storage.removePreKeyBundle(forContact: deviceLink.slave.hexEncodedPublicKey, transaction: transaction) + try! Storage.syncWrite { transaction in + OWSPrimaryStorage.shared().removePreKeyBundle(forContact: deviceLink.slave.hexEncodedPublicKey, transaction: transaction) } } dismiss(animated: true, completion: nil) diff --git a/Signal/src/Loki/View Controllers/DeviceLinksVC.swift b/Signal/src/Loki/View Controllers/DeviceLinksVC.swift index 167a72303..85554b380 100644 --- a/Signal/src/Loki/View Controllers/DeviceLinksVC.swift +++ b/Signal/src/Loki/View Controllers/DeviceLinksVC.swift @@ -146,14 +146,14 @@ final class DeviceLinksVC : BaseVC, UITableViewDataSource, UITableViewDelegate, let unlinkDeviceMessage = UnlinkDeviceMessage(thread: thread) SSKEnvironment.shared.messageSender.send(unlinkDeviceMessage, success: { let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in storage.removePreKeyBundle(forContact: linkedDeviceHexEncodedPublicKey, transaction: transaction) storage.deleteAllSessions(forContact: linkedDeviceHexEncodedPublicKey, protocolContext: transaction) } }, failure: { _ in print("[Loki] Failed to send unlink device message.") let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in storage.removePreKeyBundle(forContact: linkedDeviceHexEncodedPublicKey, transaction: transaction) storage.deleteAllSessions(forContact: linkedDeviceHexEncodedPublicKey, protocolContext: transaction) } diff --git a/Signal/src/Loki/View Controllers/JoinPublicChatVC.swift b/Signal/src/Loki/View Controllers/JoinPublicChatVC.swift index 149ca58c8..9b0ad0188 100644 --- a/Signal/src/Loki/View Controllers/JoinPublicChatVC.swift +++ b/Signal/src/Loki/View Controllers/JoinPublicChatVC.swift @@ -135,7 +135,7 @@ final class JoinPublicChatVC : BaseVC, UIPageViewControllerDataSource, UIPageVie let urlAsString = url.absoluteString let displayName = OWSProfileManager.shared().localProfileName() // TODO: Profile picture & profile key - OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.removeObject(forKey: "\(urlAsString).\(channelID)", inCollection: LokiPublicChatAPI.lastMessageServerIDCollection) transaction.removeObject(forKey: "\(urlAsString).\(channelID)", inCollection: LokiPublicChatAPI.lastDeletionServerIDCollection) } diff --git a/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift index 4cf2d374d..800758a59 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI+SwarmAPI.swift @@ -53,12 +53,9 @@ public extension LokiAPI { } }.done(on: DispatchQueue.global()) { snode in seal.fulfill(snode) - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - print("[Loki] Persisting snode pool to database.") - storage.setSnodePool(LokiAPI.snodePool, in: transaction) - } + try! Storage.syncWrite { transaction in + print("[Loki] Persisting snode pool to database.") + storage.setSnodePool(LokiAPI.snodePool, in: transaction) } }.catch(on: DispatchQueue.global()) { error in print("[Loki] Failed to contact seed node at: \(target).") @@ -90,12 +87,8 @@ public extension LokiAPI { parseTargets(from: $0) }.get { swarm in swarmCache[hexEncodedPublicKey] = swarm - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction) - } + try! Storage.syncWrite { transaction in + storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction) } } } @@ -108,12 +101,8 @@ public extension LokiAPI { internal static func dropSnodeFromSnodePool(_ target: LokiAPITarget) { LokiAPI.snodePool.remove(target) - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - storage.dropSnodeFromSnodePool(target, in: transaction) - } + try! Storage.syncWrite { transaction in + storage.dropSnodeFromSnodePool(target, in: transaction) } } @@ -122,12 +111,8 @@ public extension LokiAPI { if var swarm = swarm, let index = swarm.firstIndex(of: target) { swarm.remove(at: index) LokiAPI.swarmCache[hexEncodedPublicKey] = swarm - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction) - } + try! Storage.syncWrite { transaction in + storage.setSwarm(swarm, for: hexEncodedPublicKey, in: transaction) } } } @@ -135,11 +120,8 @@ public extension LokiAPI { // MARK: Public API @objc public static func clearSnodePool() { snodePool.removeAll() - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - storage.clearSnodePool(in: transaction) - } + try! Storage.syncWrite { transaction in + storage.clearSnodePool(in: transaction) } } diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index 4bd85fc5b..e8cdd58e9 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -194,14 +194,14 @@ public final class LokiAPI : NSObject { var result: String? = nil // Uses a read/write connection because getting the last message hash value also removes expired messages as needed // TODO: This shouldn't be the case; a getter shouldn't have an unexpected side effect - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in result = storage.getLastMessageHash(forSnode: target.address, transaction: transaction) } return result } private static func setLastMessageHashValue(for target: LokiAPITarget, hashValue: String, expirationDate: UInt64) { - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in storage.setLastMessageHash(forSnode: target.address, hash: hashValue, expiresAt: expirationDate, transaction: transaction) } } @@ -218,7 +218,7 @@ public final class LokiAPI : NSObject { } private static func setReceivedMessageHashValues(to receivedMessageHashValues: Set) { - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.setObject(receivedMessageHashValues, forKey: receivedMessageHashValuesKey, inCollection: receivedMessageHashValuesCollection) } } diff --git a/SignalServiceKit/src/Loki/API/LokiDotNetAPI.swift b/SignalServiceKit/src/Loki/API/LokiDotNetAPI.swift index 08071be7f..22cc15947 100644 --- a/SignalServiceKit/src/Loki/API/LokiDotNetAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiDotNetAPI.swift @@ -38,11 +38,8 @@ public class LokiDotNetAPI : NSObject { return Promise.value(token) } else { return requestNewAuthToken(for: server).then(on: DispatchQueue.global()) { submitAuthToken($0, for: server) }.map(on: DispatchQueue.global()) { token in - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - setAuthToken(for: server, to: token, in: transaction) - } + try! Storage.syncWrite { transaction in + setAuthToken(for: server, to: token, in: transaction) } return token } @@ -54,11 +51,8 @@ public class LokiDotNetAPI : NSObject { } public static func clearAuthToken(for server: String) { - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - transaction.removeObject(forKey: server, inCollection: authTokenCollection) - } + try! Storage.syncWrite { transaction in + transaction.removeObject(forKey: server, inCollection: authTokenCollection) } } diff --git a/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift b/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift index f50b18dfc..d0eabc4dc 100644 --- a/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift @@ -81,15 +81,7 @@ public final class LokiFileServerAPI : LokiDotNetAPI { } }) }.map(on: DispatchQueue.global()) { deviceLinks in - storage.cacheDeviceLinks(deviceLinks) - /* - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - storage.setDeviceLinks(deviceLinks, in: transaction) - } - } - */ + storage.setDeviceLinks(deviceLinks) return deviceLinks } }.handlingInvalidAuthTokenIfNeeded(for: server) @@ -122,16 +114,8 @@ public final class LokiFileServerAPI : LokiDotNetAPI { deviceLinks = storage.getDeviceLinks(for: getUserHexEncodedPublicKey(), in: transaction) } deviceLinks.insert(deviceLink) - return setDeviceLinks(deviceLinks).then(on: LokiAPI.workQueue) { _ -> Promise in - let (promise, seal) = Promise.pending() - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - storage.addDeviceLink(deviceLink, in: transaction) - } - seal.fulfill(()) - } - return promise + return setDeviceLinks(deviceLinks).map(on: LokiAPI.workQueue) { _ in + storage.addDeviceLink(deviceLink) } } @@ -142,16 +126,8 @@ public final class LokiFileServerAPI : LokiDotNetAPI { deviceLinks = storage.getDeviceLinks(for: getUserHexEncodedPublicKey(), in: transaction) } deviceLinks.remove(deviceLink) - return setDeviceLinks(deviceLinks).then(on: LokiAPI.workQueue) { _ -> Promise in - let (promise, seal) = Promise.pending() - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - storage.removeDeviceLink(deviceLink, in: transaction) - } - seal.fulfill(()) - } - return promise + return setDeviceLinks(deviceLinks).map(on: LokiAPI.workQueue) { _ in + storage.removeDeviceLink(deviceLink) } } diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 585a1b085..9ed5fb6f7 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -123,13 +123,11 @@ public enum OnionRequestAPI { } }.map(on: LokiAPI.workQueue) { paths in OnionRequestAPI.paths = paths - // Dispatch async on the main queue to avoid nested write transactions + try! Storage.syncWrite { transaction in + print("[Loki] Persisting onion request paths to database.") + OWSPrimaryStorage.shared().setOnionRequestPaths(paths, in: transaction) + } DispatchQueue.main.async { - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - print("[Loki] Persisting onion request paths to database.") - storage.setOnionRequestPaths(paths, in: transaction) - } NotificationCenter.default.post(name: .pathsBuilt, object: nil) } return paths @@ -165,12 +163,8 @@ public enum OnionRequestAPI { private static func dropAllPaths() { paths.removeAll() - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - storage.clearOnionRequestPaths(in: transaction) - } + try! Storage.syncWrite { transaction in + OWSPrimaryStorage.shared().clearOnionRequestPaths(in: transaction) } } diff --git a/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatAPI.swift b/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatAPI.swift index d58ce8356..815002664 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatAPI.swift @@ -37,13 +37,13 @@ public final class LokiPublicChatAPI : LokiDotNetAPI { } private static func setLastMessageServerID(for group: UInt64, on server: String, to newValue: UInt64) { - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.setObject(newValue, forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection) } } private static func removeLastMessageServerID(for group: UInt64, on server: String) { - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.removeObject(forKey: "\(server).\(group)", inCollection: lastMessageServerIDCollection) } } @@ -57,13 +57,13 @@ public final class LokiPublicChatAPI : LokiDotNetAPI { } private static func setLastDeletionServerID(for group: UInt64, on server: String, to newValue: UInt64) { - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.setObject(newValue, forKey: "\(server).\(group)", inCollection: lastDeletionServerIDCollection) } } private static func removeLastDeletionServerID(for group: UInt64, on server: String) { - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.removeObject(forKey: "\(server).\(group)", inCollection: lastDeletionServerIDCollection) } } @@ -271,7 +271,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI { print("[Loki] Couldn't parse display names for users: \(hexEncodedPublicKeys) from: \(rawResponse).") throw LokiDotNetAPIError.parsingFailed } - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in data.forEach { data in guard let user = data["user"] as? JSON, let hexEncodedPublicKey = user["username"] as? String, let rawDisplayName = user["name"] as? String else { return } let endIndex = hexEncodedPublicKey.endIndex @@ -355,7 +355,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI { throw LokiDotNetAPIError.parsingFailed } let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in storage.setUserCount(memberCount, forPublicChatWithID: "\(server).\(channel)", in: transaction) } // TODO: Use this to update open group names as needed diff --git a/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatManager.swift b/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatManager.swift index 1d1bf5e0e..a04e20975 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatManager.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatManager.swift @@ -71,7 +71,7 @@ public final class LokiPublicChatManager : NSObject { let model = TSGroupModel(title: chat.displayName, memberIds: [userHexEncodedPublicKey!, chat.server], image: nil, groupId: LKGroupUtilities.getEncodedOpenGroupIDAsData(chat.id), groupType: .openGroup, adminIds: []) // Store the group chat mapping - self.storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in let thread = TSGroupThread.getOrCreateThread(with: model, transaction: transaction) // Save the group chat @@ -118,7 +118,7 @@ public final class LokiPublicChatManager : NSObject { } // Remove the chat from the db - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in LokiDatabaseUtilities.removePublicChat(for: threadId, in: transaction) } diff --git a/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatPoller.swift b/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatPoller.swift index 974eb814b..9182ce78d 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatPoller.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/LokiPublicChatPoller.swift @@ -163,7 +163,7 @@ public final class LokiPublicChatPoller : NSObject { envelope.setSource(senderHexEncodedPublicKey) envelope.setSourceDevice(OWSDevicePrimaryDeviceId) envelope.setContent(try! content.build().serializedData()) - storage.dbReadWriteConnection.readWrite { transaction in + try! Storage.syncWrite { transaction in transaction.setObject(senderDisplayName, forKey: senderHexEncodedPublicKey, inCollection: publicChat.id) let messageServerID = message.serverID SSKEnvironment.shared.messageManager.throws_processEnvelope(try! envelope.build(), plaintextData: try! content.build().serializedData(), wasReceivedByUD: false, transaction: transaction, serverID: messageServerID ?? 0) @@ -213,9 +213,8 @@ public final class LokiPublicChatPoller : NSObject { private func pollForDeletedMessages() { let publicChat = self.publicChat let _ = LokiPublicChatAPI.getDeletedMessageServerIDs(for: publicChat.channel, on: publicChat.server).done(on: DispatchQueue.global()) { deletedMessageServerIDs in - let storage = OWSPrimaryStorage.shared() - storage.dbReadWriteConnection.readWrite { transaction in - let deletedMessageIDs = deletedMessageServerIDs.compactMap { storage.getIDForMessage(withServerID: UInt($0), in: transaction) } + try! Storage.syncWrite { transaction in + let deletedMessageIDs = deletedMessageServerIDs.compactMap { OWSPrimaryStorage.shared().getIDForMessage(withServerID: UInt($0), in: transaction) } deletedMessageIDs.forEach { messageID in TSMessage.fetch(uniqueId: messageID)?.remove(with: transaction) } diff --git a/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.swift b/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.swift index c69a996a5..f4d07f4ab 100644 --- a/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.swift +++ b/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.swift @@ -4,22 +4,20 @@ public extension OWSPrimaryStorage { // MARK: - Snode Pool - private static let snodePoolCollection = "LokiSnodePoolCollection" - public func setSnodePool(_ snodePool: Set, in transaction: YapDatabaseReadWriteTransaction) { clearSnodePool(in: transaction) snodePool.forEach { snode in - transaction.setObject(snode, forKey: snode.description, inCollection: OWSPrimaryStorage.snodePoolCollection) + transaction.setObject(snode, forKey: snode.description, inCollection: Storage.snodePoolCollection) } } public func clearSnodePool(in transaction: YapDatabaseReadWriteTransaction) { - transaction.removeAllObjects(inCollection: OWSPrimaryStorage.snodePoolCollection) + transaction.removeAllObjects(inCollection: Storage.snodePoolCollection) } public func getSnodePool(in transaction: YapDatabaseReadTransaction) -> Set { var result: Set = [] - transaction.enumerateKeysAndObjects(inCollection: OWSPrimaryStorage.snodePoolCollection) { _, object, _ in + transaction.enumerateKeysAndObjects(inCollection: Storage.snodePoolCollection) { _, object, _ in guard let snode = object as? LokiAPITarget else { return } result.insert(snode) } @@ -27,33 +25,29 @@ public extension OWSPrimaryStorage { } public func dropSnodeFromSnodePool(_ snode: LokiAPITarget, in transaction: YapDatabaseReadWriteTransaction) { - transaction.removeObject(forKey: snode.description, inCollection: OWSPrimaryStorage.snodePoolCollection) + transaction.removeObject(forKey: snode.description, inCollection: Storage.snodePoolCollection) } // MARK: - Swarm - private func getSwarmCollection(for publicKey: String) -> String { - return "LokiSwarmCollection-\(publicKey)" - } - public func setSwarm(_ swarm: [Snode], for publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { print("[Loki] Caching swarm for: \(publicKey).") clearSwarm(for: publicKey, in: transaction) - let collection = getSwarmCollection(for: publicKey) + let collection = Storage.getSwarmCollection(for: publicKey) swarm.forEach { snode in transaction.setObject(snode, forKey: snode.description, inCollection: collection) } } public func clearSwarm(for publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { - let collection = getSwarmCollection(for: publicKey) + let collection = Storage.getSwarmCollection(for: publicKey) transaction.removeAllObjects(inCollection: collection) } public func getSwarm(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> [Snode] { var result: [Snode] = [] - let collection = getSwarmCollection(for: publicKey) + let collection = Storage.getSwarmCollection(for: publicKey) transaction.enumerateKeysAndObjects(inCollection: collection) { _, object, _ in guard let snode = object as? Snode else { return } result.append(snode) @@ -64,15 +58,13 @@ public extension OWSPrimaryStorage { // MARK: - Onion Request Paths - private static let onionRequestPathCollection = "LokiOnionRequestPathCollection" - public func setOnionRequestPaths(_ paths: [OnionRequestAPI.Path], in transaction: YapDatabaseReadWriteTransaction) { // FIXME: This is a bit of a dirty approach that assumes 2 paths of length 3 each. We should do better than this. guard paths.count == 2 else { return } let path0 = paths[0] let path1 = paths[1] guard path0.count == 3, path1.count == 3 else { return } - let collection = OWSPrimaryStorage.onionRequestPathCollection + let collection = Storage.onionRequestPathCollection transaction.setObject(path0[0], forKey: "0-0", inCollection: collection) transaction.setObject(path0[1], forKey: "0-1", inCollection: collection) transaction.setObject(path0[2], forKey: "0-2", inCollection: collection) @@ -82,7 +74,7 @@ public extension OWSPrimaryStorage { } public func getOnionRequestPaths(in transaction: YapDatabaseReadTransaction) -> [OnionRequestAPI.Path] { - let collection = OWSPrimaryStorage.onionRequestPathCollection + let collection = Storage.onionRequestPathCollection guard let path0Snode0 = transaction.object(forKey: "0-0", inCollection: collection) as? LokiAPITarget, let path0Snode1 = transaction.object(forKey: "0-1", inCollection: collection) as? LokiAPITarget, @@ -94,20 +86,18 @@ public extension OWSPrimaryStorage { } public func clearOnionRequestPaths(in transaction: YapDatabaseReadWriteTransaction) { - transaction.removeAllObjects(inCollection: OWSPrimaryStorage.onionRequestPathCollection) + transaction.removeAllObjects(inCollection: Storage.onionRequestPathCollection) } // MARK: - Session Requests - private static let sessionRequestTimestampCollection = "LokiSessionRequestTimestampCollection" - public func setSessionRequestTimestamp(for publicKey: String, to timestamp: Date, in transaction: YapDatabaseReadWriteTransaction) { - transaction.setDate(timestamp, forKey: publicKey, inCollection: OWSPrimaryStorage.sessionRequestTimestampCollection) + transaction.setDate(timestamp, forKey: publicKey, inCollection: Storage.sessionRequestTimestampCollection) } public func getSessionRequestTimestamp(for publicKey: String, in transaction: YapDatabaseReadTransaction) -> Date? { - transaction.date(forKey: publicKey, inCollection: OWSPrimaryStorage.sessionRequestTimestampCollection) + transaction.date(forKey: publicKey, inCollection: Storage.sessionRequestTimestampCollection) } @@ -115,23 +105,15 @@ public extension OWSPrimaryStorage { // MARK: - Multi Device private static var deviceLinkCache: Set = [] - private func getDeviceLinkCollection(for masterHexEncodedPublicKey: String) -> String { - return "LokiDeviceLinkCollection-\(masterHexEncodedPublicKey)" - } - - public func cacheDeviceLinks(_ deviceLinks: Set) { - OWSPrimaryStorage.deviceLinkCache.formUnion(deviceLinks) + public func setDeviceLinks(_ deviceLinks: Set) { + deviceLinks.forEach { addDeviceLink($0) } } - public func setDeviceLinks(_ deviceLinks: Set, in transaction: YapDatabaseReadWriteTransaction) { - deviceLinks.forEach { addDeviceLink($0, in: transaction) } - } - - public func addDeviceLink(_ deviceLink: DeviceLink, in transaction: YapDatabaseReadWriteTransaction) { + public func addDeviceLink(_ deviceLink: DeviceLink) { OWSPrimaryStorage.deviceLinkCache.insert(deviceLink) } - public func removeDeviceLink(_ deviceLink: DeviceLink, in transaction: YapDatabaseReadWriteTransaction) { + public func removeDeviceLink(_ deviceLink: DeviceLink) { OWSPrimaryStorage.deviceLinkCache.remove(deviceLink) } @@ -150,13 +132,11 @@ public extension OWSPrimaryStorage { // MARK: - Open Groups - private static let openGroupUserCountCollection = "LokiPublicChatUserCountCollection" - public func getUserCount(for publicChat: LokiPublicChat, in transaction: YapDatabaseReadTransaction) -> Int? { - return transaction.object(forKey: publicChat.id, inCollection: OWSPrimaryStorage.openGroupUserCountCollection) as? Int + return transaction.object(forKey: publicChat.id, inCollection: Storage.openGroupUserCountCollection) as? Int } public func setUserCount(_ userCount: Int, forPublicChatWithID publicChatID: String, in transaction: YapDatabaseReadWriteTransaction) { - transaction.setObject(userCount, forKey: publicChatID, inCollection: OWSPrimaryStorage.openGroupUserCountCollection) + transaction.setObject(userCount, forKey: publicChatID, inCollection: Storage.openGroupUserCountCollection) } } diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index b1e740029..4a944c6b8 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -62,12 +62,9 @@ public final class MultiDeviceProtocol : NSObject { } else if let thread = TSContactThread.getWithContactId(destination.hexEncodedPublicKey, transaction: transaction) { threadPromiseSeal.fulfill(thread) } else { - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - let thread = TSContactThread.getOrCreateThread(withContactId: destination.hexEncodedPublicKey, transaction: transaction) - threadPromiseSeal.fulfill(thread) - } + Storage.write { transaction in + let thread = TSContactThread.getOrCreateThread(withContactId: destination.hexEncodedPublicKey, transaction: transaction) + threadPromiseSeal.fulfill(thread) } } return threadPromise.then(on: OWSDispatch.sendingQueue()) { thread -> Promise in @@ -81,13 +78,10 @@ public final class MultiDeviceProtocol : NSObject { let messageSendCopy = copy(messageSend, for: destination, with: seal) messageSender.sendMessage(messageSendCopy) } else { - // Dispatch async on the main queue to avoid nested write transactions - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - getAutoGeneratedMultiDeviceFRMessageSend(for: destination.hexEncodedPublicKey, in: transaction, seal: seal) - .done(on: OWSDispatch.sendingQueue()) { autoGeneratedFRMessageSend in - messageSender.sendMessage(autoGeneratedFRMessageSend) - } + Storage.write { transaction in + getAutoGeneratedMultiDeviceFRMessageSend(for: destination.hexEncodedPublicKey, in: transaction, seal: seal) + .done(on: OWSDispatch.sendingQueue()) { autoGeneratedFRMessageSend in + messageSender.sendMessage(autoGeneratedFRMessageSend) } } } diff --git a/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift index d34af79aa..2c9afcc96 100644 --- a/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift @@ -141,14 +141,12 @@ public final class SessionManagementProtocol : NSObject { @objc(repairSessionIfNeededForMessage:to:) public static func repairSessionIfNeeded(for message: TSOutgoingMessage, to hexEncodedPublicKey: String) { guard (message.thread as? TSGroupThread)?.groupModel.groupType == .closedGroup else { return } - DispatchQueue.main.async { - storage.dbReadWriteConnection.readWrite { transaction in - let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction) - let sessionRequestMessage = SessionRequestMessage(thread: thread) - storage.setSessionRequestTimestamp(for: hexEncodedPublicKey, to: Date(), in: transaction) - let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue - messageSenderJobQueue.add(message: sessionRequestMessage, transaction: transaction) - } + Storage.write { transaction in + let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction) + let sessionRequestMessage = SessionRequestMessage(thread: thread) + storage.setSessionRequestTimestamp(for: hexEncodedPublicKey, to: Date(), in: transaction) + let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue + messageSenderJobQueue.add(message: sessionRequestMessage, transaction: transaction) } } @@ -205,7 +203,7 @@ public final class SessionManagementProtocol : NSObject { closedGroupMembers.formUnion(group.groupModel.groupMemberIds) } LokiFileServerAPI.getDeviceLinks(associatedWith: closedGroupMembers).ensure { - storage.dbReadWriteConnection.readWrite { transaction in + Storage.write { transaction in let validHEPKs = closedGroupMembers.flatMap { LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: $0, in: transaction) }