Convert validateCredentials to async/await.

This commit is contained in:
Brent Simmons
2023-10-07 10:53:02 -07:00
parent 264db50981
commit f042c97156
11 changed files with 159 additions and 159 deletions

View File

@@ -373,16 +373,16 @@ public enum FetchType {
try CredentialsManager.removeCredentials(type: type, server: server, username: username)
}
public static func validateCredentials(transport: Transport = URLSession.webserviceTransport(), type: AccountType, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> Void) {
public static func validateCredentials(transport: Transport = URLSession.webserviceTransport(), type: AccountType, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
switch type {
case .feedbin:
FeedbinAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion)
return try await FeedbinAccountDelegate.validateCredentials(transport: transport, credentials: credentials)
case .newsBlur:
NewsBlurAccountDelegate.validateCredentials(transport: transport, credentials: credentials, completion: completion)
return try await NewsBlurAccountDelegate.validateCredentials(transport: transport, credentials: credentials)
case .freshRSS, .inoreader, .bazQux, .theOldReader:
ReaderAPIAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint, completion: completion)
return try await ReaderAPIAccountDelegate.validateCredentials(transport: transport, credentials: credentials, endpoint: endpoint)
default:
break
return nil
}
}

View File

@@ -53,7 +53,7 @@ import Secrets
func accountWillBeDeleted(_ account: Account)
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void)
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?) async throws -> Credentials?
/// Suspend all network activity
func suspendNetwork()

View File

@@ -612,16 +612,21 @@ public enum FeedbinAccountDelegateError: String, Error {
func accountWillBeDeleted(_ account: Account) {
}
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> Void) {
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
let caller = FeedbinAPICaller(transport: transport)
caller.credentials = credentials
caller.validateCredentials() { result in
DispatchQueue.main.async {
completion(result)
return try await withCheckedThrowingContinuation { continuation in
caller.validateCredentials() { result in
switch result {
case .success(let credentials):
continuation.resume(returning: credentials)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
// MARK: Suspend and Resume (for iOS)

View File

@@ -205,8 +205,8 @@ final class LocalAccountDelegate: AccountDelegate, Logging {
func accountWillBeDeleted(_ account: Account) {
}
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: (Result<Credentials?, Error>) -> Void) {
return completion(.success(nil))
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
nil
}
// MARK: Suspend and Resume (for iOS)

View File

@@ -649,14 +649,21 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
caller.logout() { _ in }
}
class func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> ()) {
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
let caller = NewsBlurAPICaller(transport: transport) { url, credentials in
URLRequest(url: url, credentials: credentials)
}
caller.credentials = credentials
caller.validateCredentials() { result in
DispatchQueue.main.async {
completion(result)
return try await withCheckedThrowingContinuation { continuation in
caller.validateCredentials() { result in
switch result {
case .success(let credentials):
continuation.resume(returning: credentials)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}

View File

@@ -660,17 +660,21 @@ public enum ReaderAPIAccountDelegateError: LocalizedError {
func accountWillBeDeleted(_ account: Account) {
}
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void) {
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
guard let endpoint = endpoint else {
completion(.failure(TransportError.noURL))
return
throw TransportError.noURL
}
ReaderAPICaller.validateCredentials(credentials: credentials, transport: transport, endpoint: endpoint, variant: .generic) { url, credentials in
URLRequest(url: url, credentials: credentials)
} completion: { result in
Task { @MainActor in
completion(result)
return try await withCheckedThrowingContinuation { continuation in
ReaderAPICaller.validateCredentials(credentials: credentials, transport: transport, endpoint: endpoint, variant: .generic) { url, credentials in
URLRequest(url: url, credentials: credentials)
} completion: { result in
switch result {
case .success(let credentials):
continuation.resume(returning: credentials)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}

View File

@@ -474,8 +474,8 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
articlesZone.resetChangeToken()
}
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: (Result<Credentials?, Error>) -> Void) {
return completion(.success(nil))
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
nil
}
// MARK: Suspend and Resume (for iOS)

View File

@@ -573,9 +573,9 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
MainThreadOperationQueue.shared.add(logout)
}
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL?, completion: @escaping (Result<Credentials?, Error>) -> Void) {
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil) async throws -> Credentials? {
assertionFailure("An `account` instance should enqueue an \(FeedlyRefreshAccessTokenOperation.self) instead.")
completion(.success(credentials))
return credentials
}
// MARK: Suspend and Resume (for iOS)

View File

@@ -62,73 +62,64 @@ import Secrets
}
@IBAction func action(_ sender: Any) {
self.errorMessageLabel.stringValue = ""
guard !usernameTextField.stringValue.isEmpty && !passwordTextField.stringValue.isEmpty else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.userNameAndPasswordRequired.localizedDescription
return
}
guard account != nil || !AccountManager.shared.duplicateServiceAccount(type: .feedbin, username: usernameTextField.stringValue) else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.duplicateAccount.localizedDescription
return
}
actionButton.isEnabled = false
progressIndicator.isHidden = false
progressIndicator.startAnimation(self)
let credentials = Credentials(type: .basic, username: usernameTextField.stringValue, secret: passwordTextField.stringValue)
Account.validateCredentials(type: .feedbin, credentials: credentials) { [weak self] result in
guard let self = self else { return }
self.actionButton.isEnabled = true
self.progressIndicator.isHidden = true
self.progressIndicator.stopAnimation(self)
switch result {
case .success(let validatedCredentials):
guard let validatedCredentials = validatedCredentials else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.invalidUsernameOrPassword.localizedDescription
return
}
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: .feedbin)
}
do {
try self.account?.removeCredentials(type: .basic)
try self.account?.storeCredentials(validatedCredentials)
self.account?.refreshAll() { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
let credentials = Credentials(type: .basic, username: usernameTextField.stringValue, secret: passwordTextField.stringValue)
Task { @MainActor in
do {
let validatedCredentials = try await Account.validateCredentials(type: .feedbin, credentials: credentials)
if let validatedCredentials {
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: .feedbin)
}
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.keychainError.localizedDescription
self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)")
do {
try self.account?.removeCredentials(type: .basic)
try self.account?.storeCredentials(validatedCredentials)
self.account?.refreshAll() { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.keychainError.localizedDescription
self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)")
}
}
case .failure:
else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.invalidUsernameOrPassword.localizedDescription
}
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.networkError.localizedDescription
}
actionButton.isEnabled = true
progressIndicator.isHidden = true
progressIndicator.stopAnimation(self)
}
}
@IBAction func createAccountWithProvider(_ sender: Any) {

View File

@@ -77,49 +77,46 @@ import Secrets
progressIndicator.startAnimation(self)
let credentials = Credentials(type: .newsBlurBasic, username: usernameTextField.stringValue, secret: passwordTextField.stringValue)
Account.validateCredentials(type: .newsBlur, credentials: credentials) { [weak self] result in
guard let self = self else { return }
Task { @MainActor in
do {
let validatedCredentials = try await Account.validateCredentials(type: .newsBlur, credentials: credentials)
if let validatedCredentials {
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: .newsBlur)
}
do {
try self.account?.removeCredentials(type: .newsBlurBasic)
try self.account?.removeCredentials(type: .newsBlurSessionID)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)
self.account?.refreshAll() { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.keychainError.localizedDescription
self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)")
}
}
else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.invalidUsernameOrPassword.localizedDescription
}
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.networkError.localizedDescription
}
self.actionButton.isEnabled = true
self.progressIndicator.isHidden = true
self.progressIndicator.stopAnimation(self)
switch result {
case .success(let validatedCredentials):
guard let validatedCredentials = validatedCredentials else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.invalidUsernameOrPassword.localizedDescription
return
}
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: .newsBlur)
}
do {
try self.account?.removeCredentials(type: .newsBlurBasic)
try self.account?.removeCredentials(type: .newsBlurSessionID)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)
self.account?.refreshAll() { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.keychainError.localizedDescription
self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)")
}
case .failure:
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.networkError.localizedDescription
}
}
}

