Convert the last completion-based API in Account to async await.

This commit is contained in:
Brent Simmons 2024-04-05 18:16:52 -07:00
parent cf855466b3
commit ad151b5fa4
4 changed files with 36 additions and 44 deletions

View File

@ -400,8 +400,7 @@ public enum FetchType {
client: OAuthAuthorizationClient,
accountType: AccountType,
transport: Transport = URLSession.webserviceTransport(),
secretsProvider: SecretsProvider,
completion: @escaping (Result<OAuthAuthorizationGrant, Error>) -> ()) {
secretsProvider: SecretsProvider) async throws -> OAuthAuthorizationGrant {
let grantingType: OAuthAuthorizationGranting.Type
switch accountType {
@ -411,7 +410,7 @@ public enum FetchType {
fatalError("\(accountType) does not support OAuth authorization code granting.")
}
grantingType.requestOAuthAccessToken(with: response, transport: transport, secretsProvider: secretsProvider, completion: completion)
return try await grantingType.requestOAuthAccessToken(with: response, transport: transport, secretsProvider: secretsProvider)
}
public func receiveRemoteNotification(userInfo: [AnyHashable: Any]) async {

View File

@ -38,30 +38,34 @@ extension FeedlyAccountDelegate: OAuthAuthorizationGranting {
return FeedlyAPICaller.authorizationCodeUrlRequest(for: authorizationRequest, baseUrlComponents: baseURLComponents)
}
static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: Transport, secretsProvider: SecretsProvider, completion: @escaping (Result<OAuthAuthorizationGrant, Error>) -> ()) {
static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: any Web.Transport, secretsProvider: any Secrets.SecretsProvider) async throws -> OAuthAuthorizationGrant {
let client = environment.oauthAuthorizationClient(secretsProvider: secretsProvider)
let request = OAuthAccessTokenRequest(authorizationResponse: response,
scope: oauthAuthorizationGrantScope,
client: client)
let caller = FeedlyAPICaller(transport: transport, api: environment, secretsProvider: secretsProvider)
caller.requestAccessToken(request) { result in
switch result {
case .success(let response):
let accessToken = Credentials(type: .oauthAccessToken, username: response.id, secret: response.accessToken)
let refreshToken: Credentials? = {
guard let token = response.refreshToken else {
return nil
}
return Credentials(type: .oauthRefreshToken, username: response.id, secret: token)
}()
return try await withCheckedThrowingContinuation { continuation in
caller.requestAccessToken(request) { result in
switch result {
case .success(let response):
let accessToken = Credentials(type: .oauthAccessToken, username: response.id, secret: response.accessToken)
let grant = OAuthAuthorizationGrant(accessToken: accessToken, refreshToken: refreshToken)
let refreshToken: Credentials? = {
guard let token = response.refreshToken else {
return nil
}
return Credentials(type: .oauthRefreshToken, username: response.id, secret: token)
}()
completion(.success(grant))
let grant = OAuthAuthorizationGrant(accessToken: accessToken, refreshToken: refreshToken)
case .failure(let error):
completion(.failure(error))
continuation.resume(returning: grant)
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}

View File

@ -101,7 +101,8 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
}
private func didEndAuthentication(url: URL?, error: Error?) {
MainActor.assumeIsolated {
Task { @MainActor in
guard !isCanceled else {
didFinish()
return
@ -109,15 +110,16 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
do {
guard let url = url else {
if let error = error {
if let error {
throw error
}
throw URLError(.badURL)
}
let response = try OAuthAuthorizationResponse(url: url, client: oauthClient)
let response = try OAuthAuthorizationResponse(url: url, client: self.oauthClient)
Account.requestOAuthAccessToken(with: response, client: oauthClient, accountType: accountType, secretsProvider: secretsProvider, completion: didEndRequestingAccessToken(_:))
let tokenResponse = try await Account.requestOAuthAccessToken(with: response, client: oauthClient, accountType: accountType, secretsProvider: secretsProvider)
saveAccount(for: tokenResponse)
} catch is ASWebAuthenticationSessionError {
didFinish() // Primarily, cancellation.
@ -128,6 +130,7 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
}
}
public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
guard let anchor = presentationAnchor else {
fatalError("\(self) has outlived presentation anchor.")
@ -135,20 +138,6 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
return anchor
}
@MainActor private func didEndRequestingAccessToken(_ result: Result<OAuthAuthorizationGrant, Error>) {
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let tokenResponse):
saveAccount(for: tokenResponse)
case .failure(let error):
didFinish(error)
}
}
@MainActor private func saveAccount(for grant: OAuthAuthorizationGrant) {
guard !AccountManager.shared.duplicateServiceAccount(type: .feedly, username: grant.accessToken.username) else {
didFinish(OAuthAccountAuthorizationOperationError.duplicateAccount)

View File

@ -167,7 +167,7 @@ public protocol OAuthAuthorizationCodeGrantRequesting {
protocol OAuthAuthorizationGranting: AccountDelegate {
static func oauthAuthorizationCodeGrantRequest(secretsProvider: SecretsProvider) -> URLRequest
@MainActor static func oauthAuthorizationCodeGrantRequest(secretsProvider: SecretsProvider) -> URLRequest
static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: Transport, secretsProvider: SecretsProvider, completion: @escaping (Result<OAuthAuthorizationGrant, Error>) -> ())
@MainActor static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: Transport, secretsProvider: SecretsProvider) async throws -> OAuthAuthorizationGrant
}