amplify-swift/AmplifyPlugins/API/Sources/AWSAPIPlugin/SubscriptionFactory/AWSSubscriptionConnectionFa...

101 lines
5.1 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Foundation
import AWSPluginsCore
import Amplify
import AppSyncRealTimeClient
class AWSSubscriptionConnectionFactory: SubscriptionConnectionFactory {
/// Key used to map an API to a ConnectionProvider
private struct MapperCacheKey: Hashable {
let apiName: String
let authType: AWSAuthorizationType?
}
private let concurrencyQueue = DispatchQueue(label: "com.amazonaws.amplify.AWSSubscriptionConnectionFactory",
target: DispatchQueue.global())
private var apiToConnectionProvider: [MapperCacheKey: ConnectionProvider] = [:]
func getOrCreateConnection(for endpointConfig: AWSAPICategoryPluginConfiguration.EndpointConfig,
authService: AWSAuthServiceBehavior,
authType: AWSAuthorizationType? = nil,
apiAuthProviderFactory: APIAuthProviderFactory) throws -> SubscriptionConnection {
return try concurrencyQueue.sync {
let apiName = endpointConfig.name
let url = endpointConfig.baseURL
let authInterceptor = try getInterceptor(for: getOrCreateAuthConfiguration(from: endpointConfig,
authType: authType),
authService: authService,
apiAuthProviderFactory: apiAuthProviderFactory)
// create or retrieve the connection provider. If creating, add interceptors onto the provider.
let connectionProvider = apiToConnectionProvider[MapperCacheKey(apiName: apiName, authType: authType)] ??
ConnectionProviderFactory.createConnectionProviderAsync(for: url,
authInterceptor: authInterceptor,
connectionType: .appSyncRealtime)
// store the connection provider for this api
apiToConnectionProvider[MapperCacheKey(apiName: apiName, authType: authType)] = connectionProvider
// create a subscription connection for subscribing and unsubscribing on the connection provider
return AppSyncSubscriptionConnection(provider: connectionProvider)
}
}
// MARK: Private methods
private func getOrCreateAuthConfiguration(from endpointConfig: AWSAPICategoryPluginConfiguration.EndpointConfig,
authType: AWSAuthorizationType?) throws -> AWSAuthorizationConfiguration {
// create a configuration if there's an override auth type
if let authType = authType {
return try endpointConfig.authorizationConfigurationFor(authType: authType)
}
return endpointConfig.authorizationConfiguration
}
private func getInterceptor(for authorizationConfiguration: AWSAuthorizationConfiguration,
authService: AWSAuthServiceBehavior,
apiAuthProviderFactory: APIAuthProviderFactory) throws -> AuthInterceptorAsync {
let authInterceptor: AuthInterceptorAsync
switch authorizationConfiguration {
case .apiKey(let apiKeyConfiguration):
authInterceptor = APIKeyAuthInterceptor(apiKeyConfiguration.apiKey)
case .amazonCognitoUserPools:
let provider = AWSOIDCAuthProvider(authService: authService)
authInterceptor = OIDCAuthInterceptorAsync(provider)
case .awsIAM(let awsIAMConfiguration):
authInterceptor = IAMAuthInterceptor(authService.getCredentialsProvider(),
region: awsIAMConfiguration.region)
case .openIDConnect:
guard let oidcAuthProvider = apiAuthProviderFactory.oidcAuthProvider() else {
throw APIError.invalidConfiguration(
"Using openIDConnect requires passing in an APIAuthProvider with an OIDC AuthProvider",
"When instantiating AWSAPIPlugin pass in an instance of APIAuthProvider", nil)
}
let wrappedProvider = OIDCAuthProviderWrapper(authTokenProvider: oidcAuthProvider)
authInterceptor = OIDCAuthInterceptorAsync(wrappedProvider)
case .function:
guard let functionAuthProvider = apiAuthProviderFactory.functionAuthProvider() else {
throw APIError.invalidConfiguration(
"Using function as auth provider requires passing in an APIAuthProvider with a Function AuthProvider",
"When instantiating AWSAPIPlugin pass in an instance of APIAuthProvider", nil)
}
authInterceptor = AuthenticationTokenAuthInterceptor(authTokenProvider: functionAuthProvider)
case .none:
throw APIError.unknown("Cannot create AppSync subscription for none auth mode", "")
}
return authInterceptor
}
}