diff --git a/Package.swift b/Package.swift index e3fa006f..e550962d 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,7 @@ let package = Package( .package(url: "https://github.com/swift-server/swift-backtrace.git", from: "1.1.0"), ], targets: [ - .target(name: "SwiftAwsLambda", dependencies: ["Logging", "Backtrace", "NIOHTTP1"]), + .target(name: "SwiftAwsLambda", dependencies: ["Logging", "Backtrace", "NIOHTTP1", "NIOFoundationCompat"]), .testTarget(name: "SwiftAwsLambdaTests", dependencies: ["SwiftAwsLambda"]), // samples .target(name: "SwiftAwsLambdaSample", dependencies: ["SwiftAwsLambda"]), diff --git a/Sources/SwiftAwsLambda/Lambda+Codable.swift b/Sources/SwiftAwsLambda/Lambda+Codable.swift index bb0a51e3..c7e460ce 100644 --- a/Sources/SwiftAwsLambda/Lambda+Codable.swift +++ b/Sources/SwiftAwsLambda/Lambda+Codable.swift @@ -13,6 +13,8 @@ //===----------------------------------------------------------------------===// import Foundation // for JSON +import NIO +import NIOFoundationCompat /// Extension to the `Lambda` companion to enable execution of Lambdas that take and return `Codable` payloads. /// This is the most common way to use this library in AWS Lambda, since its JSON based. @@ -32,21 +34,18 @@ extension Lambda { } // for testing - internal static func run(configuration: Configuration = .init(), closure: @escaping LambdaCodableClosure) -> LambdaLifecycleResult { + internal static func run(configuration: Configuration = .init(), closure: @escaping LambdaCodableClosure) -> Result { return self.run(handler: LambdaClosureWrapper(closure), configuration: configuration) } // for testing - internal static func run(handler: Handler, configuration: Configuration = .init()) -> LambdaLifecycleResult where Handler: LambdaCodableHandler { + internal static func run(handler: Handler, configuration: Configuration = .init()) -> Result where Handler: LambdaCodableHandler { return self.run(handler: handler as LambdaHandler, configuration: configuration) } } -/// A result type for a Lambda that returns a generic `Out`, having `Out` extend `Encodable`. -public typealias LambdaCodableResult = Result - -/// A callback for a Lambda that returns a `LambdaCodableResult` result type, having `Out` extend `Encodable`. -public typealias LambdaCodableCallback = (LambdaCodableResult) -> Void +/// A callback for a Lambda that returns a `Result` result type, having `Out` extend `Encodable`. +public typealias LambdaCodableCallback = (Result) -> Void /// A processing closure for a Lambda that takes an `In` and returns an `Out` via `LambdaCodableCallback` asynchronously, /// having `In` and `Out` extending `Decodable` and `Encodable` respectively. @@ -73,27 +72,27 @@ public extension LambdaCodableHandler { /// LambdaCodableCodec is an abstract/empty implementation for codec which does `Encodable` -> `[UInt8]` encoding and `[UInt8]` -> `Decodable' decoding. // TODO: would be nicer to use a protocol instead of this "abstract class", but generics get in the way public class LambdaCodableCodec { - func encode(_: Out) -> Result<[UInt8], Error> { fatalError("not implmented") } - func decode(_: [UInt8]) -> Result { fatalError("not implmented") } + func encode(_: Out) -> Result { fatalError("not implmented") } + func decode(_: ByteBuffer) -> Result { fatalError("not implmented") } } /// Default implementation of `Encodable` -> `[UInt8]` encoding and `[UInt8]` -> `Decodable' decoding public extension LambdaCodableHandler { - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping (LambdaResult) -> Void) { + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { switch self.codec.decode(payload) { case .failure(let error): - return callback(.failure(Errors.requestDecoding(error))) + return promise.fail(Errors.requestDecoding(error)) case .success(let payloadAsCodable): self.handle(context: context, payload: payloadAsCodable) { result in switch result { case .failure(let error): - return callback(.failure(error)) + return promise.fail(error) case .success(let encodable): switch self.codec.encode(encodable) { case .failure(let error): - return callback(.failure(Errors.responseEncoding(error))) - case .success(let codableAsBytes): - return callback(.success(codableAsBytes)) + return promise.fail(Errors.responseEncoding(error)) + case .success(let buffer): + return promise.succeed(buffer) } } } @@ -107,18 +106,25 @@ public extension LambdaCodableHandler { private final class LambdaCodableJsonCodec: LambdaCodableCodec { private let encoder = JSONEncoder() private let decoder = JSONDecoder() + private let allocator = ByteBufferAllocator() - public override func encode(_ value: Out) -> Result<[UInt8], Error> { + public override func encode(_ value: Out) -> Result { do { - return .success(try [UInt8](self.encoder.encode(value))) + let data = try self.encoder.encode(value) + var buffer = self.allocator.buffer(capacity: data.count) + buffer.writeBytes(data) + return .success(buffer) } catch { return .failure(error) } } - public override func decode(_ data: [UInt8]) -> Result { + public override func decode(_ buffer: ByteBuffer) -> Result { do { - return .success(try self.decoder.decode(In.self, from: Data(data))) + guard let data = buffer.getData(at: buffer.readerIndex, length: buffer.readableBytes) else { + throw Errors.invalidBuffer + } + return .success(try self.decoder.decode(In.self, from: data)) } catch { return .failure(error) } @@ -141,4 +147,5 @@ private struct LambdaClosureWrapper: LambdaCodabl private enum Errors: Error { case responseEncoding(Error) case requestDecoding(Error) + case invalidBuffer } diff --git a/Sources/SwiftAwsLambda/Lambda+String.swift b/Sources/SwiftAwsLambda/Lambda+String.swift index 72ceb5dd..50d5fe08 100644 --- a/Sources/SwiftAwsLambda/Lambda+String.swift +++ b/Sources/SwiftAwsLambda/Lambda+String.swift @@ -12,6 +12,8 @@ // //===----------------------------------------------------------------------===// +import NIO + /// Extension to the `Lambda` companion to enable execution of Lambdas that take and return `String` payloads. extension Lambda { /// Run a Lambda defined by implementing the `LambdaStringClosure` protocol. @@ -29,21 +31,18 @@ extension Lambda { } // for testing - internal static func run(configuration: Configuration = .init(), _ closure: @escaping LambdaStringClosure) -> LambdaLifecycleResult { + internal static func run(configuration: Configuration = .init(), _ closure: @escaping LambdaStringClosure) -> Result { return self.run(handler: LambdaClosureWrapper(closure), configuration: configuration) } // for testing - internal static func run(handler: LambdaStringHandler, configuration: Configuration = .init()) -> LambdaLifecycleResult { + internal static func run(handler: LambdaStringHandler, configuration: Configuration = .init()) -> Result { return self.run(handler: handler as LambdaHandler, configuration: configuration) } } -/// A result type for a Lambda that returns a `String`. -public typealias LambdaStringResult = Result - -/// A callback for a Lambda that returns a `LambdaStringResult` result type. -public typealias LambdaStringCallback = (LambdaStringResult) -> Void +/// A callback for a Lambda that returns a `Result` result type. +public typealias LambdaStringCallback = (Result) -> Void /// A processing closure for a Lambda that takes a `String` and returns a `LambdaStringResult` via `LambdaStringCallback` asynchronously. public typealias LambdaStringClosure = (LambdaContext, String, LambdaStringCallback) -> Void @@ -55,13 +54,18 @@ public protocol LambdaStringHandler: LambdaHandler { /// Default implementation of `String` -> `[UInt8]` encoding and `[UInt8]` -> `String' decoding public extension LambdaStringHandler { - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) { - self.handle(context: context, payload: String(decoding: payload, as: UTF8.self)) { result in + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { + guard let payload = payload.getString(at: payload.readerIndex, length: payload.readableBytes) else { + return promise.fail(Errors.invalidBuffer) + } + self.handle(context: context, payload: payload) { result in switch result { case .success(let string): - return callback(.success([UInt8](string.utf8))) + var buffer = context.allocator.buffer(capacity: string.utf8.count) + buffer.writeString(string) + return promise.succeed(buffer) case .failure(let error): - return callback(.failure(error)) + return promise.fail(error) } } } @@ -77,3 +81,7 @@ private struct LambdaClosureWrapper: LambdaStringHandler { self.closure(context, payload, callback) } } + +private enum Errors: Error { + case invalidBuffer +} diff --git a/Sources/SwiftAwsLambda/Lambda.swift b/Sources/SwiftAwsLambda/Lambda.swift index e41fe4b1..9d368493 100644 --- a/Sources/SwiftAwsLambda/Lambda.swift +++ b/Sources/SwiftAwsLambda/Lambda.swift @@ -44,14 +44,14 @@ public enum Lambda { // for testing and internal use @usableFromInline @discardableResult - internal static func run(configuration: Configuration = .init(), closure: @escaping LambdaClosure) -> LambdaLifecycleResult { + internal static func run(configuration: Configuration = .init(), closure: @escaping LambdaClosure) -> Result { return self.run(handler: LambdaClosureWrapper(closure), configuration: configuration) } // for testing and internal use @usableFromInline @discardableResult - internal static func run(handler: LambdaHandler, configuration: Configuration = .init()) -> LambdaLifecycleResult { + internal static func run(handler: LambdaHandler, configuration: Configuration = .init()) -> Result { do { let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) // only need one thread, will improve performance defer { try! eventLoopGroup.syncShutdownGracefully() } @@ -252,32 +252,20 @@ public enum Lambda { } } -/// A result type for a Lambda that returns a `[UInt8]`. -public typealias LambdaResult = Result<[UInt8], Error> - -public typealias LambdaCallback = (LambdaResult) -> Void +/// A callback for a Lambda that returns a `Result<[UInt8], Error>`. +public typealias LambdaCallback = (Result<[UInt8], Error>) -> Void /// A processing closure for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously. public typealias LambdaClosure = (LambdaContext, [UInt8], LambdaCallback) -> Void -/// A result type for a Lambda initialization. -public typealias LambdaInitResult = Result - -/// A callback to provide the result of Lambda initialization. -public typealias LambdaInitCallBack = (LambdaInitResult) -> Void - /// A processing protocol for a Lambda that takes a `[UInt8]` and returns a `LambdaResult` result type asynchronously. public protocol LambdaHandler { - /// Initializes the `LambdaHandler`. - func initialize(callback: @escaping LambdaInitCallBack) - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) } -extension LambdaHandler { - @inlinable - public func initialize(callback: @escaping LambdaInitCallBack) { - callback(.success(())) - } +public protocol InitializableLambdaHandler { + /// Initializes the `LambdaHandler`. + func initialize(promise: EventLoopPromise) } public struct LambdaContext { @@ -289,6 +277,8 @@ public struct LambdaContext { public let clientContext: String? public let deadline: String? // utliity + public let eventLoop: EventLoop + public let allocator: ByteBufferAllocator public let logger: Logger public init(requestId: String, @@ -297,6 +287,7 @@ public struct LambdaContext { cognitoIdentity: String? = nil, clientContext: String? = nil, deadline: String? = nil, + eventLoop: EventLoop, logger: Logger) { self.requestId = requestId self.traceId = traceId @@ -304,6 +295,9 @@ public struct LambdaContext { self.cognitoIdentity = cognitoIdentity self.clientContext = clientContext self.deadline = deadline + // utility + self.eventLoop = eventLoop + self.allocator = ByteBufferAllocator() // mutate logger with context var logger = logger logger[metadataKey: "awsRequestId"] = .string(requestId) @@ -314,9 +308,6 @@ public struct LambdaContext { } } -@usableFromInline -internal typealias LambdaLifecycleResult = Result - private struct LambdaClosureWrapper: LambdaHandler { private let closure: LambdaClosure init(_ closure: @escaping LambdaClosure) { @@ -326,4 +317,17 @@ private struct LambdaClosureWrapper: LambdaHandler { func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) { self.closure(context, payload, callback) } + + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { + self.closure(context, payload.getBytes(at: payload.readerIndex, length: payload.readableBytes) ?? []) { result in + switch result { + case .success(let bytes): + var buffer = context.allocator.buffer(capacity: bytes.count) + buffer.writeBytes(bytes) + promise.succeed(buffer) + case .failure(let error): + promise.fail(error) + } + } + } } diff --git a/Sources/SwiftAwsLambda/LambdaRunner.swift b/Sources/SwiftAwsLambda/LambdaRunner.swift index 58664260..e46ea335 100644 --- a/Sources/SwiftAwsLambda/LambdaRunner.swift +++ b/Sources/SwiftAwsLambda/LambdaRunner.swift @@ -36,17 +36,19 @@ internal struct LambdaRunner { /// /// - Returns: An `EventLoopFuture` fulfilled with the outcome of the initialization. func initialize(logger: Logger) -> EventLoopFuture { - logger.info("initializing lambda") - // We need to use `flatMap` instead of `whenFailure` to ensure we complete reporting the result before stopping. - return self.lambdaHandler.initialize(eventLoop: self.eventLoop, - lifecycleId: self.lifecycleId, - offload: self.offload).peekError { error in - self.runtimeClient.reportInitializationError(logger: logger, error: error).peekError { reportingError in - // We're going to bail out because the init failed, so there's not a lot we can do other than log - // that we couldn't report this error back to the runtime. - logger.error("failed reporting initialization error to lambda runtime engine: \(reportingError)") + if let handler = self.lambdaHandler as? InitializableLambdaHandler { + logger.debug("initializing lambda") + return handler.initialize(eventLoop: self.eventLoop, + lifecycleId: self.lifecycleId, + offload: self.offload).peekError { error in + self.runtimeClient.reportInitializationError(logger: logger, error: error).peekError { reportingError in + // We're going to bail out because the init failed, so there's not a lot we can do other than log + // that we couldn't report this error back to the runtime. + logger.error("failed reporting initialization error to lambda runtime engine: \(reportingError)") + } } } + return self.eventLoop.makeSucceededFuture(()) // FIXME: } func run(logger: Logger) -> EventLoopFuture { @@ -61,7 +63,7 @@ internal struct LambdaRunner { lifecycleId: self.lifecycleId, offload: self.offload, context: context, - payload: payload).map { (context, $0) } + payload: payload).mapResult { (context, $0) } }.flatMap { context, result in // 3. report results to runtime engine self.runtimeClient.reportResults(logger: logger, context: context, result: result).peekError { error in @@ -74,34 +76,43 @@ internal struct LambdaRunner { } } -private extension LambdaHandler { +private extension InitializableLambdaHandler { func initialize(eventLoop: EventLoop, lifecycleId: String, offload: Bool) -> EventLoopFuture { // offloading so user code never blocks the eventloop let promise = eventLoop.makePromise(of: Void.self) - if offload { - DispatchQueue(label: "lambda-\(lifecycleId)").async { - self.initialize { promise.completeWith($0) } - } - } else { - self.initialize { promise.completeWith($0) } - } + /* if offload { + DispatchQueue(label: "lambda-\(lifecycleId)").async { + self.initialize { promise.completeWith($0) } + } + } else { + self.initialize { promise.completeWith($0) } + } + return promise.futureResult */ + // FIXME: offloading + self.initialize(promise: promise) return promise.futureResult } +} - func handle(eventLoop: EventLoop, lifecycleId: String, offload: Bool, context: LambdaContext, payload: [UInt8]) -> EventLoopFuture { +private extension LambdaHandler { + func handle(eventLoop: EventLoop, lifecycleId: String, offload: Bool, context: LambdaContext, payload: ByteBuffer) -> EventLoopFuture { // offloading so user code never blocks the eventloop - let promise = eventLoop.makePromise(of: LambdaResult.self) - if offload { - DispatchQueue(label: "lambda-\(lifecycleId)").async { - self.handle(context: context, payload: payload) { result in - promise.succeed(result) - } - } - } else { - self.handle(context: context, payload: payload) { result in - promise.succeed(result) - } - } + let promise = eventLoop.makePromise(of: ByteBuffer.self) + /* if offload { + DispatchQueue(label: "lambda-\(lifecycleId)").async { + self.handle(context: context, payload: payload) { result in + promise.succeed(result) + } + } + } else { + self.handle(context: context, payload: payload) { result in + promise.succeed(result) + } + } + return promise.futureResult */ + + // FIXME: offloading + self.handle(context: context, payload: payload, promise: promise) return promise.futureResult } } @@ -126,6 +137,14 @@ private extension EventLoopFuture { return promise.futureResult } } + + func mapResult(_ callback: @escaping (Result) -> NewValue) -> EventLoopFuture { + return self.map { value in + callback(.success(value)) + }.flatMapErrorThrowing { error in + callback(.failure(error)) + } + } } private extension Result { diff --git a/Sources/SwiftAwsLambda/LambdaRuntimeClient.swift b/Sources/SwiftAwsLambda/LambdaRuntimeClient.swift index 05bb857b..3b865597 100644 --- a/Sources/SwiftAwsLambda/LambdaRuntimeClient.swift +++ b/Sources/SwiftAwsLambda/LambdaRuntimeClient.swift @@ -33,17 +33,17 @@ internal struct LambdaRuntimeClient { } /// Requests work from the Runtime Engine. - func requestWork(logger: Logger) -> EventLoopFuture<(LambdaContext, [UInt8])> { + func requestWork(logger: Logger) -> EventLoopFuture<(LambdaContext, ByteBuffer)> { let url = Consts.invocationURLPrefix + Consts.requestWorkURLSuffix logger.debug("requesting work from lambda runtime engine using \(url)") return self.httpClient.get(url: url).flatMapThrowing { response in guard response.status == .ok else { throw LambdaRuntimeClientError.badStatusCode(response.status) } - guard let payload = response.readWholeBody() else { + guard let payload = response.body else { throw LambdaRuntimeClientError.noBody } - guard let context = LambdaContext(logger: logger, response: response) else { + guard let context = LambdaContext(eventLoop: self.eventLoop, logger: logger, response: response) else { throw LambdaRuntimeClientError.noContext } return (context, payload) @@ -60,14 +60,13 @@ internal struct LambdaRuntimeClient { } /// Reports a result to the Runtime Engine. - func reportResults(logger: Logger, context: LambdaContext, result: LambdaResult) -> EventLoopFuture { + func reportResults(logger: Logger, context: LambdaContext, result: Result) -> EventLoopFuture { var url = Consts.invocationURLPrefix + "/" + context.requestId var body: ByteBuffer switch result { case .success(let data): url += Consts.postResponseURLSuffix - body = self.allocator.buffer(capacity: data.count) - body.writeBytes(data) + body = data case .failure(let error): url += Consts.postErrorURLSuffix // TODO: make FunctionError a const @@ -183,7 +182,7 @@ private extension HTTPClient.Response { } private extension LambdaContext { - init?(logger: Logger, response: HTTPClient.Response) { + init?(eventLoop: EventLoop, logger: Logger, response: HTTPClient.Response) { guard let requestId = response.headerValue(AmazonHeaders.requestID) else { return nil } @@ -201,6 +200,7 @@ private extension LambdaContext { cognitoIdentity: cognitoIdentity, clientContext: clientContext, deadline: deadline, + eventLoop: eventLoop, logger: logger) } } diff --git a/Tests/SwiftAwsLambdaTests/Lambda+CodeableTest.swift b/Tests/SwiftAwsLambdaTests/Lambda+CodeableTest.swift index a540b1da..d2402365 100644 --- a/Tests/SwiftAwsLambdaTests/Lambda+CodeableTest.swift +++ b/Tests/SwiftAwsLambdaTests/Lambda+CodeableTest.swift @@ -45,7 +45,7 @@ class CodableLambdaTest: XCTestCase { func testClosureFailure() throws { let server = try MockLambdaServer(behavior: BadBehavior()).start().wait() - let result: LambdaLifecycleResult = Lambda.run { (_, payload: Request, callback) in + let result: Result = Lambda.run { (_, payload: Request, callback) in callback(.success(Response(requestId: payload.requestId))) } try server.stop().wait() @@ -53,7 +53,7 @@ class CodableLambdaTest: XCTestCase { } } -private func assertLambdaLifecycleResult(result: LambdaLifecycleResult, shoudHaveRun: Int = 0, shouldFailWithError: Error? = nil) { +private func assertLambdaLifecycleResult(result: Result, shoudHaveRun: Int = 0, shouldFailWithError: Error? = nil) { switch result { case .success(let count): if shouldFailWithError != nil { diff --git a/Tests/SwiftAwsLambdaTests/Lambda+StringTest.swift b/Tests/SwiftAwsLambdaTests/Lambda+StringTest.swift index ec77e7a2..39fd0f52 100644 --- a/Tests/SwiftAwsLambdaTests/Lambda+StringTest.swift +++ b/Tests/SwiftAwsLambdaTests/Lambda+StringTest.swift @@ -45,7 +45,7 @@ class StringLambdaTest: XCTestCase { func testClosureFailure() throws { let server = try MockLambdaServer(behavior: BadBehavior()).start().wait() - let result: LambdaLifecycleResult = Lambda.run { (_, payload: String, callback) in + let result: Result = Lambda.run { (_, payload: String, callback) in callback(.success(payload)) } try server.stop().wait() @@ -53,7 +53,7 @@ class StringLambdaTest: XCTestCase { } } -private func assertLambdaLifecycleResult(result: LambdaLifecycleResult, shoudHaveRun: Int = 0, shouldFailWithError: Error? = nil) { +private func assertLambdaLifecycleResult(result: Result, shoudHaveRun: Int = 0, shouldFailWithError: Error? = nil) { switch result { case .success(let count): if shouldFailWithError != nil { diff --git a/Tests/SwiftAwsLambdaTests/LambdaTest.swift b/Tests/SwiftAwsLambdaTests/LambdaTest.swift index 25e702ab..d0d9b5ca 100644 --- a/Tests/SwiftAwsLambdaTests/LambdaTest.swift +++ b/Tests/SwiftAwsLambdaTests/LambdaTest.swift @@ -64,7 +64,7 @@ class LambdaTest: XCTestCase { func testClosureFailure() throws { let server = try MockLambdaServer(behavior: BadBehavior()).start().wait() - let result: LambdaLifecycleResult = Lambda.run { (_, payload: [UInt8], callback: LambdaCallback) in + let result: Result = Lambda.run { (_, payload: [UInt8], callback: LambdaCallback) in callback(.success(payload)) } try server.stop().wait() @@ -74,8 +74,8 @@ class LambdaTest: XCTestCase { func testStartStop() throws { let server = try MockLambdaServer(behavior: GoodBehavior()).start().wait() struct MyHandler: LambdaHandler { - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) { - callback(.success(payload)) + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { + promise.succeed(payload) } } let signal = Signal.ALRM @@ -141,7 +141,7 @@ class LambdaTest: XCTestCase { } } -private func assertLambdaLifecycleResult(result: LambdaLifecycleResult, shoudHaveRun: Int = 0, shouldFailWithError: Error? = nil) { +private func assertLambdaLifecycleResult(result: Result, shoudHaveRun: Int = 0, shouldFailWithError: Error? = nil) { switch result { case .success(let count): if shouldFailWithError != nil { diff --git a/Tests/SwiftAwsLambdaTests/Utils.swift b/Tests/SwiftAwsLambdaTests/Utils.swift index 93b09ffe..addbdda0 100644 --- a/Tests/SwiftAwsLambdaTests/Utils.swift +++ b/Tests/SwiftAwsLambdaTests/Utils.swift @@ -30,16 +30,16 @@ func runLambda(behavior: LambdaServerBehavior, handler: LambdaHandler) throws { }.wait() } -class EchoHandler: LambdaHandler { +final class EchoHandler: LambdaHandler, InitializableLambdaHandler { var initializeCalls = 0 - func initialize(callback: @escaping LambdaInitCallBack) { + func initialize(promise: EventLoopPromise) { self.initializeCalls += 1 - callback(.success(())) + promise.succeed(()) } - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) { - callback(.success(payload)) + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { + promise.succeed(payload) } } @@ -50,8 +50,8 @@ struct FailedHandler: LambdaHandler { self.reason = reason } - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) { - callback(.failure(Error(description: self.reason))) + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { + promise.fail(Error(description: self.reason)) } struct Error: Swift.Error, Equatable, CustomStringConvertible { @@ -59,19 +59,19 @@ struct FailedHandler: LambdaHandler { } } -struct FailedInitializerHandler: LambdaHandler { +struct FailedInitializerHandler: LambdaHandler, InitializableLambdaHandler { private let reason: String public init(_ reason: String) { self.reason = reason } - func handle(context: LambdaContext, payload: [UInt8], callback: @escaping LambdaCallback) { - callback(.success(payload)) + func handle(context: LambdaContext, payload: ByteBuffer, promise: EventLoopPromise) { + promise.succeed(payload) } - func initialize(callback: @escaping LambdaInitCallBack) { - callback(.failure(Error(description: self.reason))) + func initialize(promise: EventLoopPromise) { + promise.fail(Error(description: self.reason)) } public struct Error: Swift.Error, Equatable, CustomStringConvertible {