|
|
|
@ -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<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 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<Void>] = []
|
|
|
|
|
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
|
|
|
|
|