@@ -26,7 +26,14 @@ import NIOCore
26
26
/// level protocols ``EventLoopLambdaHandler`` and
27
27
/// ``ByteBufferLambdaHandler``.
28
28
@available ( macOS 12 , iOS 15 , tvOS 15 , watchOS 8 , * )
29
- public protocol LambdaHandler : EventLoopLambdaHandler {
29
+ public protocol LambdaHandler {
30
+ /// The lambda functions input. In most cases this should be `Codable`. If your event originates from an
31
+ /// AWS service, have a look at [AWSLambdaEvents](https://github.com/swift-server/swift-aws-lambda-events),
32
+ /// which provides a number of commonly used AWS Event implementations.
33
+ associatedtype Event
34
+ /// The lambda functions output. Can be `Void`.
35
+ associatedtype Output
36
+
30
37
/// The Lambda initialization method.
31
38
/// Use this method to initialize resources that will be used in every request.
32
39
///
@@ -44,18 +51,38 @@ public protocol LambdaHandler: EventLoopLambdaHandler {
44
51
///
45
52
/// - Returns: A Lambda result ot type `Output`.
46
53
func handle( _ event: Event , context: LambdaContext ) async throws -> Output
54
+
55
+ /// Encode a response of type ``Output`` to `ByteBuffer`.
56
+ /// Concrete Lambda handlers implement this method to provide coding functionality.
57
+ /// - parameters:
58
+ /// - allocator: A `ByteBufferAllocator` to help allocate the `ByteBuffer`.
59
+ /// - value: Response of type ``Output``.
60
+ ///
61
+ /// - Returns: A `ByteBuffer` with the encoded version of the `value`.
62
+ func encode( allocator: ByteBufferAllocator , value: Output ) throws -> ByteBuffer ?
63
+
64
+ /// Decode a `ByteBuffer` to a request or event of type ``Event``.
65
+ /// Concrete Lambda handlers implement this method to provide coding functionality.
66
+ ///
67
+ /// - parameters:
68
+ /// - buffer: The `ByteBuffer` to decode.
69
+ ///
70
+ /// - Returns: A request or event of type ``Event``.
71
+ func decode( buffer: ByteBuffer ) throws -> Event
47
72
}
48
73
49
74
@available ( macOS 12 , iOS 15 , tvOS 15 , watchOS 8 , * )
50
75
extension LambdaHandler {
51
- public static func makeHandler( context: LambdaInitializationContext ) -> EventLoopFuture < Self > {
76
+ // FIXME: why public?
77
+ public static func makeHandler( context: LambdaInitializationContext ) -> EventLoopFuture < ( ByteBuffer , LambdaContext ) -> EventLoopFuture < ByteBuffer ? > > {
52
78
let promise = context. eventLoop. makePromise ( of: Self . self)
53
79
promise. completeWithTask {
54
80
try await Self ( context: context)
55
81
}
56
- return promise. futureResult
82
+ return promise. futureResult. map { $0 . handle ( buffer : context : ) }
57
83
}
58
84
85
+ // FIXME: why public?
59
86
public func handle( _ event: Event , context: LambdaContext ) -> EventLoopFuture < Output > {
60
87
let promise = context. eventLoop. makePromise ( of: Output . self)
61
88
// using an unchecked sendable wrapper for the handler
@@ -66,6 +93,68 @@ extension LambdaHandler {
66
93
}
67
94
return promise. futureResult
68
95
}
96
+
97
+ /// Driver for `ByteBuffer` -> ``Event`` decoding and ``Output`` -> `ByteBuffer` encoding
98
+ @inlinable
99
+ internal func handle( buffer: ByteBuffer , context: LambdaContext ) -> EventLoopFuture < ByteBuffer ? > {
100
+ let input : Event
101
+ do {
102
+ input = try self . decode ( buffer: buffer)
103
+ } catch {
104
+ return context. eventLoop. makeFailedFuture ( CodecError . requestDecoding ( error) )
105
+ }
106
+
107
+ return self . handle ( input, context: context) . flatMapThrowing { output in
108
+ do {
109
+ return try self . encode ( allocator: context. allocator, value: output)
110
+ } catch {
111
+ throw CodecError . responseEncoding ( error)
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ /// Implementation of `ByteBuffer` to `Void` decoding.
118
+ @available ( macOS 12 , iOS 15 , tvOS 15 , watchOS 8 , * )
119
+ extension LambdaHandler where Output == Void {
120
+ @inlinable
121
+ public func encode( allocator: ByteBufferAllocator , value: Void ) throws -> ByteBuffer ? {
122
+ nil
123
+ }
124
+ }
125
+
126
+ @available ( macOS 12 , iOS 15 , tvOS 15 , watchOS 8 , * )
127
+ extension LambdaHandler where Event == String {
128
+ @inlinable
129
+ public func decode( buffer: ByteBuffer ) throws -> String {
130
+ guard let value = buffer. getString ( at: buffer. readerIndex, length: buffer. readableBytes) else {
131
+ throw CodecError . invalidString
132
+ }
133
+ return value
134
+ }
135
+ }
136
+
137
+ @available ( macOS 12 , iOS 15 , tvOS 15 , watchOS 8 , * )
138
+ extension LambdaHandler where Output == String {
139
+ @inlinable
140
+ public func encode( allocator: ByteBufferAllocator , value: String ) throws -> ByteBuffer ? {
141
+ allocator. buffer ( string: value)
142
+ }
143
+ }
144
+
145
+ @available ( macOS 12 , iOS 15 , tvOS 15 , watchOS 8 , * )
146
+ extension LambdaHandler {
147
+ /// Initializes and runs the Lambda function.
148
+ ///
149
+ /// If you precede your ``ByteBufferLambdaHandler`` conformer's declaration with the
150
+ /// [@main](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID626)
151
+ /// attribute, the system calls the conformer's `main()` method to launch the lambda function.
152
+ ///
153
+ /// The lambda runtime provides a default implementation of the method that manages the launch
154
+ /// process.
155
+ public static func main( ) {
156
+ _ = Lambda . run ( configuration: . init( ) , handlerType: Self . self)
157
+ }
69
158
}
70
159
71
160
/// unchecked sendable wrapper for the handler
@@ -100,14 +189,22 @@ fileprivate struct UncheckedSendableHandler<Underlying: LambdaHandler, Event, Ou
100
189
/// as the core runtime engine, making the processing faster but requires more care from the
101
190
/// implementation to never block the `EventLoop`. Implement this protocol only in performance
102
191
/// critical situations and implement ``LambdaHandler`` in all other circumstances.
103
- public protocol EventLoopLambdaHandler : ByteBufferLambdaHandler {
192
+ public protocol EventLoopLambdaHandler {
104
193
/// The lambda functions input. In most cases this should be `Codable`. If your event originates from an
105
194
/// AWS service, have a look at [AWSLambdaEvents](https://github.com/swift-server/swift-aws-lambda-events),
106
195
/// which provides a number of commonly used AWS Event implementations.
107
196
associatedtype Event
108
197
/// The lambda functions output. Can be `Void`.
109
198
associatedtype Output
110
199
200
+ /// Create a Lambda handler for the runtime.
201
+ ///
202
+ /// Use this to initialize all your resources that you want to cache between invocations. This could be database
203
+ /// connections and HTTP clients for example. It is encouraged to use the given `EventLoop`'s conformance
204
+ /// to `EventLoopGroup` when initializing NIO dependencies. This will improve overall performance, as it
205
+ /// minimizes thread hopping.
206
+ static func makeHandler( context: LambdaInitializationContext ) -> EventLoopFuture < Self >
207
+
111
208
/// The Lambda handling method.
112
209
/// Concrete Lambda handlers implement this method to provide the Lambda functionality.
113
210
///
@@ -139,12 +236,17 @@ public protocol EventLoopLambdaHandler: ByteBufferLambdaHandler {
139
236
}
140
237
141
238
extension EventLoopLambdaHandler {
239
+ @inlinable
240
+ internal static func makeHandler( context: LambdaInitializationContext ) -> EventLoopFuture < ( ByteBuffer , LambdaContext ) -> EventLoopFuture < ByteBuffer ? > > {
241
+ Self . makeHandler ( context: context) . map { $0. handle ( buffer: context: ) }
242
+ }
243
+
142
244
/// Driver for `ByteBuffer` -> ``Event`` decoding and ``Output`` -> `ByteBuffer` encoding
143
245
@inlinable
144
- public func handle( _ event : ByteBuffer , context: LambdaContext ) -> EventLoopFuture < ByteBuffer ? > {
246
+ internal func handle( buffer : ByteBuffer , context: LambdaContext ) -> EventLoopFuture < ByteBuffer ? > {
145
247
let input : Event
146
248
do {
147
- input = try self . decode ( buffer: event )
249
+ input = try self . decode ( buffer: buffer )
148
250
} catch {
149
251
return context. eventLoop. makeFailedFuture ( CodecError . requestDecoding ( error) )
150
252
}
@@ -167,6 +269,20 @@ extension EventLoopLambdaHandler where Output == Void {
167
269
}
168
270
}
169
271
272
+ extension EventLoopLambdaHandler {
273
+ /// Initializes and runs the Lambda function.
274
+ ///
275
+ /// If you precede your ``ByteBufferLambdaHandler`` conformer's declaration with the
276
+ /// [@main](https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID626)
277
+ /// attribute, the system calls the conformer's `main()` method to launch the lambda function.
278
+ ///
279
+ /// The lambda runtime provides a default implementation of the method that manages the launch
280
+ /// process.
281
+ public static func main( ) {
282
+ _ = Lambda . run ( configuration: . init( ) , handlerType: Self . self)
283
+ }
284
+ }
285
+
170
286
// MARK: - ByteBufferLambdaHandler
171
287
172
288
/// An `EventLoopFuture` based processing protocol for a Lambda that takes a `ByteBuffer` and returns
@@ -176,7 +292,7 @@ extension EventLoopLambdaHandler where Output == Void {
176
292
/// ``LambdaHandler`` based APIs.
177
293
/// Most users are not expected to use this protocol.
178
294
public protocol ByteBufferLambdaHandler {
179
- /// Create your Lambda handler for the runtime.
295
+ /// Create a Lambda handler for the runtime.
180
296
///
181
297
/// Use this to initialize all your resources that you want to cache between invocations. This could be database
182
298
/// connections and HTTP clients for example. It is encouraged to use the given `EventLoop`'s conformance
@@ -193,7 +309,14 @@ public protocol ByteBufferLambdaHandler {
193
309
///
194
310
/// - Returns: An `EventLoopFuture` to report the result of the Lambda back to the runtime engine.
195
311
/// The `EventLoopFuture` should be completed with either a response encoded as `ByteBuffer` or an `Error`.
196
- func handle( _ event: ByteBuffer , context: LambdaContext ) -> EventLoopFuture < ByteBuffer ? >
312
+ func handle( _ buffer: ByteBuffer , context: LambdaContext ) -> EventLoopFuture < ByteBuffer ? >
313
+ }
314
+
315
+ extension ByteBufferLambdaHandler {
316
+ @inlinable
317
+ internal static func makeHandler( context: LambdaInitializationContext ) -> EventLoopFuture < ( ByteBuffer , LambdaContext ) -> EventLoopFuture < ByteBuffer ? > > {
318
+ Self . makeHandler ( context: context) . map { $0. handle ( _: context: ) }
319
+ }
197
320
}
198
321
199
322
extension ByteBufferLambdaHandler {
@@ -210,8 +333,12 @@ extension ByteBufferLambdaHandler {
210
333
}
211
334
}
212
335
336
+ // MARK: - Other
337
+
213
338
@usableFromInline
214
339
enum CodecError : Error {
215
340
case requestDecoding( Error )
216
341
case responseEncoding( Error )
342
+ case invalidString
217
343
}
344
+
0 commit comments