Skip to content

Commit

Permalink
feat: move AWSEndpoint.swift, Partition.swift classes to aws-sdk-swift
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewFossAWS committed May 9, 2024
1 parent 0ea2d08 commit c13ba4c
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 0 deletions.
58 changes: 58 additions & 0 deletions Sources/Core/AWSClientRuntime/Endpoints/AWSEndpoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import ClientRuntime

/**
A structure used by the service client to determine the endpoint.
The SDK will automatically resolve endpoints per API client using an internal resolver.
*/
public struct AWSEndpoint: Equatable {
/**
The endpoint object contains the host name (e.g. "{service-id}.{region}.amazonaws.com"),
the transport protocol (e.g. "HTTPS") and the port to connect to when making requests to this endpoint.
*/
public let endpoint: Endpoint

/**
Flag indicating that the hostname can be modified by the SDK client.
If the hostname is mutable the SDK clients may modify any part of the hostname based
on the requirements of the API (e.g. adding or removing content in the hostname). If the hostname
is expected to be mutable and the client cannot modify the endpoint correctly, the operation
will likely fail.
*/
public let isHostnameImmutable: Bool
/**
The service name that should be used for signing requests to this endpoint.
This overrides the default signing name used by an SDK client.
*/
public let signingName: String?
/**
The region that should be used for signing requests to this endpoint.
This overrides the default signing region used by an SDK client.
*/
public let signingRegion: String?

public init(endpoint: Endpoint,
isHostnameImmutable: Bool = false,
signingName: String? = nil,
signingRegion: String? = nil) {
self.endpoint = endpoint
self.isHostnameImmutable = isHostnameImmutable
self.signingName = signingName
self.signingRegion = signingRegion
}

public static func resolveEndpoint(partitions: [Partition], region: String) throws -> AWSEndpoint {
guard !partitions.isEmpty else {
throw EndpointError.partitionsEmpty(
"The partitions array cannot be empty in order to properly resolve an AWS endpoint")
}

let candidate = partitions.first { $0.canResolveEndpoint(region: region)} ?? partitions[0]
return try candidate.resolveEndpoint(region: region)
}
}
68 changes: 68 additions & 0 deletions Sources/Core/AWSClientRuntime/Endpoints/Partition.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import ClientRuntime

public struct Partition {

/// The partition name/id e.g. "aws"
let id: String

/// The regular expression that specified the pattern that region names in the endpoint adhere to
let regionRegex: String

/// Endpoint that works across all regions or if [isRegionalized] is false
let partitionEndpoint: String

/// Flag indicating whether or not the service is regionalized in the partition. Some services have only a single,
/// partition-global endpoint (e.g. CloudFront).
let isRegionalized: Bool

/**
Default endpoint values for the partition. Some or all of the defaults specified may be superseded
by an entry in [endpoints].
*/
let defaults: ServiceEndpointMetadata

/// Map of endpoint names to their definitions
let endpoints: [String: ServiceEndpointMetadata]

public init(id: String,
regionRegex: String,
partitionEndpoint: String,
isRegionalized: Bool,
defaults: ServiceEndpointMetadata,
endpoints: [String: ServiceEndpointMetadata]) {
self.id = id
self.regionRegex = regionRegex
self.partitionEndpoint = partitionEndpoint
self.isRegionalized = isRegionalized
self.defaults = defaults
self.endpoints = endpoints
}

public func canResolveEndpoint(region: String) -> Bool {
return endpoints[region] != nil || region.range(of: regionRegex,
options: .regularExpression) != nil
}

public func resolveEndpoint(region: String) throws -> AWSEndpoint {
let shouldUsePartitionEndpoint = region.isEmpty && !partitionEndpoint.isEmpty
let resolvedRegion = shouldUsePartitionEndpoint ? partitionEndpoint : region
let endpointDefinition = endpointDefinitionForRegion(region: resolvedRegion)
return try endpointDefinition.resolve(region: region, defaults: defaults)
}

public func endpointDefinitionForRegion(region: String) -> ServiceEndpointMetadata {
if let endpointMetadata = endpoints[region] {
return endpointMetadata
} else if !isRegionalized {
return endpoints[partitionEndpoint] ?? ServiceEndpointMetadata()
} else {
return ServiceEndpointMetadata()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import ClientRuntime

extension ServiceEndpointMetadata {
func resolve(region: String, defaults: ServiceEndpointMetadata) throws -> AWSEndpoint {
let serviceEndpointMetadata = buildEndpointMetadataIfNotSet(defaults: defaults)
guard let hostname = serviceEndpointMetadata.hostName else {
throw EndpointError.hostnameIsNil("EndpointDefinition.hostname cannot be nil at this point")
}
let editedHostName = hostname.replacingOccurrences(of: "{region}", with: region)
let transportProtocol = getProtocolByPriority(from: serviceEndpointMetadata.protocols)
let signingName = serviceEndpointMetadata.credentialScope?.serviceId
let signingRegion = serviceEndpointMetadata.credentialScope?.region ?? region

return AWSEndpoint(endpoint: Endpoint(host: editedHostName,
path: "/",
protocolType: ProtocolType(rawValue: transportProtocol)),
signingName: signingName,
signingRegion: signingRegion)
}

private func buildEndpointMetadataIfNotSet(defaults: ServiceEndpointMetadata) -> ServiceEndpointMetadata {
let hostName = self.hostName ?? defaults.hostName
let protocols = !self.protocols.isEmpty ? self.protocols : defaults.protocols
let credentialScope = CredentialScope(
region: self.credentialScope?.region ?? defaults.credentialScope?.region,
serviceId: self.credentialScope?.serviceId ?? defaults.credentialScope?.serviceId
)
let signatureVersions = !self.signatureVersions.isEmpty ? self.signatureVersions : defaults.signatureVersions
return ServiceEndpointMetadata(
hostName: hostName,
protocols: protocols,
credentialScope: credentialScope,
signatureVersions: signatureVersions
)
}

private func getProtocolByPriority(from: [String]) -> String {
guard from.isEmpty else {
return defaultProtocol
}

for p in protocolPriority {
if let candidate = from.first(where: { $0 == p}) {
return candidate
}
}

return defaultProtocol
}
}

Check warning on line 56 in Sources/Core/AWSClientRuntime/Endpoints/ServiceEndpointMetadata+Extension.swift

View workflow job for this annotation

GitHub Actions / swiftlint

Files should have a single trailing newline (trailing_newline)

0 comments on commit c13ba4c

Please sign in to comment.