From fbdab8ccb097d4ab16ad4ef472c57c27b46383d5 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 29 Apr 2020 15:59:27 +1000 Subject: [PATCH] Handle slave device message send failures --- .../Multi Device/MultiDeviceProtocol.swift | 38 +++++++++++++++++-- .../src/Messages/OWSMessageSend.swift | 10 ----- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index 38ec825d1..cd60fa71b 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -41,7 +41,21 @@ public final class MultiDeviceProtocol : NSObject { return !(message is DeviceLinkMessage) && !message.thread.isGroupThread() } - private static func sendMessage(_ messageSend: OWSMessageSend, to destination: MultiDeviceDestination, in transaction: YapDatabaseReadTransaction) { + private static func copy(_ messageSend: OWSMessageSend, for destination: MultiDeviceDestination, with seal: Resolver) -> OWSMessageSend { + var recipient: SignalRecipient! + storage.dbReadConnection.read { transaction in + recipient = SignalRecipient.getOrBuildUnsavedRecipient(forRecipientId: destination.hexEncodedPublicKey, transaction: transaction) + } + // TODO: Apparently it's okay that the thread, sender certificate, etc. don't get changed? + return OWSMessageSend(message: messageSend.message, thread: messageSend.thread, recipient: recipient, + senderCertificate: messageSend.senderCertificate, udAccess: messageSend.udAccess, localNumber: messageSend.localNumber, success: { + seal.fulfill(messageSend.thread as! TSContactThread) + }, failure: { error in + seal.reject(error) + }) + } + + private static func sendMessage(_ messageSend: OWSMessageSend, to destination: MultiDeviceDestination, in transaction: YapDatabaseReadTransaction) -> Promise { let (promise, seal) = Promise.pending() let message = messageSend.message let messageSender = SSKEnvironment.shared.messageSender @@ -50,7 +64,7 @@ public final class MultiDeviceProtocol : NSObject { let shouldSendAutoGeneratedFR = !thread.isContactFriend && !(message is FriendRequestMessage) && !(message is SessionRequestMessage) && !isSessionResetMessage && !(message is TypingIndicatorMessage) if !shouldSendAutoGeneratedFR { - let messageSendCopy = messageSend.copy(with: destination) + let messageSendCopy = copy(messageSend, for: destination, with: seal) messageSender.sendMessage(messageSendCopy) } else { DispatchQueue.main.async { @@ -76,6 +90,7 @@ public final class MultiDeviceProtocol : NSObject { } } } + return promise.map { _ in } } @objc(sendMessageToDestinationAndLinkedDevices:in:) @@ -92,16 +107,31 @@ public final class MultiDeviceProtocol : NSObject { print("[Loki] Sending \(type(of: message)) message using multi device routing.") let recipientID = messageSend.recipient.recipientId() getMultiDeviceDestinations(for: recipientID, in: transaction).done(on: OWSDispatch.sendingQueue()) { destinations in + var promises: [Promise] = [] let masterDestination = destinations.first { $0.isMaster } if let masterDestination = masterDestination { storage.dbReadConnection.read { transaction in - sendMessage(messageSend, to: masterDestination, in: transaction) + promises.append(sendMessage(messageSend, to: masterDestination, in: transaction)) } } let slaveDestinations = destinations.filter { !$0.isMaster } slaveDestinations.forEach { slaveDestination in storage.dbReadConnection.read { transaction in - sendMessage(messageSend, to: slaveDestination, in: transaction) + promises.append(sendMessage(messageSend, to: slaveDestination, in: transaction)) + } + } + when(resolved: promises).done(on: OWSDispatch.sendingQueue()) { results in + let errors = results.compactMap { result -> Error? in + if case Result.rejected(let error) = result { + return error + } else { + return nil + } + } + if errors.isEmpty { + messageSend.success() + } else { + messageSend.failure(errors.first!) } } }.catch(on: OWSDispatch.sendingQueue()) { error in diff --git a/SignalServiceKit/src/Messages/OWSMessageSend.swift b/SignalServiceKit/src/Messages/OWSMessageSend.swift index 00cbf59c2..b9d186947 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSend.swift +++ b/SignalServiceKit/src/Messages/OWSMessageSend.swift @@ -93,14 +93,4 @@ public class OWSMessageSend: NSObject { // We "fail over" to non-UD sends after auth errors sending via UD. disableUD() } - - public func copy(with destination: MultiDeviceProtocol.MultiDeviceDestination) -> OWSMessageSend { - var recipient: SignalRecipient! - OWSPrimaryStorage.shared().dbReadConnection.read { transaction in - recipient = SignalRecipient.getOrBuildUnsavedRecipient(forRecipientId: destination.hexEncodedPublicKey, transaction: transaction) - } - let success = destination.isMaster ? self.success : { } - let failure = destination.isMaster ? self.failure : { _ in } - return OWSMessageSend(message: message, thread: thread, recipient: recipient, senderCertificate: senderCertificate, udAccess: udAccess, localNumber: localNumber, success: success, failure: failure) - } }