From bd0df2c84a6486f272ce26747243eb41ce3fd1fc Mon Sep 17 00:00:00 2001 From: Ralph Kuepper Date: Tue, 5 Jan 2021 23:10:16 +0100 Subject: [PATCH 1/6] Updated the repo to work with the application load balancer. --- .../contents.xcworkspacedata | 7 + Package.swift | 2 +- Sources/VaporAWSLambdaRuntime/ALB.swift | 152 ++++++++++++++++++ .../VaporAWSLambdaRuntime/LambdaServer.swift | 10 +- Tests/VaporAWSLambdaRuntimeTests/ALB.swift | 80 +++++++++ .../contents.xcworkspacedata | 7 + examples/Hello/Package.resolved | 22 +-- examples/Hello/Sources/Hello/main.swift | 5 +- examples/Hello/makefile | 2 +- 9 files changed, 269 insertions(+), 18 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 Sources/VaporAWSLambdaRuntime/ALB.swift create mode 100644 Tests/VaporAWSLambdaRuntimeTests/ALB.swift create mode 100644 examples/Hello/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Package.swift b/Package.swift index 3befa1e..e3d8253 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.13.0")), - .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", .upToNextMajor(from: "0.3.0")), + .package(url: "https://github.com/skelpo/swift-aws-lambda-runtime.git", .upToNextMajor(from: "0.4.0")), .package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "4.0.0")), .package(url: "https://github.com/swift-extras/swift-extras-base64", .upToNextMajor(from: "0.4.0")), ], diff --git a/Sources/VaporAWSLambdaRuntime/ALB.swift b/Sources/VaporAWSLambdaRuntime/ALB.swift new file mode 100644 index 0000000..ecd6ad2 --- /dev/null +++ b/Sources/VaporAWSLambdaRuntime/ALB.swift @@ -0,0 +1,152 @@ +// +// File.swift +// +// +// Created by Ralph Küpper on 1/5/21. +// + +import AWSLambdaEvents +import AWSLambdaRuntimeCore +import ExtrasBase64 +import NIO +import NIOHTTP1 +import Vapor + +// MARK: - Handler - + +struct ALBHandler: EventLoopLambdaHandler { + + typealias In = ALB.TargetGroupRequest + typealias Out = ALB.TargetGroupResponse + + private let application: Application + private let responder: Responder + + init(application: Application, responder: Responder) { + self.application = application + self.responder = responder + } + + public func handle(context: Lambda.Context, event: ALB.TargetGroupRequest) + -> EventLoopFuture + { + let vaporRequest: Vapor.Request + do { + vaporRequest = try Vapor.Request(req: event, in: context, for: self.application) + } catch { + return context.eventLoop.makeFailedFuture(error) + } + + return self.responder.respond(to: vaporRequest).flatMap { ALB.TargetGroupResponse.from(response: $0, in: context) } + } +} + +// MARK: - Request - + +extension Vapor.Request { + private static let bufferAllocator = ByteBufferAllocator() + + convenience init(req: ALB.TargetGroupRequest, in ctx: Lambda.Context, for application: Application) throws { + var buffer: NIO.ByteBuffer? + switch (req.body, req.isBase64Encoded) { + case (let .some(string), true): + let bytes = try string.base64decoded() + buffer = Vapor.Request.bufferAllocator.buffer(capacity: bytes.count) + buffer!.writeBytes(bytes) + + case (let .some(string), false): + buffer = Vapor.Request.bufferAllocator.buffer(capacity: string.utf8.count) + buffer!.writeString(string) + + case (.none, _): + break + } + + var nioHeaders = NIOHTTP1.HTTPHeaders() + req.headers?.forEach { key, value in + nioHeaders.add(name: key, value: value) + } + + /*if let cookies = req., cookies.count > 0 { + nioHeaders.add(name: "Cookie", value: cookies.joined(separator: "; ")) + }*/ + + var url: String = req.path + if req.queryStringParameters.count > 0 { + url += "?\(req.queryStringParameters)" + } + + self.init( + application: application, + method: NIOHTTP1.HTTPMethod(rawValue: req.httpMethod.rawValue), + url: Vapor.URI(path: url), + version: HTTPVersion(major: 1, minor: 1), + headers: nioHeaders, + collectedBody: buffer, + remoteAddress: nil, + logger: ctx.logger, + on: ctx.eventLoop + ) + + storage[ALB.TargetGroupRequest] = req + } +} + +extension ALB.TargetGroupRequest: Vapor.StorageKey { + public typealias Value = ALB.TargetGroupRequest +} + +// MARK: - Response - + +extension ALB.TargetGroupResponse { + static func from(response: Vapor.Response, in context: Lambda.Context) -> EventLoopFuture { + // Create the headers + var headers = [String: String]() + response.headers.forEach { name, value in + if let current = headers[name] { + headers[name] = "\(current),\(value)" + } else { + headers[name] = value + } + } + + // Can we access the body right away? + if let string = response.body.string { + return context.eventLoop.makeSucceededFuture(.init( + statusCode: AWSLambdaEvents.HTTPResponseStatus(code: response.status.code), + headers: headers, + body: string, + isBase64Encoded: false + )) + } else if let bytes = response.body.data { + return context.eventLoop.makeSucceededFuture(.init( + statusCode: AWSLambdaEvents.HTTPResponseStatus(code: response.status.code), + headers: headers, + body: String(base64Encoding: bytes), + isBase64Encoded: true + )) + } else { + // See if it is a stream and try to gather the data + return response.body.collect(on: context.eventLoop).map { (buffer) -> ALB.TargetGroupResponse in + // Was there any content + guard + var buffer = buffer, + let bytes = buffer.readBytes(length: buffer.readableBytes) + else { + return ALB.TargetGroupResponse( + statusCode: AWSLambdaEvents.HTTPResponseStatus(code: response.status.code), + headers: headers + ) + } + + // Done + return ALB.TargetGroupResponse( + statusCode: AWSLambdaEvents.HTTPResponseStatus(code: response.status.code), + headers: headers, + body: String(base64Encoding: bytes), + isBase64Encoded: true + ) + } + } + } +} diff --git a/Sources/VaporAWSLambdaRuntime/LambdaServer.swift b/Sources/VaporAWSLambdaRuntime/LambdaServer.swift index de1fbf1..ac56fa7 100644 --- a/Sources/VaporAWSLambdaRuntime/LambdaServer.swift +++ b/Sources/VaporAWSLambdaRuntime/LambdaServer.swift @@ -66,8 +66,8 @@ public extension Application.Lambda { } } - struct ConfigurationKey: StorageKey { - typealias Value = LambdaServer.Configuration + public struct ConfigurationKey: StorageKey { + public typealias Value = LambdaServer.Configuration } } } @@ -79,13 +79,13 @@ public class LambdaServer: Server { public enum RequestSource { case apiGateway case apiGatewayV2 -// case applicationLoadBalancer // not in this release + case applicationLoadBalancer } var requestSource: RequestSource var logger: Logger - init(apiService: RequestSource = .apiGatewayV2, logger: Logger) { + public init(apiService: RequestSource = .apiGatewayV2, logger: Logger) { self.requestSource = apiService self.logger = logger } @@ -115,6 +115,8 @@ public class LambdaServer: Server { handler = APIGatewayHandler(application: application, responder: responder) case .apiGatewayV2: handler = APIGatewayV2Handler(application: application, responder: responder) + case .applicationLoadBalancer: + handler = ALBHandler(application: application, responder: responder) } self.lambdaLifecycle = Lambda.Lifecycle( diff --git a/Tests/VaporAWSLambdaRuntimeTests/ALB.swift b/Tests/VaporAWSLambdaRuntimeTests/ALB.swift new file mode 100644 index 0000000..403984d --- /dev/null +++ b/Tests/VaporAWSLambdaRuntimeTests/ALB.swift @@ -0,0 +1,80 @@ +import AWSLambdaEvents +@testable import AWSLambdaRuntimeCore +import Logging +import NIO +import Vapor +@testable import VaporAWSLambdaRuntime +import XCTest + +final class ALBTests: XCTestCase { + func testALBRequest() throws { + let requestdata = """ + { + "requestContext": { + "elb": { + "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-279XGJDqGZ5rsrHC2Fjr/49e9d65c45c6791a" + } + }, + "httpMethod": "GET", + "path": "/lambda", + "queryStringParameters": { + "query": "1234ABCD" + }, + "headers": { + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + "accept-encoding": "gzip", + "accept-language": "en-US,en;q=0.9", + "connection": "keep-alive", + "host": "lambda-alb-123578498.us-east-2.elb.amazonaws.com", + "upgrade-insecure-requests": "1", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36", + "x-amzn-trace-id": "Root=1-5c536348-3d683b8b04734faae651f476", + "x-forwarded-for": "72.12.164.125", + "x-forwarded-port": "80", + "x-forwarded-proto": "http", + "x-imforwards": "20" + }, + "body": "", + "isBase64Encoded": false + } + """ + let decoder = JSONDecoder() + let request = try decoder.decode(ALB.TargetGroupRequest.self, from: requestdata.data(using: .utf8)!) + print("F: ", request) + } + + func testCreateALBResponse() { + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } + let eventLoop = eventLoopGroup.next() + let allocator = ByteBufferAllocator() + let logger = Logger(label: "test") + + let body = #"{"hello": "world"}"# + let vaporResponse = Vapor.Response( + status: .ok, + headers: HTTPHeaders([ + ("Content-Type", "application/json"), + ]), + body: .init(string: body) + ) + + let context = Lambda.Context( + requestID: "abc123", + traceID: AmazonHeaders.generateXRayTraceID(), + invokedFunctionARN: "function-arn", + deadline: .now() + .seconds(3), + logger: logger, + eventLoop: eventLoop, + allocator: allocator + ) + + var response: ALB.TargetGroupResponse? + XCTAssertNoThrow(response = try ALB.TargetGroupResponse.from(response: vaporResponse, in: context).wait()) + + XCTAssertEqual(response?.body, body) + XCTAssertEqual(response?.headers?.count, 2) + XCTAssertEqual(response?.headers?["Content-Type"], "application/json") + XCTAssertEqual(response?.headers?["content-length"], String(body.count)) + } +} diff --git a/examples/Hello/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/examples/Hello/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/examples/Hello/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/Hello/Package.resolved b/examples/Hello/Package.resolved index f69666b..cfc54ae 100644 --- a/examples/Hello/Package.resolved +++ b/examples/Hello/Package.resolved @@ -39,11 +39,11 @@ }, { "package": "swift-aws-lambda-runtime", - "repositoryURL": "https://github.com/swift-server/swift-aws-lambda-runtime.git", + "repositoryURL": "https://github.com/skelpo/swift-aws-lambda-runtime.git", "state": { "branch": null, - "revision": "2bac89639fffd7b1197ab597473a4d10c459a230", - "version": "0.2.0" + "revision": "eb8924dde415c8d9daca242556c23b84b2ef3a5d", + "version": "0.4.0" } }, { @@ -56,21 +56,21 @@ } }, { - "package": "swift-base64-kit", - "repositoryURL": "https://github.com/fabianfett/swift-base64-kit", + "package": "swift-crypto", + "repositoryURL": "https://github.com/apple/swift-crypto.git", "state": { "branch": null, - "revision": "3ffa48a7047fc9ac6581cd53ab1df29466d8f13b", - "version": "0.2.0" + "revision": "9b9d1868601a199334da5d14f4ab2d37d4f8d0c5", + "version": "1.0.2" } }, { - "package": "swift-crypto", - "repositoryURL": "https://github.com/apple/swift-crypto.git", + "package": "swift-extras-base64", + "repositoryURL": "https://github.com/swift-extras/swift-extras-base64", "state": { "branch": null, - "revision": "9b9d1868601a199334da5d14f4ab2d37d4f8d0c5", - "version": "1.0.2" + "revision": "bf6706e1811e746cb204deaa921d8c7b4d0509e2", + "version": "0.4.0" } }, { diff --git a/examples/Hello/Sources/Hello/main.swift b/examples/Hello/Sources/Hello/main.swift index e2e6f79..d6c6316 100644 --- a/examples/Hello/Sources/Hello/main.swift +++ b/examples/Hello/Sources/Hello/main.swift @@ -19,6 +19,9 @@ app.post("hello") { req -> Hello in let name = try req.content.decode(Name.self) return Hello(hello: name.name) } - +app.storage[Application.Lambda.Server.ConfigurationKey.self] = .init(apiService: .applicationLoadBalancer, + logger: app.logger) app.servers.use(.lambda) try app.run() + + diff --git a/examples/Hello/makefile b/examples/Hello/makefile index f28bec8..8335e2a 100644 --- a/examples/Hello/makefile +++ b/examples/Hello/makefile @@ -11,7 +11,7 @@ build_lambda: $(SWIFT_DOCKER_IMAGE) \ swift build --product Hello -c release -package_lambda: build_lambda +package_lambda: docker run \ --rm \ --volume "$(shell pwd)/../..:/src" \ From 8bef83fbcb3cea0417e5dae7d88f1e5c5c029c53 Mon Sep 17 00:00:00 2001 From: Ralph Kuepper Date: Thu, 11 Feb 2021 11:44:19 +0100 Subject: [PATCH 2/6] debug info --- Sources/VaporAWSLambdaRuntime/ALB.swift | 6 ++ .../xcshareddata/xcschemes/Hello.xcscheme | 90 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 examples/Hello/.swiftpm/xcode/xcshareddata/xcschemes/Hello.xcscheme diff --git a/Sources/VaporAWSLambdaRuntime/ALB.swift b/Sources/VaporAWSLambdaRuntime/ALB.swift index ecd6ad2..b45f41b 100644 --- a/Sources/VaporAWSLambdaRuntime/ALB.swift +++ b/Sources/VaporAWSLambdaRuntime/ALB.swift @@ -24,12 +24,14 @@ struct ALBHandler: EventLoopLambdaHandler { init(application: Application, responder: Responder) { self.application = application + print("responder: ", responder) self.responder = responder } public func handle(context: Lambda.Context, event: ALB.TargetGroupRequest) -> EventLoopFuture { + print("handling here") let vaporRequest: Vapor.Request do { vaporRequest = try Vapor.Request(req: event, in: context, for: self.application) @@ -76,6 +78,10 @@ extension Vapor.Request { url += "?\(req.queryStringParameters)" } + ctx.logger.debug("The constructed URL is: \(url)") + ctx.logger.debug("The incoming request is: ") + print("request: ", req) + self.init( application: application, method: NIOHTTP1.HTTPMethod(rawValue: req.httpMethod.rawValue), diff --git a/examples/Hello/.swiftpm/xcode/xcshareddata/xcschemes/Hello.xcscheme b/examples/Hello/.swiftpm/xcode/xcshareddata/xcschemes/Hello.xcscheme new file mode 100644 index 0000000..1e67dfd --- /dev/null +++ b/examples/Hello/.swiftpm/xcode/xcshareddata/xcschemes/Hello.xcscheme @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 01d6c4f6bcbb0971c2a70e46c0a60668a2570286 Mon Sep 17 00:00:00 2001 From: Ralph Kuepper Date: Fri, 12 Feb 2021 07:27:52 +0100 Subject: [PATCH 3/6] Construct URL correctly. --- Sources/VaporAWSLambdaRuntime/ALB.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Sources/VaporAWSLambdaRuntime/ALB.swift b/Sources/VaporAWSLambdaRuntime/ALB.swift index b45f41b..2e5ffac 100644 --- a/Sources/VaporAWSLambdaRuntime/ALB.swift +++ b/Sources/VaporAWSLambdaRuntime/ALB.swift @@ -31,7 +31,6 @@ struct ALBHandler: EventLoopLambdaHandler { public func handle(context: Lambda.Context, event: ALB.TargetGroupRequest) -> EventLoopFuture { - print("handling here") let vaporRequest: Vapor.Request do { vaporRequest = try Vapor.Request(req: event, in: context, for: self.application) @@ -75,12 +74,14 @@ extension Vapor.Request { var url: String = req.path if req.queryStringParameters.count > 0 { - url += "?\(req.queryStringParameters)" + url += "?" + for key in req.queryStringParameters.keys { + // It leaves an ampersand (&) at the end, but who cares? + url += key + "=" + (req.queryStringParameters[key] ?? "") + "&" + } } ctx.logger.debug("The constructed URL is: \(url)") - ctx.logger.debug("The incoming request is: ") - print("request: ", req) self.init( application: application, From 13de56d0b031f55d7d707ac420c2feeb28ca8957 Mon Sep 17 00:00:00 2001 From: Ralph Kuepper Date: Sat, 23 Oct 2021 15:56:01 +0200 Subject: [PATCH 4/6] SQS Support --- Sources/VaporAWSLambdaRuntime/SQS.swift | 152 ++++++++++++++++++ .../VaporAWSLambdaRuntimeTests/SQSTests.swift | 79 +++++++++ 2 files changed, 231 insertions(+) create mode 100644 Sources/VaporAWSLambdaRuntime/SQS.swift create mode 100644 Tests/VaporAWSLambdaRuntimeTests/SQSTests.swift diff --git a/Sources/VaporAWSLambdaRuntime/SQS.swift b/Sources/VaporAWSLambdaRuntime/SQS.swift new file mode 100644 index 0000000..ed3afb0 --- /dev/null +++ b/Sources/VaporAWSLambdaRuntime/SQS.swift @@ -0,0 +1,152 @@ +// +// File.swift +// +// +// Created by Ralph Küpper on 10/23/21. +// + + +import AWSLambdaEvents +import AWSLambdaRuntimeCore +import ExtrasBase64 +import NIO +import NIOHTTP1 +import Vapor + +// MARK: - Handler - + +struct SQSHandler: EventLoopLambdaHandler { + + typealias In = SQS.Event + typealias Out = SQSResponse + + private let application: Application + private let responder: Responder + + init(application: Application, responder: Responder) { + self.application = application + print("responder: ", responder) + self.responder = responder + } + + public func handle(context: Lambda.Context, event: SQS.Event) + -> EventLoopFuture + { + let vaporRequest: Vapor.Request + do { + vaporRequest = try Vapor.Request(req: event, in: context, for: self.application) + } catch { + return context.eventLoop.makeFailedFuture(error) + } + + return self.responder.respond(to: vaporRequest).flatMap { SQSResponse.from(response: $0, in: context) } + } +} + +// MARK: - Request - + +extension Vapor.Request { + private static let bufferAllocator = ByteBufferAllocator() + + convenience init(req: SQS.Event, in ctx: Lambda.Context, for application: Application) throws { + let event = req.records.first! + /*var buffer: NIO.ByteBuffer? + switch (req.body, req.isBase64Encoded) { + case (let .some(string), true): + let bytes = try string.base64decoded() + buffer = Vapor.Request.bufferAllocator.buffer(capacity: bytes.count) + buffer!.writeBytes(bytes) + + case (let .some(string), false): + buffer = Vapor.Request.bufferAllocator.buffer(capacity: string.utf8.count) + buffer!.writeString(string) + + case (.none, _): + break + } + + var nioHeaders = NIOHTTP1.HTTPHeaders() + req.headers?.forEach { key, value in + nioHeaders.add(name: key, value: value) + } + + /*if let cookies = req., cookies.count > 0 { + nioHeaders.add(name: "Cookie", value: cookies.joined(separator: "; ")) + }*/ + + var url: String = req.path + if req.queryStringParameters.count > 0 { + url += "?" + for key in req.queryStringParameters.keys { + // It leaves an ampersand (&) at the end, but who cares? + url += key + "=" + (req.queryStringParameters[key] ?? "") + "&" + } + }*/ + var buffer: NIO.ByteBuffer? + buffer = Vapor.Request.bufferAllocator.buffer(capacity: event.body.utf8.count) + buffer!.writeString(event.body) + + let url = "/sqs" + + ctx.logger.debug("The constructed URL is: \(url)") + + self.init( + application: application, + method: NIOHTTP1.HTTPMethod.POST, + url: Vapor.URI(path: url), + version: HTTPVersion(major: 1, minor: 1), + headers: [:], + collectedBody: buffer, + remoteAddress: nil, + logger: ctx.logger, + on: ctx.eventLoop + ) + + storage[SQS.Event] = req + } +} + +extension SQS.Event: Vapor.StorageKey { + public typealias Value = SQS.Event +} + +// MARK: - Response - + +struct SQSResponse: Codable { + public var statusCode: HTTPResponseStatus + public var statusDescription: String? + public var headers: HTTPHeaders? + public var multiValueHeaders: HTTPMultiValueHeaders? + public var body: String + public var isBase64Encoded: Bool + + public init( + statusCode: HTTPResponseStatus, + statusDescription: String? = nil, + headers: HTTPHeaders? = nil, + multiValueHeaders: HTTPMultiValueHeaders? = nil, + body: String = "", + isBase64Encoded: Bool = false + ) { + self.statusCode = statusCode + self.statusDescription = statusDescription + self.headers = headers + self.multiValueHeaders = multiValueHeaders + self.body = body + self.isBase64Encoded = isBase64Encoded + } + + static func from(response: Vapor.Response, in context: Lambda.Context) -> EventLoopFuture { + // Create the headers + var headers: HTTPHeaders = [:] + + // Can we access the body right away? + let string = response.body.string ?? "" + return context.eventLoop.makeSucceededFuture(.init( + statusCode: HTTPResponseStatus.ok, + headers: headers, + body: string, + isBase64Encoded: false + )) + } +} diff --git a/Tests/VaporAWSLambdaRuntimeTests/SQSTests.swift b/Tests/VaporAWSLambdaRuntimeTests/SQSTests.swift new file mode 100644 index 0000000..6951d25 --- /dev/null +++ b/Tests/VaporAWSLambdaRuntimeTests/SQSTests.swift @@ -0,0 +1,79 @@ +// +// File.swift +// +// +// Created by Ralph Küpper on 10/23/21. +// + +import AWSLambdaEvents +@testable import AWSLambdaRuntimeCore +import Logging +import NIO +import Vapor +@testable import VaporAWSLambdaRuntime +import XCTest + +final class SQSTests: XCTestCase { + func testSQSRequest() throws { + let requestdata = """ + { + "Records": [ + { + "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", + "receiptHandle": "MessageReceiptHandle", + "body": "Hello from SQS!", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1523232000000", + "SenderId": "123456789012", + "ApproximateFirstReceiveTimestamp": "1523232000001" + }, + "messageAttributes": {}, + "md5OfBody": "{{{md5_of_body}}}", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue", + "awsRegion": "us-east-1" + } + ] + } + """ + let decoder = JSONDecoder() + let request = try decoder.decode(SQS.Event.self, from: requestdata.data(using: .utf8)!) + print("F: ", request) + } + + func testCreateALBResponse() { + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + defer { XCTAssertNoThrow(try eventLoopGroup.syncShutdownGracefully()) } + let eventLoop = eventLoopGroup.next() + let allocator = ByteBufferAllocator() + let logger = Logger(label: "test") + + let body = #"{"hello": "world"}"# + let vaporResponse = Vapor.Response( + status: .ok, + headers: HTTPHeaders([ + ("Content-Type", "application/json"), + ]), + body: .init(string: body) + ) + + let context = Lambda.Context( + requestID: "abc123", + traceID: AmazonHeaders.generateXRayTraceID(), + invokedFunctionARN: "function-arn", + deadline: .now() + .seconds(3), + logger: logger, + eventLoop: eventLoop, + allocator: allocator + ) + + var response: ALB.TargetGroupResponse? + XCTAssertNoThrow(response = try ALB.TargetGroupResponse.from(response: vaporResponse, in: context).wait()) + + XCTAssertEqual(response?.body, body) + XCTAssertEqual(response?.headers?.count, 2) + XCTAssertEqual(response?.headers?["Content-Type"], "application/json") + XCTAssertEqual(response?.headers?["content-length"], String(body.count)) + } +} From 51e5d643ad4921432318d9ad2b1430233fb4400d Mon Sep 17 00:00:00 2001 From: Ralph Kuepper Date: Sat, 23 Oct 2021 16:00:10 +0200 Subject: [PATCH 5/6] SQS Support --- Sources/VaporAWSLambdaRuntime/LambdaServer.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/VaporAWSLambdaRuntime/LambdaServer.swift b/Sources/VaporAWSLambdaRuntime/LambdaServer.swift index ac56fa7..71c5bb8 100644 --- a/Sources/VaporAWSLambdaRuntime/LambdaServer.swift +++ b/Sources/VaporAWSLambdaRuntime/LambdaServer.swift @@ -80,6 +80,7 @@ public class LambdaServer: Server { case apiGateway case apiGatewayV2 case applicationLoadBalancer + case sqs } var requestSource: RequestSource @@ -117,6 +118,8 @@ public class LambdaServer: Server { handler = APIGatewayV2Handler(application: application, responder: responder) case .applicationLoadBalancer: handler = ALBHandler(application: application, responder: responder) + case .sqs: + handler = SQSHandler(application: application, responder: responder) } self.lambdaLifecycle = Lambda.Lifecycle( From 9e50652806d09b10bbca44dd2d678a666ce1dbd9 Mon Sep 17 00:00:00 2001 From: Ralph Kuepper Date: Sat, 23 Oct 2021 21:32:34 +0200 Subject: [PATCH 6/6] update --- Sources/VaporAWSLambdaRuntime/ALB.swift | 1 - Sources/VaporAWSLambdaRuntime/SQS.swift | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/VaporAWSLambdaRuntime/ALB.swift b/Sources/VaporAWSLambdaRuntime/ALB.swift index 2e5ffac..5035b18 100644 --- a/Sources/VaporAWSLambdaRuntime/ALB.swift +++ b/Sources/VaporAWSLambdaRuntime/ALB.swift @@ -24,7 +24,6 @@ struct ALBHandler: EventLoopLambdaHandler { init(application: Application, responder: Responder) { self.application = application - print("responder: ", responder) self.responder = responder } diff --git a/Sources/VaporAWSLambdaRuntime/SQS.swift b/Sources/VaporAWSLambdaRuntime/SQS.swift index ed3afb0..167cf88 100644 --- a/Sources/VaporAWSLambdaRuntime/SQS.swift +++ b/Sources/VaporAWSLambdaRuntime/SQS.swift @@ -25,7 +25,6 @@ struct SQSHandler: EventLoopLambdaHandler { init(application: Application, responder: Responder) { self.application = application - print("responder: ", responder) self.responder = responder } @@ -50,6 +49,7 @@ extension Vapor.Request { convenience init(req: SQS.Event, in ctx: Lambda.Context, for application: Application) throws { let event = req.records.first! + print("incoming events: ", req.records.count) /*var buffer: NIO.ByteBuffer? switch (req.body, req.isBase64Encoded) { case (let .some(string), true):