View File

@@ -133,54 +133,50 @@ import ReaderAPI
progressIndicator.startAnimation(self)
let credentials = Credentials(type: .readerBasic, username: usernameTextField.stringValue, secret: passwordTextField.stringValue)
Account.validateCredentials(type: accountType, credentials: credentials, endpoint: apiURL) { [weak self] result in
guard let self = self else { return }
Task { @MainActor in
do {
let validatedCredentials = try await Account.validateCredentials(type: accountType, credentials: credentials, endpoint: apiURL)
if let validatedCredentials {
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: self.accountType!)
}
do {
self.account?.endpointURL = apiURL
try self.account?.removeCredentials(type: .readerBasic)
try self.account?.removeCredentials(type: .readerAPIKey)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)
self.account?.refreshAll() { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.keychainError.localizedDescription
self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)")
}
}
else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.invalidUsernameOrPassword.localizedDescription
}
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.networkError.localizedDescription
}
self.actionButton.isEnabled = true
self.progressIndicator.isHidden = true
self.progressIndicator.stopAnimation(self)
switch result {
case .success(let validatedCredentials):
guard let validatedCredentials = validatedCredentials else {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.invalidUsernameOrPassword.localizedDescription
return
}
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: self.accountType!)
}
do {
self.account?.endpointURL = apiURL
try self.account?.removeCredentials(type: .readerBasic)
try self.account?.removeCredentials(type: .readerAPIKey)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)
self.account?.refreshAll() { result in
switch result {
case .success:
break
case .failure(let error):
NSApplication.shared.presentError(error)
}
}
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
} catch {
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.keychainError.localizedDescription
self.logger.error("Keychain error while storing credentials: \(error.localizedDescription, privacy: .public)")
}
case .failure:
self.errorMessageLabel.stringValue = LocalizedNetNewsWireError.networkError.localizedDescription
}
}
}
@IBAction func createAccountWithProvider(_ sender: Any) {