Skip to content

Commit 05fbc1b

Browse files
author
Ed Paulosky
authored
feat: Updates CRT to 0.5.0+ (#497)
* Updates in response to CRT 0.5.0 update * Deletes empty files * Converts SDKDefaultIO to a singleton * Converts toData to getData in codegen * Temp: Updates crt dependency to specific branch * Bumps CRT to 0.5.2 * Untracks accidentally added files * Removes unnecessary `close` function * Updates codegen * Updates codegen * Properly handle blob * Addresses PR feedback * Addresses PR feedback * Addresses PR feedback * Addresses PR feedback
1 parent f4ac78c commit 05fbc1b

33 files changed

+222
-311
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let package = Package(
1313
.library(name: "SmithyTestUtil", targets: ["SmithyTestUtil"])
1414
],
1515
dependencies: [
16-
.package(url: "https://github.com/awslabs/aws-crt-swift.git", .exact("0.4.0")),
16+
.package(url: "https://github.com/awslabs/aws-crt-swift.git", .exact("0.5.2")),
1717
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
1818
.package(url: "https://github.com/MaxDesiatov/XMLCoder.git", from: "0.13.0")
1919
],

Sources/ClientRuntime/Config/DefaultSDKRuntimeConfiguration.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,25 @@
66
//
77

88
public struct DefaultSDKRuntimeConfiguration: SDKRuntimeConfiguration {
9-
public var endpoint: String?
9+
public var encoder: RequestEncoder?
10+
public var decoder: ResponseDecoder?
11+
public var httpClientEngine: HttpClientEngine
12+
public var httpClientConfiguration: HttpClientConfiguration
13+
public var idempotencyTokenGenerator: IdempotencyTokenGenerator
14+
public var logger: LogAgent
1015
public let retryer: SDKRetryer
1116
public var clientLogMode: ClientLogMode
12-
public var logger: LogAgent
13-
14-
public init(_ clientName: String, clientLogMode: ClientLogMode = .request) throws {
17+
public var endpoint: String?
18+
19+
public init(
20+
_ clientName: String,
21+
clientLogMode: ClientLogMode = .request
22+
) throws {
23+
self.encoder = nil
24+
self.decoder = nil
25+
self.httpClientEngine = CRTClientEngine()
26+
self.httpClientConfiguration = HttpClientConfiguration()
27+
self.idempotencyTokenGenerator = DefaultIdempotencyTokenGenerator()
1528
self.retryer = try SDKRetryer()
1629
self.logger = SwiftLogger(label: clientName)
1730
self.clientLogMode = clientLogMode

Sources/ClientRuntime/Config/SDKRuntimeConfiguration.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,3 @@ public protocol SDKRuntimeConfiguration {
1919
var retryer: SDKRetryer {get}
2020
var endpoint: String? {get set}
2121
}
22-
23-
public extension SDKRuntimeConfiguration {
24-
var httpClientEngine: HttpClientEngine {
25-
return CRTClientEngine()
26-
}
27-
28-
var httpClientConfiguration: HttpClientConfiguration {
29-
return HttpClientConfiguration()
30-
}
31-
32-
var idempotencyTokenGenerator: IdempotencyTokenGenerator {
33-
return DefaultIdempotencyTokenGenerator()
34-
}
35-
36-
var clientLogMode: ClientLogMode {
37-
return .request
38-
}
39-
40-
var encoder: RequestEncoder? {
41-
return nil
42-
}
43-
44-
var decoder: ResponseDecoder? {
45-
return nil
46-
}
47-
}

Sources/ClientRuntime/Networking/Http/CRT/CRTClientEngine.swift

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,56 +16,50 @@ public class CRTClientEngine: HttpClientEngine {
1616

1717
private let windowSize: Int
1818
private let maxConnectionsPerEndpoint: Int
19-
private var connectionPools: [Endpoint: HttpClientConnectionManager] = [:]
19+
private var connectionPools: [Endpoint: HTTPClientConnectionManager] = [:]
20+
private let sharedDefaultIO = SDKDefaultIO.shared
2021

2122
init(config: CRTClientEngineConfig) {
2223
self.windowSize = config.windowSize
2324
self.maxConnectionsPerEndpoint = config.maxConnectionsPerEndpoint
2425
self.logger = SwiftLogger(label: "SerialExecutor")
2526
}
2627

27-
func getOrCreateConnectionPool(endpoint: Endpoint) -> HttpClientConnectionManager {
28+
func getOrCreateConnectionPool(endpoint: Endpoint) throws -> HTTPClientConnectionManager {
2829
guard let connectionPool = connectionPools[endpoint] else {
29-
let newConnectionPool = createConnectionPool(endpoint: endpoint)
30+
let newConnectionPool = try createConnectionPool(endpoint: endpoint)
3031
connectionPools[endpoint] = newConnectionPool // save in dictionary
3132
return newConnectionPool
3233
}
3334

3435
return connectionPool
3536
}
3637

37-
func closeAllPendingConnections() {
38-
for (endpoint, value) in connectionPools {
39-
logger.debug("Connection to endpoint: \(String(describing: endpoint.url?.absoluteString)) is closing")
40-
value.closePendingConnections()
41-
}
42-
}
38+
private func createConnectionPool(endpoint: Endpoint) throws -> HTTPClientConnectionManager {
39+
let tlsConnectionOptions = TLSConnectionOptions(
40+
context: sharedDefaultIO.tlsContext,
41+
serverName: endpoint.host
42+
)
4343

44-
private func createConnectionPool(endpoint: Endpoint) -> HttpClientConnectionManager {
45-
let tlsConnectionOptions = SDKDefaultIO.shared.tlsContext.newConnectionOptions()
46-
do {
47-
try tlsConnectionOptions.setServerName(endpoint.host)
48-
} catch let err {
49-
logger.error("Server name was not able to be set in TLS Connection Options. TLS Negotiation will fail.")
50-
logger.error("Error: \(err.localizedDescription)")
51-
}
5244
let socketOptions = SocketOptions(socketType: .stream)
5345
#if os(iOS) || os(watchOS)
5446
socketOptions.connectTimeoutMs = 30_000
5547
#endif
56-
let options = HttpClientConnectionOptions(clientBootstrap: SDKDefaultIO.shared.clientBootstrap,
57-
hostName: endpoint.host,
58-
initialWindowSize: windowSize,
59-
port: UInt16(endpoint.port),
60-
proxyOptions: nil,
61-
socketOptions: socketOptions,
62-
tlsOptions: tlsConnectionOptions,
63-
monitoringOptions: nil,
64-
maxConnections: maxConnectionsPerEndpoint,
65-
enableManualWindowManagement: false) // not using backpressure yet
48+
let options = HTTPClientConnectionOptions(
49+
clientBootstrap: sharedDefaultIO.clientBootstrap,
50+
hostName: endpoint.host,
51+
initialWindowSize: windowSize,
52+
port: UInt16(endpoint.port),
53+
proxyOptions: nil,
54+
socketOptions: socketOptions,
55+
tlsOptions: tlsConnectionOptions,
56+
monitoringOptions: nil,
57+
maxConnections: maxConnectionsPerEndpoint,
58+
enableManualWindowManagement: false
59+
) // not using backpressure yet
6660
logger.debug("Creating connection pool for \(String(describing: endpoint.url?.absoluteString))" +
6761
"with max connections: \(maxConnectionsPerEndpoint)")
68-
return HttpClientConnectionManager(options: options)
62+
return try HTTPClientConnectionManager(options: options)
6963
}
7064
}
7165

@@ -78,7 +72,6 @@ public class CRTClientEngine: HttpClientEngine {
7872

7973
private let windowSize: Int
8074
private let maxConnectionsPerEndpoint: Int
81-
private let sharedDefaultIO: SDKDefaultIO = SDKDefaultIO.shared
8275

8376
init(config: CRTClientEngineConfig = CRTClientEngineConfig()) {
8477
self.maxConnectionsPerEndpoint = config.maxConnectionsPerEndpoint
@@ -88,55 +81,58 @@ public class CRTClientEngine: HttpClientEngine {
8881
}
8982

9083
public func execute(request: SdkHttpRequest) async throws -> HttpResponse {
91-
let connectionMgr = await serialExecutor.getOrCreateConnectionPool(endpoint: request.endpoint)
84+
let connectionMgr = try await serialExecutor.getOrCreateConnectionPool(endpoint: request.endpoint)
9285
let connection = try await connectionMgr.acquireConnection()
9386
self.logger.debug("Connection was acquired to: \(String(describing: request.endpoint.url?.absoluteString))")
9487
return try await withCheckedThrowingContinuation({ (continuation: StreamContinuation) in
95-
let requestOptions = makeHttpRequestStreamOptions(request, continuation)
96-
let stream = connection.makeRequest(requestOptions: requestOptions)
97-
stream.activate()
88+
do {
89+
let requestOptions = try makeHttpRequestStreamOptions(request, continuation)
90+
let stream = try connection.makeRequest(requestOptions: requestOptions)
91+
try stream.activate()
92+
} catch {
93+
continuation.resume(throwing: error)
94+
}
9895
})
9996
}
10097

101-
public func close() async {
102-
await serialExecutor.closeAllPendingConnections()
103-
}
104-
10598
public func makeHttpRequestStreamOptions(
10699
_ request: SdkHttpRequest,
107100
_ continuation: StreamContinuation
108-
) -> HttpRequestOptions {
101+
) throws -> HTTPRequestOptions {
109102
let response = HttpResponse()
110-
let crtRequest = request.toHttpRequest(bufferSize: windowSize)
103+
let crtRequest = try request.toHttpRequest()
111104
let streamReader: StreamReader = DataStreamReader()
105+
106+
let makeStatusCode: (HTTPStream) -> HttpStatusCode = { stream in
107+
guard
108+
let statusCodeInt = try? stream.statusCode(),
109+
let statusCode = HttpStatusCode(rawValue: statusCodeInt)
110+
else { return .notFound }
111+
return statusCode
112+
}
112113

113-
let requestOptions = HttpRequestOptions(request: crtRequest) { [self] (stream, _, httpHeaders) in
114+
let requestOptions = HTTPRequestOptions(request: crtRequest) { [self] (stream, _, httpHeaders) in
114115
logger.debug("headers were received")
115-
response.statusCode = HttpStatusCode(rawValue: Int(stream.statusCode)) ?? HttpStatusCode.notFound
116+
response.statusCode = makeStatusCode(stream)
116117
response.headers.addAll(httpHeaders: httpHeaders)
117118
} onIncomingHeadersBlockDone: { [self] (stream, _) in
118119
logger.debug("header block is done")
119-
response.statusCode = HttpStatusCode(rawValue: Int(stream.statusCode)) ?? HttpStatusCode.notFound
120+
response.statusCode = makeStatusCode(stream)
120121
} onIncomingBody: { [self] (stream, data) in
121122
logger.debug("incoming data")
122-
response.statusCode = HttpStatusCode(rawValue: Int(stream.statusCode)) ?? HttpStatusCode.notFound
123+
response.statusCode = makeStatusCode(stream)
123124
let byteBuffer = ByteBuffer(data: data)
124125
streamReader.write(buffer: byteBuffer)
125126
} onStreamComplete: { [self] (stream, error) in
126127
logger.debug("stream completed")
127-
streamReader.hasFinishedWriting = true
128-
if case let CRTError.crtError(unwrappedError) = error {
129-
if unwrappedError.errorCode != 0 {
130-
logger.error("Response encountered an error: \(error)")
131-
streamReader.onError(error: ClientError.crtError(error))
132-
continuation.resume(throwing: error)
133-
return
134-
}
128+
if let error = error, error.code != 0 {
129+
logger.error("Response encountered an error: \(error)")
130+
continuation.resume(throwing: CommonRunTimeError.crtError(error))
131+
return
135132
}
136-
133+
137134
response.body = .stream(.reader(streamReader))
138-
139-
response.statusCode = HttpStatusCode(rawValue: Int(stream.statusCode)) ?? HttpStatusCode.notFound
135+
response.statusCode = makeStatusCode(stream)
140136

141137
continuation.resume(returning: response)
142138
}

Sources/ClientRuntime/Networking/Http/CRT/SDKDefaultIO.swift

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,40 @@ import Darwin
1414
#endif
1515

1616
public final class SDKDefaultIO {
17-
static weak var privateShared: SDKDefaultIO?
17+
public let eventLoopGroup: EventLoopGroup
18+
public let hostResolver: HostResolver
19+
public let clientBootstrap: ClientBootstrap
20+
public let tlsContext: TLSContext
21+
public let logger: Logger
1822

19-
// TODO: revisit this and verify that it is thread safe.
20-
public static var shared: SDKDefaultIO {
21-
if let shared = privateShared {
22-
return shared
23-
} else {
24-
let shared = SDKDefaultIO()
25-
privateShared = shared
26-
return shared
27-
}
28-
}
29-
30-
public var eventLoopGroup: EventLoopGroup
31-
public var hostResolver: DefaultHostResolver
32-
public var clientBootstrap: ClientBootstrap
33-
public var tlsContext: TlsContext
34-
public var logger: Logger
23+
/// Provide singleton access since we want to share and re-use the instance properties
24+
public static let shared = SDKDefaultIO()
3525

3626
private init() {
37-
AwsCommonRuntimeKit.initialize()
27+
CommonRuntimeKit.initialize()
3828
self.logger = Logger(pipe: stdout, level: .none, allocator: defaultAllocator)
39-
self.eventLoopGroup = EventLoopGroup(threadCount: 0)
40-
self.hostResolver = DefaultHostResolver(eventLoopGroup: eventLoopGroup,
41-
maxHosts: 8,
42-
maxTTL: 30)
29+
30+
do {
31+
self.eventLoopGroup = try EventLoopGroup(threadCount: 0)
32+
} catch {
33+
fatalError("""
34+
Event Loop Group failed to create. This should never happen. Please open a
35+
Github issue with us at https://github.com/awslabs/aws-sdk-swift.
36+
""")
37+
}
38+
39+
do {
40+
self.hostResolver = try HostResolver.makeDefault(
41+
eventLoopGroup: eventLoopGroup,
42+
maxHosts: 8,
43+
maxTTL: 30
44+
)
45+
} catch {
46+
fatalError("""
47+
Host Resolver failed to create. This should never happen. Please open a
48+
Github issue with us at https://github.com/awslabs/aws-sdk-swift.
49+
""")
50+
}
4351

4452
do {
4553
self.clientBootstrap = try ClientBootstrap(eventLoopGroup: eventLoopGroup,
@@ -52,11 +60,11 @@ public final class SDKDefaultIO {
5260
""")
5361
}
5462

55-
let tlsContextOptions = TlsContextOptions()
63+
let tlsContextOptions = TLSContextOptions.makeDefault()
5664
tlsContextOptions.setVerifyPeer(true)
5765

5866
do {
59-
self.tlsContext = try TlsContext(options: tlsContextOptions,
67+
self.tlsContext = try TLSContext(options: tlsContextOptions,
6068
mode: .client)
6169
} catch {
6270
fatalError("""
@@ -65,8 +73,4 @@ public final class SDKDefaultIO {
6573
""")
6674
}
6775
}
68-
69-
deinit {
70-
AwsCommonRuntimeKit.cleanUp()
71-
}
7276
}

Sources/ClientRuntime/Networking/Http/Headers.swift

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -219,27 +219,20 @@ extension Header: Comparable {
219219
}
220220

221221
extension Headers {
222-
func toHttpHeaders() -> HttpHeaders {
223-
let httpHeaders = HttpHeaders()
224-
225-
for header in headers {
226-
_ = httpHeaders.add(name: header.name, value: header.value.joined(separator: ","))
222+
func toHttpHeaders() -> [HTTPHeader] {
223+
headers.map {
224+
HTTPHeader(name: $0.name, value: $0.value.joined(separator: ","))
227225
}
228-
return httpHeaders
229226
}
230227

231-
init(httpHeaders: HttpHeaders) {
228+
init(httpHeaders: [HTTPHeader]) {
232229
self.init()
233-
let headers = httpHeaders.getAll()
234-
headers.forEach { (header) in
235-
add(name: header.name, value: header.value)
236-
}
230+
addAll(httpHeaders: httpHeaders)
237231
}
238232

239-
public mutating func addAll(httpHeaders: HttpHeaders) {
240-
let headers = httpHeaders.getAll()
241-
headers.forEach { (header) in
242-
add(name: header.name, value: header.value)
233+
public mutating func addAll(httpHeaders: [HTTPHeader]) {
234+
httpHeaders.forEach {
235+
add(name: $0.name, value: $0.value)
243236
}
244237
}
245238
}

0 commit comments

Comments
 (0)