diff --git a/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift b/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift index e7b706272..c5cd758df 100644 --- a/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiFileServerAPI.swift @@ -24,8 +24,8 @@ public final class LokiFileServerAPI : LokiDotNetAPI { /// Gets the device links associated with the given hex encoded public key from the /// server and stores and returns the valid ones. - public static func getDeviceLinks(associatedWith hexEncodedPublicKey: String) -> Promise> { - return getDeviceLinks(associatedWith: [ hexEncodedPublicKey ]) + public static func getDeviceLinks(associatedWith hexEncodedPublicKey: String, in transaction: YapDatabaseReadWriteTransaction? = nil) -> Promise> { + return getDeviceLinks(associatedWith: [ hexEncodedPublicKey ], in: transaction) } @objc(getDeviceLinksAssociatedWithHexEncodedPublicKeys:) @@ -35,7 +35,7 @@ public final class LokiFileServerAPI : LokiDotNetAPI { /// Gets the device links associated with the given hex encoded public keys from the /// server and stores and returns the valid ones. - public static func getDeviceLinks(associatedWith hexEncodedPublicKeys: Set) -> Promise> { + public static func getDeviceLinks(associatedWith hexEncodedPublicKeys: Set, in transaction: YapDatabaseReadWriteTransaction? = nil) -> Promise> { let hexEncodedPublicKeysDescription = "[ \(hexEncodedPublicKeys.joined(separator: ", ")) ]" print("[Loki] Getting device links for: \(hexEncodedPublicKeysDescription).") return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise> in @@ -88,8 +88,12 @@ public final class LokiFileServerAPI : LokiDotNetAPI { 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.setDeviceLinks(deviceLinks, in: transaction) + if let trans = transaction { + storage.setDeviceLinks(deviceLinks, in: trans) + } else { + storage.dbReadWriteConnection.readWrite { transaction in + storage.setDeviceLinks(deviceLinks, in: transaction) + } } // We have to wait for the device links to be stored because a lot of our logic relies // on them being in the database diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index 20451221c..6b22f113a 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -306,7 +306,7 @@ public extension MultiDeviceProtocol { } if timeSinceLastUpdate > deviceLinkUpdateInterval { let masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: hexEncodedPublicKey, in: transaction) ?? hexEncodedPublicKey - LokiFileServerAPI.getDeviceLinks(associatedWith: masterHexEncodedPublicKey).done(on: DispatchQueue.global()) { _ in + LokiFileServerAPI.getDeviceLinks(associatedWith: masterHexEncodedPublicKey, in: transaction as! YapDatabaseReadWriteTransaction).done(on: DispatchQueue.global()) { _ in getDestinations() lastDeviceLinkUpdate[hexEncodedPublicKey] = Date() }.catch(on: DispatchQueue.global()) { error in diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 8fb9f0caa..501b1f94f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1266,12 +1266,14 @@ NS_ASSUME_NONNULL_BEGIN // Loki: Update device links in a blocking way // FIXME: This is horrible for performance // FIXME: ======== + // FIX: Using the same transaction for write to avoid deadlock // The envelope source is set during UD decryption if ([ECKeyPair isValidHexEncodedPublicKeyWithCandidate:envelope.source] && dataMessage.publicChatInfo == nil) { // Handled in LokiPublicChatPoller for open group messages dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - [[LKMultiDeviceProtocol updateDeviceLinksIfNeededForHexEncodedPublicKey:envelope.source in:transaction].ensureOn(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() { + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + [[LKMultiDeviceProtocol updateDeviceLinksIfNeededForHexEncodedPublicKey:envelope.source in:transaction].ensureOn(queue, ^() { dispatch_semaphore_signal(semaphore); - }).catchOn(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(NSError *error) { + }).catchOn(queue, ^(NSError *error) { dispatch_semaphore_signal(semaphore); }) retainUntilComplete]; dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC));