Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ disabled_rules:
- syntactic_sugar
- unused_capture_list
- nesting
- operator_whitespace
- large_tuple

opt_in_rules:
Expand All @@ -32,6 +33,8 @@ empty_enum_arguments: error
function_body_length:
warning: 100
error: 150
generic_type_name:
max_length: 48
identifier_name:
excluded:
- id
Expand Down
220 changes: 207 additions & 13 deletions Sources/Core/AWSClientRuntime/AWSClientConfiguration.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,212 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import ClientRuntime

public protocol AWSRuntimeConfiguration {
var credentialsProvider: CredentialsProviding { get set }
var region: String? { get set }
var signingRegion: String? {get set}
var regionResolver: RegionResolver? {get set}
var frameworkMetadata: FrameworkMetadata? {get set}
var useFIPS: Bool? {get set}
var useDualStack: Bool? {get set}
/// Provides configuration properties for AWS services.
///
/// This type is used to configure every AWS service client. It is specialized with a `AWSServiceSpecificConfiguration` that contains
/// service-specific configuration properties.
///
/// The service-specific configuration is code-generated for each AWS service; see the generated client code for implementation.
///
/// A custom `typealias` of this type is code-generated for each AWS service; i.e.
/// ```
/// public typealias S3Client.S3ClientConfiguration = AWSClientConfiguration<S3Client.ServiceSpecificConfiguration>
/// ```
public class AWSClientConfiguration<ServiceSpecificConfiguration: AWSServiceSpecificConfiguration> {

/// The custom encoder to be used for encoding models for transmission.
///
/// If no encoder is provided, one will be provided by the SDK.
public var encoder: RequestEncoder?

/// The custom decoder to be used for decoding models from a response.
///
/// If no decoder is provided, one will be provided by the SDK.
public var decoder: ResponseDecoder?

/// The HTTP client engine to be used for HTTP requests.
///
/// If none is provided, AWS provides its own HTTP engine for use.
public var httpClientEngine: HttpClientEngine

/// Configuration for the HTTP client.
public var httpClientConfiguration: HttpClientConfiguration

/// A token generator to ensure idempotency of requests.
public var idempotencyTokenGenerator: IdempotencyTokenGenerator

/// A logger to be used by the SDK for logging events.
public var logger: LogAgent

/// The log level to be used when logging.
public var clientLogMode: ClientLogMode

/// The configuation for retry of failed network requests.
///
/// Default options are provided if none are set.
public var retryStrategyOptions: RetryStrategyOptions

/// The network host to use.
///
/// If none is provided, the SDK selects the most appropriate host for the AWS service in use
///
/// Note: non-secure HTTP is not supported at this time.
public var endpoint: String?

/// The credentials provider to be used for AWS credentials.
///
/// If no credentials provider is supplied, the SDK will look for credentials in the environment, then in the `~/.aws/credentials` file.
public var credentialsProvider: CredentialsProviding

/// The AWS region to use, i.e. `us-east-1` or `us-west-2`, etc.
///
/// If no region is specified here, one must be specified in the `~/.aws/configuration` file.
public var region: String?

/// The signing region to be used for signing AWS requests.
///
/// If none is specified, it is supplied by the SDK.
public var signingRegion: String?

/// Framework Metadata for the client.
///
/// If none is supplied, the SDK will supply default metadata.
public var frameworkMetadata: FrameworkMetadata?

/// Specifies whether FIPS endpoints should be used.
public var useFIPS: Bool?

/// Specifies whether dual-stack endpoints should be used.
public var useDualStack: Bool?

/// A structure containing AWS service-specific properties.
///
/// This structure is custom code-generated for each AWS service.
public var serviceSpecific: ServiceSpecificConfiguration

/// Internal designated init
/// All convenience inits should call this.
init(
// these params have no labels to distinguish this init from the similar convenience inits below
_ credentialsProvider: AWSClientRuntime.CredentialsProviding,
_ endpoint: Swift.String?,
_ serviceSpecific: ServiceSpecificConfiguration?,
_ frameworkMetadata: AWSClientRuntime.FrameworkMetadata?,
_ region: Swift.String?,
_ signingRegion: Swift.String?,
_ useDualStack: Swift.Bool?,
_ useFIPS: Swift.Bool?,
_ retryStrategyOptions: RetryStrategyOptions?
) throws {
typealias RuntimeConfigType =
DefaultSDKRuntimeConfiguration<DefaultRetryStrategy, DefaultRetryErrorInfoProvider>

self.credentialsProvider = credentialsProvider
self.serviceSpecific = try serviceSpecific ?? ServiceSpecificConfiguration(endpointResolver: nil)
self.frameworkMetadata = frameworkMetadata
self.region = region
self.signingRegion = signingRegion ?? region
self.useDualStack = useDualStack
self.useFIPS = useFIPS
self.clientLogMode = RuntimeConfigType.defaultClientLogMode
self.httpClientConfiguration = RuntimeConfigType.defaultHttpClientConfiguration
self.httpClientEngine = RuntimeConfigType.defaultHttpClientEngine
self.idempotencyTokenGenerator = RuntimeConfigType.defaultIdempotencyTokenGenerator
self.logger = RuntimeConfigType.defaultLogger(clientName: self.serviceSpecific.clientName)
self.retryStrategyOptions = retryStrategyOptions ?? RuntimeConfigType.defaultRetryStrategyOptions
}
}

public typealias AWSClientConfiguration = SDKRuntimeConfiguration & AWSRuntimeConfiguration
// MARK: - Convenience initializers

extension AWSClientConfiguration {

public convenience init(region: String) throws {
try self.init(region: region, serviceSpecific: try ServiceSpecificConfiguration(endpointResolver: nil))
}

public convenience init() async throws {
try await self.init(serviceSpecific: try ServiceSpecificConfiguration(endpointResolver: nil))
}

/// Creates a configuration asynchronously
public convenience init(
credentialsProvider: AWSClientRuntime.CredentialsProviding? = nil,
endpoint: Swift.String? = nil,
serviceSpecific: ServiceSpecificConfiguration? = nil,
frameworkMetadata: AWSClientRuntime.FrameworkMetadata? = nil,
region: Swift.String? = nil,
regionResolver: AWSClientRuntime.RegionResolver? = nil,
signingRegion: Swift.String? = nil,
useDualStack: Swift.Bool? = nil,
useFIPS: Swift.Bool? = nil,
retryStrategyOptions: RetryStrategyOptions? = nil
) async throws {
let fileBasedConfig = try await CRTFileBasedConfiguration.makeAsync()
let resolvedRegionResolver = try regionResolver ?? DefaultRegionResolver { _, _ in fileBasedConfig }
let resolvedRegion: String?
if let region = region {
resolvedRegion = region
} else {
resolvedRegion = await resolvedRegionResolver.resolveRegion()
}
let resolvedCredentialsProvider: AWSClientRuntime.CredentialsProviding
if let credentialsProvider = credentialsProvider {
resolvedCredentialsProvider = credentialsProvider
} else {
resolvedCredentialsProvider = try DefaultChainCredentialsProvider(fileBasedConfig: fileBasedConfig)
}
try self.init(
resolvedCredentialsProvider,
endpoint,
serviceSpecific,
frameworkMetadata,
resolvedRegion,
signingRegion,
useDualStack,
useFIPS,
retryStrategyOptions
)
}

public convenience init(
region: Swift.String,
credentialsProvider: AWSClientRuntime.CredentialsProviding? = nil,
endpoint: Swift.String? = nil,
serviceSpecific: ServiceSpecificConfiguration? = nil,
frameworkMetadata: AWSClientRuntime.FrameworkMetadata? = nil,
signingRegion: Swift.String? = nil,
useDualStack: Swift.Bool? = nil,
useFIPS: Swift.Bool? = nil,
retryStrategyOptions: RetryStrategyOptions? = nil
) throws {
let resolvedCredentialsProvider: CredentialsProviding
if let credentialsProvider = credentialsProvider {
resolvedCredentialsProvider = credentialsProvider
} else {
let fileBasedConfig = try CRTFileBasedConfiguration.make()
resolvedCredentialsProvider = try DefaultChainCredentialsProvider(fileBasedConfig: fileBasedConfig)
}
try self.init(
resolvedCredentialsProvider,
endpoint,
serviceSpecific,
frameworkMetadata,
region,
signingRegion,
useDualStack,
useFIPS,
retryStrategyOptions
)
}

public var partitionID: String? {
return "\(serviceSpecific.clientName) - \(region ?? "")"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

/// Contains config properties specific to one AWS service
///
/// A custom service-specific configuration that conforms to this protocol will be code-generated
/// for every AWS service, and an instance of it will be exposed by `AWSClientConfiguration`'s
/// `serviceSpecific` property.
public protocol AWSServiceSpecificConfiguration {

/// The type for the service's endpoint resolver.
associatedtype AWSServiceEndpointResolver

/// The name of the service, i.e. "STS".
///
/// Derived from the service's `sdkId` property.
var serviceName: String { get }

/// The name of the service's client, i.e. "STSClient".
var clientName: String { get }

/// An endpoint resolver for this service.
///
/// If none is provided at compile time, the service will provide one.
var endpointResolver: AWSServiceEndpointResolver { get }

/// Creates a service-specific configuration for this service
/// - Parameter endpointResolver: An endpoint resolver for the service, or `nil` to let
/// the service resolve its own endpoint.
init(endpointResolver: AWSServiceEndpointResolver?) throws
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class AWSEndpointsRuleEngine {
let crtEngine: AwsCommonRuntimeKit.EndpointsRuleEngine

public init(partitions: String, ruleSet: String) throws {
Utils.setupCRT() // ensures CRT is set up before calling the CRT endpoint rules engine
crtEngine = try AwsCommonRuntimeKit.EndpointsRuleEngine(partitions: partitions, ruleSet: ruleSet)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ extension UnknownAWSHTTPServiceError {
InvalidAccessKeyId.self
]
if let Candidate = candidates.first(where: { $0.errorCode == typeName }) {
return Candidate.init(httpResponse: httpResponse, message: message, requestID: requestID, requestID2: requestID2)
return Candidate.init(
httpResponse: httpResponse,
message: message,
requestID: requestID,
requestID2: requestID2
)
}
return UnknownAWSHTTPServiceError(
httpResponse: httpResponse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@

import AwsCommonRuntimeKit

@_spi(FileBasedConfig) public typealias CRTFileBasedConfiguration = AwsCommonRuntimeKit.FileBasedConfiguration
@_spi(FileBasedConfig) public typealias CRTFileBasedConfigurationSection = AwsCommonRuntimeKit.FileBasedConfiguration.Section
@_spi(FileBasedConfig) public typealias CRTFileBasedConfigurationSectionType = AwsCommonRuntimeKit.FileBasedConfiguration.SectionType
@_spi(FileBasedConfig) public typealias CRTFileBasedConfigurationProperty = AwsCommonRuntimeKit.FileBasedConfiguration.Section.Property
@_spi(FileBasedConfig) public typealias CRTFileBasedConfiguration =
AwsCommonRuntimeKit.FileBasedConfiguration
@_spi(FileBasedConfig) public typealias CRTFileBasedConfigurationSection =
AwsCommonRuntimeKit.FileBasedConfiguration.Section
@_spi(FileBasedConfig) public typealias CRTFileBasedConfigurationSectionType =
AwsCommonRuntimeKit.FileBasedConfiguration.SectionType
@_spi(FileBasedConfig) public typealias CRTFileBasedConfigurationProperty =
AwsCommonRuntimeKit.FileBasedConfiguration.Section.Property

extension CRTFileBasedConfigurationSectionType {
init(_ type: FileBasedConfigurationSectionType) {
Expand All @@ -30,7 +34,8 @@ extension CRTFileBasedConfiguration: FileBasedConfiguration {
credentialsFilePath: String? = nil
) throws -> CRTFileBasedConfiguration {
let configFilePath = try configFilePath ?? CRTFileBasedConfiguration.resolveConfigPath(sourceType: .config)
let credentialsFilePath = try credentialsFilePath ?? CRTFileBasedConfiguration.resolveConfigPath(sourceType: .credentials)
let credentialsFilePath = try credentialsFilePath ??
CRTFileBasedConfiguration.resolveConfigPath(sourceType: .credentials)
return try CRTFileBasedConfiguration(configFilePath: configFilePath, credentialsFilePath: credentialsFilePath)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import ClientRuntime
import struct Foundation.Date

extension HttpContext {
static let credentialsProvider = AttributeKey<CredentialsProviding>(name: "CredentialsProvider")
Expand Down
18 changes: 18 additions & 0 deletions Sources/Core/AWSClientRuntime/Utils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import struct AwsCommonRuntimeKit.CommonRuntimeKit

public enum Utils {

/// Sets up CRT-related shared resources such as the global allocator, event loops, etc.
///
/// Calls to CRT functions may crash the SDK if `CommonRuntimeKit.initialize()` is not called first.
///
/// This function may safely be called multiple times.
public static func setupCRT() { CommonRuntimeKit.initialize() }
}
Loading