Handle slave device message send failures

pull/176/head
nielsandriesse 5 years ago
parent 739cb1b6ab
commit fbdab8ccb0

@ -41,7 +41,21 @@ public final class MultiDeviceProtocol : NSObject {
return !(message is DeviceLinkMessage) && !message.thread.isGroupThread() 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<TSContactThread>) -> 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<Void> {
let (promise, seal) = Promise<TSContactThread>.pending() let (promise, seal) = Promise<TSContactThread>.pending()
let message = messageSend.message let message = messageSend.message
let messageSender = SSKEnvironment.shared.messageSender let messageSender = SSKEnvironment.shared.messageSender
@ -50,7 +64,7 @@ public final class MultiDeviceProtocol : NSObject {
let shouldSendAutoGeneratedFR = !thread.isContactFriend && !(message is FriendRequestMessage) let shouldSendAutoGeneratedFR = !thread.isContactFriend && !(message is FriendRequestMessage)
&& !(message is SessionRequestMessage) && !isSessionResetMessage && !(message is TypingIndicatorMessage) && !(message is SessionRequestMessage) && !isSessionResetMessage && !(message is TypingIndicatorMessage)
if !shouldSendAutoGeneratedFR { if !shouldSendAutoGeneratedFR {
let messageSendCopy = messageSend.copy(with: destination) let messageSendCopy = copy(messageSend, for: destination, with: seal)
messageSender.sendMessage(messageSendCopy) messageSender.sendMessage(messageSendCopy)
} else { } else {
DispatchQueue.main.async { DispatchQueue.main.async {
@ -76,6 +90,7 @@ public final class MultiDeviceProtocol : NSObject {
} }
} }
} }
return promise.map { _ in }
} }
@objc(sendMessageToDestinationAndLinkedDevices:in:) @objc(sendMessageToDestinationAndLinkedDevices:in:)
@ -92,16 +107,31 @@ public final class MultiDeviceProtocol : NSObject {
print("[Loki] Sending \(type(of: message)) message using multi device routing.") print("[Loki] Sending \(type(of: message)) message using multi device routing.")
let recipientID = messageSend.recipient.recipientId() let recipientID = messageSend.recipient.recipientId()
getMultiDeviceDestinations(for: recipientID, in: transaction).done(on: OWSDispatch.sendingQueue()) { destinations in getMultiDeviceDestinations(for: recipientID, in: transaction).done(on: OWSDispatch.sendingQueue()) { destinations in
var promises: [Promise<Void>] = []
let masterDestination = destinations.first { $0.isMaster } let masterDestination = destinations.first { $0.isMaster }
if let masterDestination = masterDestination { if let masterDestination = masterDestination {
storage.dbReadConnection.read { transaction in 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 } let slaveDestinations = destinations.filter { !$0.isMaster }
slaveDestinations.forEach { slaveDestination in slaveDestinations.forEach { slaveDestination in
storage.dbReadConnection.read { transaction 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 }.catch(on: OWSDispatch.sendingQueue()) { error in

@ -93,14 +93,4 @@ public class OWSMessageSend: NSObject {
// We "fail over" to non-UD sends after auth errors sending via UD. // We "fail over" to non-UD sends after auth errors sending via UD.
disableUD() 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)
}
} }

Loading…
Cancel
Save