Skip to content

Commit 804bed7

Browse files
committed
Add NewLambdaHandler + LambdaWithBackgroundProcessingHandler protocols. Add closure handlers for StreamingLambdaHandler + NewLambdaHandler. Add Codable adapters.
1 parent b2da91d commit 804bed7

File tree

4 files changed

+207
-16
lines changed

4 files changed

+207
-16
lines changed

Sources/AWSLambdaRuntimeCore/LambdaRuntimeClientProtocol.swift

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,6 @@
1414

1515
import NIOCore
1616

17-
package protocol LambdaResponseStreamWriter {
18-
mutating func write(_ buffer: ByteBuffer) async throws
19-
func finish() async throws
20-
func writeAndFinish(_ buffer: ByteBuffer) async throws
21-
func reportError(_ error: any Error) async throws
22-
}
23-
2417
package protocol LambdaRuntimeClientProtocol {
2518
associatedtype Writer: LambdaResponseStreamWriter
2619

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
import NIOFoundationCompat
17+
18+
import class Foundation.JSONDecoder
19+
import class Foundation.JSONEncoder
20+
21+
package protocol LambdaEventDecoder {
22+
func decode<Event: Decodable>(_ type: Event.Type, from buffer: ByteBuffer) throws -> Event
23+
}
24+
25+
package protocol LambdaOutputEncoder {
26+
func encode<Output: Encodable>(_ value: Output, into buffer: inout ByteBuffer) throws
27+
}
28+
29+
extension JSONEncoder: LambdaOutputEncoder {}
30+
31+
extension JSONDecoder: LambdaEventDecoder {}
32+
33+
package struct VoidEncoder: LambdaOutputEncoder {
34+
package func encode<Output>(_ value: Output, into buffer: inout NIOCore.ByteBuffer) throws where Output: Encodable {
35+
fatalError("LambdaOutputEncoder must never be called on a void output")
36+
}
37+
}
38+
39+
package struct LambdaHandlerAdapter<
40+
Event: Decodable,
41+
Output,
42+
Handler: NewLambdaHandler
43+
>: LambdaWithBackgroundProcessingHandler where Handler.Event == Event, Handler.Output == Output {
44+
let handler: Handler
45+
46+
package init(handler: Handler) {
47+
self.handler = handler
48+
}
49+
50+
package func handle(
51+
_ event: Event,
52+
outputWriter: consuming some LambdaResponseWriter<Output>,
53+
context: NewLambdaContext
54+
) async throws {
55+
let response = try await self.handler.handle(event, context: context)
56+
try await outputWriter.write(response: response)
57+
}
58+
}
59+
60+
package struct LambdaCodableAdapter<
61+
Handler: LambdaWithBackgroundProcessingHandler,
62+
Event: Decodable,
63+
Output,
64+
Decoder: LambdaEventDecoder,
65+
Encoder: LambdaOutputEncoder
66+
>: StreamingLambdaHandler where Handler.Event == Event, Handler.Output == Output {
67+
let handler: Handler
68+
let encoder: Encoder
69+
let decoder: Decoder
70+
private var byteBuffer: ByteBuffer = .init()
71+
72+
package init(encoder: Encoder, decoder: Decoder, handler: Handler) where Output: Encodable {
73+
self.encoder = encoder
74+
self.decoder = decoder
75+
self.handler = handler
76+
}
77+
78+
package init(decoder: Decoder, handler: Handler) where Output == Void, Encoder == VoidEncoder {
79+
self.encoder = VoidEncoder()
80+
self.decoder = decoder
81+
self.handler = handler
82+
}
83+
84+
package mutating func handle(
85+
_ request: ByteBuffer,
86+
responseWriter: some LambdaResponseStreamWriter,
87+
context: NewLambdaContext
88+
) async throws {
89+
let event = try self.decoder.decode(Event.self, from: request)
90+
91+
let writer = ResponseWriter<Output>(encoder: self.encoder, streamWriter: responseWriter)
92+
try await self.handler.handle(event, outputWriter: writer, context: context)
93+
}
94+
}
95+
96+
package struct ResponseWriter<Output>: LambdaResponseWriter {
97+
let underlyingStreamWriter: LambdaResponseStreamWriter
98+
let encoder: LambdaOutputEncoder
99+
var byteBuffer = ByteBuffer()
100+
101+
package init(encoder: LambdaOutputEncoder, streamWriter: LambdaResponseStreamWriter) {
102+
self.encoder = encoder
103+
self.underlyingStreamWriter = streamWriter
104+
}
105+
106+
package mutating func write(response: Output) async throws {
107+
if Output.self == Void.self {
108+
try await self.underlyingStreamWriter.finish()
109+
} else if let response = response as? Encodable {
110+
try self.encoder.encode(response, into: &self.byteBuffer)
111+
try await self.underlyingStreamWriter.writeAndFinish(self.byteBuffer)
112+
}
113+
}
114+
}

Sources/AWSLambdaRuntimeCore/NewLambda.swift

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@
1414

1515
import Dispatch
1616
import Logging
17-
import NIOCore
18-
19-
package protocol StreamingLambdaHandler {
20-
mutating func handle(
21-
_ event: ByteBuffer,
22-
responseWriter: some LambdaResponseStreamWriter,
23-
context: NewLambdaContext
24-
) async throws
25-
}
2617

2718
extension Lambda {
2819
package static func runLoop<RuntimeClient: LambdaRuntimeClientProtocol, Handler>(
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import NIOCore
16+
17+
package protocol StreamingLambdaHandler {
18+
mutating func handle(
19+
_ event: ByteBuffer,
20+
responseWriter: some LambdaResponseStreamWriter,
21+
context: NewLambdaContext
22+
) async throws
23+
}
24+
25+
package protocol LambdaResponseStreamWriter {
26+
mutating func write(_ buffer: ByteBuffer) async throws
27+
func finish() async throws
28+
func writeAndFinish(_ buffer: ByteBuffer) async throws
29+
func reportError(_ error: any Error) async throws
30+
}
31+
32+
package protocol NewLambdaHandler {
33+
associatedtype Event: Decodable
34+
associatedtype Output
35+
36+
func handle(_ event: Event, context: NewLambdaContext) async throws -> Output
37+
}
38+
39+
package protocol LambdaWithBackgroundProcessingHandler {
40+
associatedtype Event: Decodable
41+
associatedtype Output
42+
43+
/// The business logic of the Lambda function. Receives a generic input type and returns a generic output type.
44+
/// Agnostic to JSON encoding/decoding
45+
func handle(
46+
_ event: Event,
47+
outputWriter: some LambdaResponseWriter<Output>,
48+
context: NewLambdaContext
49+
) async throws
50+
}
51+
52+
package protocol LambdaResponseWriter<Output>: ~Copyable {
53+
associatedtype Output
54+
/// Sends the generic Output object (representing the computed result of the handler)
55+
/// to the AWS Lambda response endpoint.
56+
/// This function simply serves as a mechanism to return the computed result from a handler function
57+
/// without an explicit `return`.
58+
mutating func write(response: Output) async throws
59+
}
60+
61+
package struct StreamingClosureHandler: StreamingLambdaHandler {
62+
let body: @Sendable (ByteBuffer, LambdaResponseStreamWriter, NewLambdaContext) async throws -> Void
63+
64+
package init(
65+
body: @Sendable @escaping (ByteBuffer, LambdaResponseStreamWriter, NewLambdaContext) async throws -> Void
66+
) {
67+
self.body = body
68+
}
69+
70+
package func handle(
71+
_ request: ByteBuffer,
72+
responseWriter: some LambdaResponseStreamWriter,
73+
context: NewLambdaContext
74+
) async throws {
75+
try await self.body(request, responseWriter, context)
76+
}
77+
}
78+
79+
package struct ClosureHandler<Event: Decodable, Output>: NewLambdaHandler {
80+
let body: (Event, NewLambdaContext) async throws -> Output
81+
82+
package init(body: @escaping (Event, NewLambdaContext) async throws -> Output) where Output: Encodable {
83+
self.body = body
84+
}
85+
86+
package init(body: @escaping (Event, NewLambdaContext) async throws -> Void) where Output == Void {
87+
self.body = body
88+
}
89+
90+
package func handle(_ event: Event, context: NewLambdaContext) async throws -> Output {
91+
try await self.body(event, context)
92+
}
93+
}

0 commit comments

Comments
 (0)