diff --git a/FlowCrypt/Controllers/Compose/ComposeViewController.swift b/FlowCrypt/Controllers/Compose/ComposeViewController.swift index 880886a46..71e8b1d27 100644 --- a/FlowCrypt/Controllers/Compose/ComposeViewController.swift +++ b/FlowCrypt/Controllers/Compose/ComposeViewController.swift @@ -6,6 +6,7 @@ import AsyncDisplayKit import FlowCryptCommon import FlowCryptUI import Promises +import Combine final class ComposeViewController: TableNodeViewController { struct Recipient { @@ -44,6 +45,13 @@ final class ComposeViewController: TableNodeViewController { case subject, subjectDivider, text } + private enum SendMessageError: Error { + case internalError(String) + case missedSender + case noPubKeyForRecipient + } + + private var cancellable = Set() private let messageSender: MessageGateway private let notificationCenter: NotificationCenter private let dataService: DataServiceType & KeyDataServiceType @@ -111,6 +119,8 @@ final class ComposeViewController: TableNodeViewController { // temporary disable search contacts - https://github.com/FlowCrypt/flowcrypt-ios/issues/217 // showScopeAlertIfNeeded() + + cancellable.forEach { $0.cancel() } } deinit { @@ -211,57 +221,52 @@ extension ComposeViewController { showSpinner("sending_title".localized) - Promise { [weak self] in - try await(self!.encryptAndSendMessage()) - }.then(on: .main) { [weak self] sent in - if sent { // else it must have shown error to user - self?.handleSuccessfullySentMessage() - } - }.catch(on: .main) { [weak self] error in - self?.showAlert(error: error, message: "compose_error".localized) - } + encryptAndSendMessage() } - private func encryptAndSendMessage() -> Promise { - Promise { [weak self] () -> Bool in - guard let self = self else { return false } - - let recipients = self.contextToSend.recipients - - guard recipients.isNotEmpty else { - assertionFailure("Recipients should not be empty. Fail in checking") - return false - } - - guard let text = self.contextToSend.message else { - assertionFailure("Text and Email should not be nil at this point. Fail in checking") - return false - } - - let subject = self.input.subjectReplyTitle - ?? self.contextToSend.subject - ?? "(no subject)" - - guard let myPubKey = self.dataService.publicKey else { - self.showAlert(message: "compose_no_pub_sender".localized) - return false - } - - guard let allRecipientPubs = self.getPubKeys(for: recipients) else { - return false - } - - let encrypted = self.encryptMsg( - pubkeys: allRecipientPubs + [myPubKey], - subject: subject, - message: text, - to: recipients.map { $0.email } - ) - - try await(self.messageSender.sendMail(mime: encrypted.mimeEncoded)) - - return true + private func encryptAndSendMessage() { + let recipients = self.contextToSend.recipients + + guard recipients.isNotEmpty else { + return + } + + guard let text = self.contextToSend.message else { + return + } + + let subject = self.input.subjectReplyTitle + ?? self.contextToSend.subject + ?? "(no subject)" + + guard let myPubKey = self.dataService.publicKey else { + return } + + guard let allRecipientPubs = getPubKeys(for: recipients) else { + return + } + + let encrypted = self.encryptMsg( + pubkeys: allRecipientPubs + [myPubKey], + subject: subject, + message: text, + to: recipients.map { $0.email } + ) + + self.messageSender + .sendMail(mime: encrypted.mimeEncoded) + .sink( + receiveCompletion: { [weak self] result in + guard case .failure(let error) = result else { + return + } + self?.showAlert(error: error, message: "compose_error".localized) + }, + receiveValue: { [weak self] in + self?.handleSuccessfullySentMessage() + }) + .store(in: &cancellable) } private func getPubKeys(for recepients: [Recipient]) -> [String]? { diff --git a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift index 1f9b6329c..3c7140690 100644 --- a/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift +++ b/FlowCrypt/Controllers/SideMenu/Menu/MyMenuViewController.swift @@ -4,7 +4,6 @@ import AsyncDisplayKit import FlowCryptUI -import Promises final class MyMenuViewController: ASDKViewController { private enum Constants { diff --git a/FlowCrypt/Functionality/Mail Provider/Message Gateway/GmailService+send.swift b/FlowCrypt/Functionality/Mail Provider/Message Gateway/GmailService+send.swift index 96c494705..b3794cb18 100644 --- a/FlowCrypt/Functionality/Mail Provider/Message Gateway/GmailService+send.swift +++ b/FlowCrypt/Functionality/Mail Provider/Message Gateway/GmailService+send.swift @@ -7,15 +7,16 @@ // import Foundation -import Promises import GoogleAPIClientForREST import GTMSessionFetcher +import Combine extension GmailService: MessageGateway { - func sendMail(mime: Data) -> Promise { - Promise { (resolve, reject) in + func sendMail(mime: Data) -> Future { + Future { promise in guard let raw = GTLREncodeBase64(mime) else { - return reject(GmailServiceError.messageEncode) + promise(.failure(GmailServiceError.messageEncode)) + return } let gtlMessage = GTLRGmail_Message() @@ -29,10 +30,10 @@ extension GmailService: MessageGateway { self.gmailService.executeQuery(querySend) { (_, _, error) in if let error = error { - reject(GmailServiceError.providerError(error)) + promise(.failure(GmailServiceError.providerError(error))) return } - resolve(()) + promise(.success(())) } } } diff --git a/FlowCrypt/Functionality/Mail Provider/Message Gateway/Imap+send.swift b/FlowCrypt/Functionality/Mail Provider/Message Gateway/Imap+send.swift index 1323301bc..3a2b3d6af 100644 --- a/FlowCrypt/Functionality/Mail Provider/Message Gateway/Imap+send.swift +++ b/FlowCrypt/Functionality/Mail Provider/Message Gateway/Imap+send.swift @@ -3,15 +3,22 @@ // import Foundation -import Promises +import Combine extension Imap: MessageGateway { - func sendMail(mime: Data) -> Promise { - Promise { [weak self] resolve, reject in - guard let self = self else { return reject(AppErr.nilSelf) } + func sendMail(mime: Data) -> Future { + Future { [weak self] promise in + guard let self = self else { return promise(.failure(AppErr.nilSelf)) } + self.smtpSess? .sendOperation(with: mime) - .start(self.finalizeVoid("send", resolve, reject, retry: { self.sendMail(mime: mime) })) + .start { error in + if let error = error { + promise(.failure(error)) + } else { + promise(.success(())) + } + } } } } diff --git a/FlowCrypt/Functionality/Mail Provider/Message Gateway/MessageGateway.swift b/FlowCrypt/Functionality/Mail Provider/Message Gateway/MessageGateway.swift index abadd0182..42108c01c 100644 --- a/FlowCrypt/Functionality/Mail Provider/Message Gateway/MessageGateway.swift +++ b/FlowCrypt/Functionality/Mail Provider/Message Gateway/MessageGateway.swift @@ -8,7 +8,8 @@ import Foundation import Promises +import Combine protocol MessageGateway { - func sendMail(mime: Data) -> Promise + func sendMail(mime: Data) -> Future } diff --git a/FlowCrypt/Functionality/Services/Backup Services/BackupService.swift b/FlowCrypt/Functionality/Services/Backup Services/BackupService.swift index 889dd39f2..7bdc0bdf5 100644 --- a/FlowCrypt/Functionality/Services/Backup Services/BackupService.swift +++ b/FlowCrypt/Functionality/Services/Backup Services/BackupService.swift @@ -76,7 +76,7 @@ extension BackupService: BackupServiceType { atts: attachments ) let backupEmail = try self.core.composeEmail(msg: message, fmt: .plain, pubKeys: nil) - try await(messageSender.sendMail(mime: backupEmail.mimeEncoded)) +// try await(messageSender.sendMail(mime: backupEmail.mimeEncoded)) } }