Merge branch 'main' into sebsto/new-plugins
@@ -19,6 +19,11 @@ on:
|
||||
type: boolean
|
||||
description: "Boolean to enable the compilation of examples. Defaults to true."
|
||||
default: true
|
||||
archive_plugin_examples:
|
||||
type: string
|
||||
description: "The list of examples to run through the archive plugin test. Pass a String with a valid JSON array such as \"[ 'HelloWorld', 'APIGateway' ]\""
|
||||
required: true
|
||||
default: ""
|
||||
archive_plugin_enabled:
|
||||
type: boolean
|
||||
description: "Boolean to enable the test of the archive plugin. Defaults to true."
|
||||
@@ -33,8 +38,8 @@ on:
|
||||
required: true
|
||||
matrix_linux_swift_container_image:
|
||||
type: string
|
||||
description: "Container image for the matrix job. Defaults to matching latest Swift Ubuntu image."
|
||||
default: "swift:amazonlinux2"
|
||||
description: "Container image for the matrix job. Defaults to matching latest Swift 6.1 Amazon Linux 2 image."
|
||||
default: "swiftlang/swift:nightly-6.1-amazonlinux2"
|
||||
|
||||
## We are cancelling previously triggered workflow runs
|
||||
concurrency:
|
||||
@@ -54,7 +59,6 @@ jobs:
|
||||
# We are using only one Swift version
|
||||
swift:
|
||||
- image: ${{ inputs.matrix_linux_swift_container_image }}
|
||||
swift_version: "6.0.1-amazonlinux2"
|
||||
container:
|
||||
image: ${{ matrix.swift.image }}
|
||||
steps:
|
||||
@@ -88,7 +92,6 @@ jobs:
|
||||
- name: Run matrix job
|
||||
working-directory: ${{ github.event.repository.name }} # until we can use action/checkout@v4
|
||||
env:
|
||||
SWIFT_VERSION: ${{ matrix.swift.swift_version }}
|
||||
COMMAND: ${{ inputs.matrix_linux_command }}
|
||||
EXAMPLE: ${{ matrix.examples }}
|
||||
run: |
|
||||
@@ -98,6 +101,10 @@ jobs:
|
||||
name: Test archive plugin
|
||||
if: ${{ inputs.archive_plugin_enabled }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
examples: ${{ fromJson(inputs.archive_plugin_examples) }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -107,8 +114,10 @@ jobs:
|
||||
# https://github.com/actions/checkout/issues/766
|
||||
run: git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
- name: Test the archive plugin
|
||||
env:
|
||||
EXAMPLE: ${{ matrix.examples }}
|
||||
run: |
|
||||
.github/workflows/scripts/check-archive-plugin.sh
|
||||
.github/workflows/scripts/check-archive-plugin.sh
|
||||
|
||||
check-foundation:
|
||||
name: No dependencies on Foundation
|
||||
|
||||
@@ -12,9 +12,9 @@ jobs:
|
||||
license_header_check_project_name: "SwiftAWSLambdaRuntime"
|
||||
shell_check_enabled: true
|
||||
python_lint_check_enabled: true
|
||||
api_breakage_check_container_image: "swift:6.0-noble"
|
||||
api_breakage_check_container_image: "swiftlang/swift:nightly-6.1-jammy"
|
||||
docs_check_container_image: "swift:6.0-noble"
|
||||
format_check_container_image: "swiftlang/swift:nightly-6.0-jammy"
|
||||
format_check_container_image: "swiftlang/swift:nightly-6.1-jammy"
|
||||
yamllint_check_enabled: true
|
||||
|
||||
unit-tests:
|
||||
@@ -36,8 +36,8 @@ jobs:
|
||||
# We pass the list of examples here, but we can't pass an array as argument
|
||||
# Instead, we pass a String with a valid JSON array.
|
||||
# The workaround is mentioned here https://github.com/orgs/community/discussions/11692
|
||||
examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'Testing', 'Tutorial' ]"
|
||||
|
||||
examples: "[ 'APIGateway', 'APIGateway+LambdaAuthorizer', 'BackgroundTasks', 'HelloJSON', 'HelloWorld', 'ResourcesPackaging', 'S3EventNotifier', 'S3_AWSSDK', 'S3_Soto', 'Streaming', 'Testing', 'Tutorial' ]"
|
||||
archive_plugin_examples: "[ 'HelloWorld', 'ResourcesPackaging' ]"
|
||||
archive_plugin_enabled: true
|
||||
|
||||
swift-6-language-mode:
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
##
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
EXAMPLE=HelloWorld
|
||||
log() { printf -- "** %s\n" "$*" >&2; }
|
||||
error() { printf -- "** ERROR: %s\n" "$*" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
|
||||
test -n "${EXAMPLE:-}" || fatal "EXAMPLE unset"
|
||||
|
||||
OUTPUT_DIR=.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager
|
||||
OUTPUT_FILE=${OUTPUT_DIR}/MyLambda/bootstrap
|
||||
ZIP_FILE=${OUTPUT_DIR}/MyLambda/MyLambda.zip
|
||||
|
||||
pushd Examples/${EXAMPLE} || exit 1
|
||||
pushd "Examples/${EXAMPLE}" || exit 1
|
||||
|
||||
# package the example (docker and swift toolchain are installed on the GH runner)
|
||||
LAMBDA_USE_LOCAL_DEPS=../.. swift package archive --allow-network-connections docker || exit 1
|
||||
@@ -33,5 +38,10 @@ file "${OUTPUT_FILE}" | grep --silent ELF
|
||||
# does the ZIP file contain the bootstrap?
|
||||
unzip -l "${ZIP_FILE}" | grep --silent bootstrap
|
||||
|
||||
echo "✅ The archive plugin is OK"
|
||||
# if EXAMPLE is ResourcesPackaging, check if the ZIP file contains hello.txt
|
||||
if [ "$EXAMPLE" == "ResourcesPackaging" ]; then
|
||||
unzip -l "${ZIP_FILE}" | grep --silent hello.txt
|
||||
fi
|
||||
|
||||
echo "✅ The archive plugin is OK with example ${EXAMPLE}"
|
||||
popd || exit 1
|
||||
|
||||
@@ -19,6 +19,7 @@ log() { printf -- "** %s\n" "$*" >&2; }
|
||||
error() { printf -- "** ERROR: %s\n" "$*" >&2; }
|
||||
fatal() { error "$@"; exit 1; }
|
||||
|
||||
SWIFT_VERSION=$(swift --version)
|
||||
test -n "${SWIFT_VERSION:-}" || fatal "SWIFT_VERSION unset"
|
||||
test -n "${COMMAND:-}" || fatal "COMMAND unset"
|
||||
test -n "${EXAMPLE:-}" || fatal "EXAMPLE unset"
|
||||
|
||||
@@ -33,4 +33,5 @@ Package.resolved
|
||||
*.yaml
|
||||
*.yml
|
||||
**/.npmignore
|
||||
**/*.json
|
||||
**/*.json
|
||||
**/*.txt
|
||||
@@ -1,4 +1,4 @@
|
||||
version: 1
|
||||
builder:
|
||||
configs:
|
||||
- documentation_targets: [AWSLambdaRuntimeCore, AWSLambdaRuntime]
|
||||
- documentation_targets: [AWSLambdaRuntime]
|
||||
|
||||
@@ -5,12 +5,6 @@ import PackageDescription
|
||||
// needed for CI to test the local version of the library
|
||||
import struct Foundation.URL
|
||||
|
||||
#if os(macOS)
|
||||
let platforms: [PackageDescription.SupportedPlatform]? = [.macOS(.v15)]
|
||||
#else
|
||||
let platforms: [PackageDescription.SupportedPlatform]? = nil
|
||||
#endif
|
||||
|
||||
let package = Package(
|
||||
name: "swift-aws-lambda-runtime-example",
|
||||
platforms: [.macOS(.v15)],
|
||||
@@ -21,7 +15,7 @@ let package = Package(
|
||||
dependencies: [
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
|
||||
@@ -14,7 +14,7 @@ let package = Package(
|
||||
dependencies: [
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
|
||||
@@ -14,7 +14,7 @@ let package = Package(
|
||||
dependencies: [
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@aws-cdk/asset-awscli-v1": {
|
||||
"version": "2.2.215",
|
||||
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.215.tgz",
|
||||
"integrity": "sha512-D+Jzwpl+zlBGjJf7nuRcz6JFNwqDQ+IzwIq0VSC4LMRRvrkhGE/ZE+zab3EnjmVkipcQqtQe+PVKefgmxETbvA==",
|
||||
"version": "2.2.220",
|
||||
"resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.220.tgz",
|
||||
"integrity": "sha512-2eXZnnIgwWmXc7eRh8mRKPp6yHTKiQrLziRX/oVSfp4M6Jn2no0QFKJoHWqziF5MDQa5TF8qhD4FGsls/1nYPg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@aws-cdk/asset-kubectl-v20": {
|
||||
@@ -41,16 +41,16 @@
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@aws-cdk/cloud-assembly-schema": {
|
||||
"version": "38.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-38.0.1.tgz",
|
||||
"integrity": "sha512-KvPe+NMWAulfNVwY7jenFhzhuLhLqJ/OPy5jx7wUstbjnYnjRVLpUHPU3yCjXFE0J8cuJVdx95BJ4rOs66Pi9w==",
|
||||
"version": "39.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-39.2.1.tgz",
|
||||
"integrity": "sha512-cz18QG02p++ivQ5wdjLI8TyMk1p6kwQc1ExeL2A9RoUg1gCnwEBrkJMhiWgTroWBblT0GF0MqSvzkyeEdHqn2A==",
|
||||
"bundleDependencies": [
|
||||
"jsonschema",
|
||||
"semver"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"jsonschema": "^1.4.1",
|
||||
"jsonschema": "~1.4.1",
|
||||
"semver": "^7.6.3"
|
||||
}
|
||||
},
|
||||
@@ -356,9 +356,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/aws-cdk-lib": {
|
||||
"version": "2.173.2",
|
||||
"resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.173.2.tgz",
|
||||
"integrity": "sha512-cL9+z8Pl3VZGoO7BwdsrFAOeud/vSl3at7OvmhihbNprMN15XuFUx/rViAU5OI1m92NbV4NBzYSLbSeCwYLNyw==",
|
||||
"version": "2.176.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.176.0.tgz",
|
||||
"integrity": "sha512-6Gs2kBaq4elQ4fNAOiCgbD9oOLx/heb/Lp4OVE6Uf7FulYW0DikWJXxR5GWJslTJ4/sCf3UU91q415fc0bruLg==",
|
||||
"bundleDependencies": [
|
||||
"@balena/dockerignore",
|
||||
"case",
|
||||
@@ -377,7 +377,7 @@
|
||||
"@aws-cdk/asset-awscli-v1": "^2.2.208",
|
||||
"@aws-cdk/asset-kubectl-v20": "^2.1.3",
|
||||
"@aws-cdk/asset-node-proxy-agent-v6": "^2.1.0",
|
||||
"@aws-cdk/cloud-assembly-schema": "^38.0.1",
|
||||
"@aws-cdk/cloud-assembly-schema": "^39.0.1",
|
||||
"@balena/dockerignore": "^1.0.2",
|
||||
"case": "1.6.3",
|
||||
"fs-extra": "^11.2.0",
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
// swift-tools-version:6.0
|
||||
// swift-tools-version:6.1
|
||||
|
||||
import PackageDescription
|
||||
|
||||
// needed for CI to test the local version of the library
|
||||
import struct Foundation.URL
|
||||
|
||||
#if os(macOS)
|
||||
let platforms: [PackageDescription.SupportedPlatform]? = [.macOS(.v15)]
|
||||
#else
|
||||
let platforms: [PackageDescription.SupportedPlatform]? = nil
|
||||
#endif
|
||||
|
||||
let package = Package(
|
||||
name: "swift-aws-lambda-runtime-example",
|
||||
platforms: platforms,
|
||||
platforms: [.macOS(.v15)],
|
||||
products: [
|
||||
.executable(name: "HelloJSON", targets: ["HelloJSON"])
|
||||
],
|
||||
dependencies: [
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
|
||||
.package(
|
||||
url: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
|
||||
branch: "ff-package-traits",
|
||||
traits: [
|
||||
.trait(name: "FoundationJSONSupport")
|
||||
]
|
||||
)
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
|
||||
@@ -12,6 +12,35 @@ The handler is `(event: String, context: LambdaContext)`. The function takes two
|
||||
|
||||
The function return value will be encoded as your Lambda function response.
|
||||
|
||||
## Test locally
|
||||
|
||||
You can test your function locally before deploying it to AWS Lambda.
|
||||
|
||||
To start the local function, type the following commands:
|
||||
|
||||
```bash
|
||||
swift run
|
||||
```
|
||||
|
||||
It will compile your code and start the local server. You know the local server is ready to accept connections when you see this message.
|
||||
|
||||
```txt
|
||||
Building for debugging...
|
||||
[1/1] Write swift-version--644A47CB88185983.txt
|
||||
Build of product 'MyLambda' complete! (0.31s)
|
||||
2025-01-29T12:44:48+0100 info LocalServer : host="127.0.0.1" port=7000 [AWSLambdaRuntime] Server started and listening
|
||||
```
|
||||
|
||||
Then, from another Terminal, send your payload with `curl`. Note that the payload must be a valid JSON string. In the case of this function that accepts a simple String, it means the String must be wrapped in between double quotes.
|
||||
|
||||
```bash
|
||||
curl -d '"seb"' http://127.0.0.1:7000/invoke
|
||||
"Hello seb"
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The local server is only available in `DEBUG` mode. It will not start with `swift -c release run`.
|
||||
|
||||
## Build & Package
|
||||
|
||||
To build & archive the package, type the following commands.
|
||||
|
||||
@@ -28,6 +28,8 @@ This directory contains example code for Lambda functions.
|
||||
|
||||
- **[HelloWorld](HelloWorld/README.md)**: a simple Lambda function (requires [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)).
|
||||
|
||||
- **[S3EventNotifier](S3EventNotifier/README.md)**: a Lambda function that receives object-upload notifications from an [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) bucket.
|
||||
|
||||
- **[S3_AWSSDK](S3_AWSSDK/README.md)**: a Lambda function that uses the [AWS SDK for Swift](https://docs.aws.amazon.com/sdk-for-swift/latest/developer-guide/getting-started.html) to invoke an [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) API (requires [AWS SAM](https://aws.amazon.com/serverless/sam/)).
|
||||
|
||||
- **[S3_Soto](S3_Soto/README.md)**: a Lambda function that uses [Soto](https://github.com/soto-project/soto) to invoke an [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) API (requires [AWS SAM](https://aws.amazon.com/serverless/sam/)).
|
||||
@@ -64,4 +66,4 @@ To obtain these keys, you need an AWS account:
|
||||
|
||||
4. **(Optional) Generate Temporary Security Credentials**: If you’re using temporary credentials (which are more secure for short-term access), use AWS Security Token Service (STS). You can call the `GetSessionToken` or `AssumeRole` API to generate temporary credentials, including a session token.
|
||||
|
||||
With these in hand, you can use AWS SigV4 to securely sign your requests and interact with AWS services from your Swift app.
|
||||
With these in hand, you can use AWS SigV4 to securely sign your requests and interact with AWS services from your Swift app.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
@@ -0,0 +1,57 @@
|
||||
// swift-tools-version: 6.0
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
// needed for CI to test the local version of the library
|
||||
import struct Foundation.URL
|
||||
|
||||
let package = Package(
|
||||
name: "ResourcesPackaging",
|
||||
platforms: [.macOS(.v15)],
|
||||
products: [
|
||||
.executable(name: "MyLambda", targets: ["MyLambda"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main")
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
name: "MyLambda",
|
||||
dependencies: [
|
||||
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime")
|
||||
],
|
||||
path: ".",
|
||||
resources: [
|
||||
.process("hello.txt")
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"],
|
||||
localDepsPath != "",
|
||||
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
|
||||
v.isDirectory == true
|
||||
{
|
||||
// when we use the local runtime as deps, let's remove the dependency added above
|
||||
let indexToRemove = package.dependencies.firstIndex { dependency in
|
||||
if case .sourceControl(
|
||||
name: _,
|
||||
location: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
|
||||
requirement: _
|
||||
) = dependency.kind {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if let indexToRemove {
|
||||
package.dependencies.remove(at: indexToRemove)
|
||||
}
|
||||
|
||||
// then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..)
|
||||
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
|
||||
package.dependencies += [
|
||||
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
|
||||
]
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// This source file is part of the SwiftAWSLambdaRuntime open source project
|
||||
//
|
||||
// Copyright (c) 2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors
|
||||
// Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
@@ -13,6 +13,14 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import AWSLambdaRuntime
|
||||
import AWSLambdaTesting
|
||||
import NIOCore
|
||||
import Testing
|
||||
import Foundation
|
||||
|
||||
let runtime = LambdaRuntime {
|
||||
(event: String, context: LambdaContext) in
|
||||
guard let fileURL = Bundle.module.url(forResource: "hello", withExtension: "txt") else {
|
||||
fatalError("no file url")
|
||||
}
|
||||
return try String(contentsOf: fileURL, encoding: .utf8)
|
||||
}
|
||||
|
||||
try await runtime.run()
|
||||
@@ -0,0 +1 @@
|
||||
Hello World
|
||||
@@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/.index-build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
@@ -0,0 +1,50 @@
|
||||
// swift-tools-version: 6.0
|
||||
import PackageDescription
|
||||
|
||||
// needed for CI to test the local version of the library
|
||||
import struct Foundation.URL
|
||||
|
||||
let package = Package(
|
||||
name: "S3EventNotifier",
|
||||
platforms: [.macOS(.v15)],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events", branch: "main"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
name: "S3EventNotifier",
|
||||
dependencies: [
|
||||
.product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
|
||||
.product(name: "AWSLambdaEvents", package: "swift-aws-lambda-events"),
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
if let localDepsPath = Context.environment["LAMBDA_USE_LOCAL_DEPS"],
|
||||
localDepsPath != "",
|
||||
let v = try? URL(fileURLWithPath: localDepsPath).resourceValues(forKeys: [.isDirectoryKey]),
|
||||
v.isDirectory == true
|
||||
{
|
||||
// when we use the local runtime as deps, let's remove the dependency added above
|
||||
let indexToRemove = package.dependencies.firstIndex { dependency in
|
||||
if case .sourceControl(
|
||||
name: _,
|
||||
location: "https://github.com/swift-server/swift-aws-lambda-runtime.git",
|
||||
requirement: _
|
||||
) = dependency.kind {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
if let indexToRemove {
|
||||
package.dependencies.remove(at: indexToRemove)
|
||||
}
|
||||
|
||||
// then we add the dependency on LAMBDA_USE_LOCAL_DEPS' path (typically ../..)
|
||||
print("[INFO] Compiling against swift-aws-lambda-runtime located at \(localDepsPath)")
|
||||
package.dependencies += [
|
||||
.package(name: "swift-aws-lambda-runtime", path: localDepsPath)
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
# S3 Event Notifier
|
||||
|
||||
This example demonstrates how to write a Lambda that is invoked by an event originating from Amazon S3, such as a new object being uploaded to a bucket.
|
||||
|
||||
## Code
|
||||
|
||||
In this example the Lambda function receives an `S3Event` object defined in the `AWSLambdaEvents` library as input object. The `S3Event` object contains all the information about the S3 event that triggered the function, but what we are interested in is the bucket name and the object key, which are inside of a notification `Record`. The object contains an array of records, however since the Lambda function is triggered by a single event, we can safely assume that there is only one record in the array: the first one. Inside of this record, we can find the bucket name and the object key:
|
||||
|
||||
```swift
|
||||
guard let s3NotificationRecord = event.records.first else {
|
||||
throw LambdaError.noNotificationRecord
|
||||
}
|
||||
|
||||
let bucket = s3NotificationRecord.s3.bucket.name
|
||||
let key = s3NotificationRecord.s3.object.key.replacingOccurrences(of: "+", with: " ")
|
||||
```
|
||||
|
||||
The key is URL encoded, so we replace the `+` with a space.
|
||||
|
||||
## Build & Package
|
||||
|
||||
To build & archive the package you can use the following commands:
|
||||
|
||||
```bash
|
||||
swift build
|
||||
swift package archive --allow-network-connections docker
|
||||
```
|
||||
|
||||
If there are no errors, a ZIP file should be ready to deploy, located at `.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/S3EventNotifier/S3EventNotifier.zip`.
|
||||
|
||||
## Deploy
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The Lambda function and the S3 bucket must be located in the same AWS Region. In the code below, we use `eu-west-1` (Ireland).
|
||||
|
||||
To deploy the Lambda function, you can use the `aws` command line:
|
||||
|
||||
```bash
|
||||
REGION=eu-west-1
|
||||
aws lambda create-function \
|
||||
--region "${REGION}" \
|
||||
--function-name S3EventNotifier \
|
||||
--zip-file fileb://.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/S3EventNotifier/S3EventNotifier.zip \
|
||||
--runtime provided.al2 \
|
||||
--handler provided \
|
||||
--architectures arm64 \
|
||||
--role arn:aws:iam::<YOUR_ACCOUNT_ID>:role/lambda_basic_execution
|
||||
```
|
||||
|
||||
The `--architectures` flag is only required when you build the binary on an Apple Silicon machine (Apple M1 or more recent). It defaults to `x64`.
|
||||
|
||||
Be sure to define `REGION` with the region where you want to deploy your Lambda function and replace `<YOUR_ACCOUNT_ID>` with your actual AWS account ID (for example: 012345678901).
|
||||
|
||||
Besides deploying the Lambda function you also need to create the S3 bucket and configure it to send events to the Lambda function. You can do this using the following commands:
|
||||
|
||||
```bash
|
||||
REGION=eu-west-1
|
||||
|
||||
aws s3api create-bucket \
|
||||
--region "${REGION}" \
|
||||
--bucket my-test-bucket \
|
||||
--create-bucket-configuration LocationConstraint="${REGION}"
|
||||
|
||||
aws lambda add-permission \
|
||||
--region "${REGION}" \
|
||||
--function-name S3EventNotifier \
|
||||
--statement-id S3InvokeFunction \
|
||||
--action lambda:InvokeFunction \
|
||||
--principal s3.amazonaws.com \
|
||||
--source-arn arn:aws:s3:::my-test-bucket
|
||||
|
||||
aws s3api put-bucket-notification-configuration \
|
||||
--region "${REGION}" \
|
||||
--bucket my-test-bucket \
|
||||
--notification-configuration '{
|
||||
"LambdaFunctionConfigurations": [{
|
||||
"LambdaFunctionArn": "arn:aws:lambda:${REGION}:<YOUR_ACCOUNT_ID>:function:S3EventNotifier",
|
||||
"Events": ["s3:ObjectCreated:*"]
|
||||
}]
|
||||
}'
|
||||
|
||||
touch testfile.txt && aws s3 cp testfile.txt s3://my-test-bucket/
|
||||
```
|
||||
|
||||
This will:
|
||||
- create a bucket named `my-test-bucket` in the `$REGION` region;
|
||||
- add a permission to the Lambda function to be invoked by Amazon S3;
|
||||
- configure the bucket to send `s3:ObjectCreated:*` events to the Lambda function named `S3EventNotifier`;
|
||||
- upload a file named `testfile.txt` to the bucket.
|
||||
|
||||
Replace `my-test-bucket` with your bucket name (bucket names are unique globaly and this one is already taken). Also replace `REGION` environment variable with the AWS Region where you deployed the Lambda function and `<YOUR_ACCOUNT_ID>` with your actual AWS account ID.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The Lambda function and the S3 bucket must be located in the same AWS Region. Adjust the code above according to your closest AWS Region.
|
||||
@@ -0,0 +1,33 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftAWSLambdaRuntime open source project
|
||||
//
|
||||
// Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import AWSLambdaEvents
|
||||
import AWSLambdaRuntime
|
||||
import Foundation
|
||||
|
||||
let runtime = LambdaRuntime { (event: S3Event, context: LambdaContext) async throws in
|
||||
guard let s3NotificationRecord = event.records.first else {
|
||||
context.logger.error("No S3 notification record found in the event")
|
||||
return
|
||||
}
|
||||
|
||||
let bucket = s3NotificationRecord.s3.bucket.name
|
||||
let key = s3NotificationRecord.s3.object.key.replacingOccurrences(of: "+", with: " ")
|
||||
|
||||
context.logger.info("Received notification from S3 bucket '\(bucket)' for object with key '\(key)'")
|
||||
|
||||
// Here you could, for example, notify an API or a messaging service
|
||||
}
|
||||
|
||||
try await runtime.run()
|
||||
@@ -14,7 +14,7 @@ let package = Package(
|
||||
dependencies: [
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events", from: "1.0.0"),
|
||||
.package(url: "https://github.com/awslabs/aws-sdk-swift", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
|
||||
@@ -16,7 +16,7 @@ let package = Package(
|
||||
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
|
||||
@@ -14,7 +14,7 @@ let package = Package(
|
||||
dependencies: [
|
||||
// during CI, the dependency on local version of swift-aws-lambda-runtime is added dynamically below
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", branch: "main"),
|
||||
.package(url: "https://github.com/swift-server/swift-aws-lambda-events.git", from: "1.0.0"),
|
||||
],
|
||||
targets: [
|
||||
.executableTarget(
|
||||
|
||||
@@ -160,8 +160,8 @@ You must pass an event to the Lambda function. You can use the `event.json` file
|
||||
sam local invoke -e Tests/event.json
|
||||
|
||||
START RequestId: 3270171f-46d3-45f9-9bb6-3c2e5e9dc625 Version: $LATEST
|
||||
2024-12-21T16:49:31+0000 debug LambdaRuntime : [AWSLambdaRuntimeCore] LambdaRuntime initialized
|
||||
2024-12-21T16:49:31+0000 trace LambdaRuntime : lambda_ip=127.0.0.1 lambda_port=9001 [AWSLambdaRuntimeCore] Connection to control plane created
|
||||
2024-12-21T16:49:31+0000 debug LambdaRuntime : [AWSLambdaRuntime] LambdaRuntime initialized
|
||||
2024-12-21T16:49:31+0000 trace LambdaRuntime : lambda_ip=127.0.0.1 lambda_port=9001 [AWSLambdaRuntime] Connection to control plane created
|
||||
2024-12-21T16:49:31+0000 debug LambdaRuntime : [APIGatewayLambda] HTTP API Message received
|
||||
2024-12-21T16:49:31+0000 trace LambdaRuntime : [APIGatewayLambda] Event: APIGatewayV2Request(version: "2.0", routeKey: "$default", rawPath: "/", rawQueryString: "", cookies: [], headers: ["x-forwarded-proto": "https", "host": "a5q74es3k2.execute-api.us-east-1.amazonaws.com", "content-length": "0", "x-forwarded-for": "81.0.0.43", "accept": "*/*", "x-amzn-trace-id": "Root=1-66fb03de-07533930192eaf5f540db0cb", "x-forwarded-port": "443", "user-agent": "curl/8.7.1"], queryStringParameters: [:], pathParameters: [:], context: AWSLambdaEvents.APIGatewayV2Request.Context(accountId: "012345678901", apiId: "a5q74es3k2", domainName: "a5q74es3k2.execute-api.us-east-1.amazonaws.com", domainPrefix: "a5q74es3k2", stage: "$default", requestId: "e72KxgsRoAMEMSA=", http: AWSLambdaEvents.APIGatewayV2Request.Context.HTTP(method: GET, path: "/", protocol: "HTTP/1.1", sourceIp: "81.0.0.43", userAgent: "curl/8.7.1"), authorizer: nil, authentication: nil, time: "30/Sep/2024:20:02:38 +0000", timeEpoch: 1727726558220), stageVariables: [:], body: Optional("aGVsbG8gd29ybGQgb2YgU1dJRlQgTEFNQkRBIQ=="), isBase64Encoded: false)
|
||||
END RequestId: 5b71587a-39da-445e-855d-27a700e57efd
|
||||
|
||||
@@ -18,7 +18,7 @@ import Logging
|
||||
import Testing
|
||||
|
||||
@testable import APIGatewayLambda // to access the business code
|
||||
@testable import AWSLambdaRuntimeCore // to access the LambdaContext
|
||||
@testable import AWSLambdaRuntime // to access the LambdaContext
|
||||
|
||||
#if canImport(FoundationEssentials)
|
||||
import FoundationEssentials
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// swift-tools-version:6.0
|
||||
// swift-tools-version:6.1
|
||||
|
||||
import PackageDescription
|
||||
|
||||
@@ -6,17 +6,8 @@ let package = Package(
|
||||
name: "swift-aws-lambda-runtime",
|
||||
platforms: [.macOS(.v15)],
|
||||
products: [
|
||||
|
||||
//
|
||||
// The runtime library targets
|
||||
//
|
||||
|
||||
// this library exports `AWSLambdaRuntimeCore` and adds Foundation convenience methods
|
||||
.library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]),
|
||||
|
||||
// this has all the main functionality for lambda and it does not link Foundation
|
||||
.library(name: "AWSLambdaRuntimeCore", targets: ["AWSLambdaRuntimeCore"]),
|
||||
|
||||
//
|
||||
// The plugins
|
||||
// 'lambda-init' creates a new Lambda function
|
||||
@@ -34,36 +25,40 @@ let package = Package(
|
||||
|
||||
// plugin to deploy a Lambda function
|
||||
.plugin(name: "AWSLambdaDeployer", targets: ["AWSLambdaDeployer"]),
|
||||
|
||||
//
|
||||
// Testing targets
|
||||
//
|
||||
|
||||
// for testing only
|
||||
.library(name: "AWSLambdaTesting", targets: ["AWSLambdaTesting"]),
|
||||
],
|
||||
traits: [
|
||||
"FoundationJSONSupport",
|
||||
"ServiceLifecycleSupport",
|
||||
"LocalServerSupport",
|
||||
.default(
|
||||
enabledTraits: [
|
||||
"FoundationJSONSupport",
|
||||
"ServiceLifecycleSupport",
|
||||
"LocalServerSupport",
|
||||
]
|
||||
),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/apple/swift-nio.git", from: "2.76.0"),
|
||||
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
|
||||
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"),
|
||||
.package(url: "https://github.com/apple/swift-collections.git", from: "1.1.4"),
|
||||
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.6.3"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "AWSLambdaRuntime",
|
||||
dependencies: [
|
||||
.byName(name: "AWSLambdaRuntimeCore"),
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
]
|
||||
),
|
||||
.target(
|
||||
name: "AWSLambdaRuntimeCore",
|
||||
dependencies: [
|
||||
.product(name: "DequeModule", package: "swift-collections"),
|
||||
.product(name: "Logging", package: "swift-log"),
|
||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
],
|
||||
swiftSettings: [.swiftLanguageMode(.v5)]
|
||||
.product(
|
||||
name: "ServiceLifecycle",
|
||||
package: "swift-service-lifecycle",
|
||||
condition: .when(traits: ["ServiceLifecycleSupport"])
|
||||
),
|
||||
]
|
||||
),
|
||||
.plugin(
|
||||
name: "AWSLambdaInitializer",
|
||||
@@ -146,45 +141,23 @@ let package = Package(
|
||||
],
|
||||
swiftSettings: [.swiftLanguageMode(.v6)]
|
||||
),
|
||||
.testTarget(
|
||||
name: "AWSLambdaRuntimeCoreTests",
|
||||
dependencies: [
|
||||
.byName(name: "AWSLambdaRuntimeCore"),
|
||||
.product(name: "NIOTestUtils", package: "swift-nio"),
|
||||
.product(name: "NIOFoundationCompat", package: "swift-nio"),
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "AWSLambdaRuntimeTests",
|
||||
dependencies: [
|
||||
.byName(name: "AWSLambdaRuntimeCore"),
|
||||
.byName(name: "AWSLambdaRuntime"),
|
||||
]
|
||||
),
|
||||
// testing helper
|
||||
.target(
|
||||
name: "AWSLambdaTesting",
|
||||
dependencies: [
|
||||
.byName(name: "AWSLambdaRuntime"),
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "AWSLambdaTestingTests",
|
||||
dependencies: [
|
||||
.byName(name: "AWSLambdaTesting")
|
||||
.product(name: "NIOTestUtils", package: "swift-nio"),
|
||||
.product(name: "NIOFoundationCompat", package: "swift-nio"),
|
||||
]
|
||||
),
|
||||
// for perf testing
|
||||
.executableTarget(
|
||||
name: "MockServer",
|
||||
dependencies: [
|
||||
.product(name: "Logging", package: "swift-log"),
|
||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
],
|
||||
swiftSettings: [.swiftLanguageMode(.v5)]
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "AWSLambdaPluginHelperTests",
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
// swift-tools-version:6.0
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "swift-aws-lambda-runtime",
|
||||
platforms: [.macOS(.v15)],
|
||||
products: [
|
||||
.library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]),
|
||||
|
||||
//
|
||||
// The plugins
|
||||
// 'lambda-init' creates a new Lambda function
|
||||
// 'lambda-build' packages the Lambda function
|
||||
// 'lambda-deploy' deploys the Lambda function
|
||||
//
|
||||
// Plugins requires Linux or at least macOS v15
|
||||
//
|
||||
|
||||
// plugin to create a new Lambda function, based on a template
|
||||
.plugin(name: "AWSLambdaInitializer", targets: ["AWSLambdaInitializer"]),
|
||||
|
||||
// plugin to package the lambda, creating an archive that can be uploaded to AWS
|
||||
.plugin(name: "AWSLambdaBuilder", targets: ["AWSLambdaBuilder"]),
|
||||
|
||||
// plugin to deploy a Lambda function
|
||||
.plugin(name: "AWSLambdaDeployer", targets: ["AWSLambdaDeployer"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/apple/swift-nio.git", from: "2.81.0"),
|
||||
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"),
|
||||
.package(url: "https://github.com/apple/swift-collections.git", from: "1.1.4"),
|
||||
.package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "2.6.3"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "AWSLambdaRuntime",
|
||||
dependencies: [
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
.product(name: "DequeModule", package: "swift-collections"),
|
||||
.product(name: "Logging", package: "swift-log"),
|
||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
|
||||
],
|
||||
swiftSettings: [
|
||||
.define("FoundationJSONSupport"),
|
||||
.define("ServiceLifecycleSupport"),
|
||||
.define("LocalServerSupport"),
|
||||
]
|
||||
),
|
||||
.plugin(
|
||||
name: "AWSLambdaInitializer",
|
||||
capability: .command(
|
||||
intent: .custom(
|
||||
verb: "lambda-init",
|
||||
description:
|
||||
"Create a new Lambda function in the current project directory."
|
||||
),
|
||||
permissions: [
|
||||
.writeToPackageDirectory(reason: "Create a file with an HelloWorld Lambda function.")
|
||||
]
|
||||
),
|
||||
dependencies: [
|
||||
.target(name: "AWSLambdaPluginHelper")
|
||||
]
|
||||
),
|
||||
// keep this one (with "archive") to not break workflows
|
||||
// This will be deprecated at some point in the future
|
||||
// .plugin(
|
||||
// name: "AWSLambdaPackager",
|
||||
// capability: .command(
|
||||
// intent: .custom(
|
||||
// verb: "archive",
|
||||
// description:
|
||||
// "Archive the Lambda binary and prepare it for uploading to AWS. Requires docker on macOS or non Amazonlinux 2 distributions."
|
||||
// ),
|
||||
// permissions: [
|
||||
// .allowNetworkConnections(
|
||||
// scope: .docker,
|
||||
// reason: "This plugin uses Docker to create the AWS Lambda ZIP package."
|
||||
// )
|
||||
// ]
|
||||
// ),
|
||||
// path: "Plugins/AWSLambdaBuilder" // same sources as the new "lambda-build" plugin
|
||||
// ),
|
||||
.plugin(
|
||||
name: "AWSLambdaBuilder",
|
||||
capability: .command(
|
||||
intent: .custom(
|
||||
verb: "lambda-build",
|
||||
description:
|
||||
"Archive the Lambda binary and prepare it for uploading to AWS. Requires docker on macOS or non Amazonlinux 2 distributions."
|
||||
),
|
||||
permissions: [
|
||||
.allowNetworkConnections(
|
||||
scope: .docker,
|
||||
reason: "This plugin uses Docker to create the AWS Lambda ZIP package."
|
||||
)
|
||||
]
|
||||
),
|
||||
dependencies: [
|
||||
.target(name: "AWSLambdaPluginHelper")
|
||||
]
|
||||
),
|
||||
.plugin(
|
||||
name: "AWSLambdaDeployer",
|
||||
capability: .command(
|
||||
intent: .custom(
|
||||
verb: "lambda-deploy",
|
||||
description:
|
||||
"Deploy the Lambda function. You must have an AWS account and know an access key and secret access key."
|
||||
),
|
||||
permissions: [
|
||||
.allowNetworkConnections(
|
||||
scope: .all(ports: [443]),
|
||||
reason: "This plugin uses the AWS Lambda API to deploy the function."
|
||||
)
|
||||
]
|
||||
),
|
||||
dependencies: [
|
||||
.target(name: "AWSLambdaPluginHelper")
|
||||
]
|
||||
),
|
||||
.executableTarget(
|
||||
name: "AWSLambdaPluginHelper",
|
||||
dependencies: [
|
||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
],
|
||||
swiftSettings: [.swiftLanguageMode(.v6)]
|
||||
),
|
||||
.testTarget(
|
||||
name: "AWSLambdaRuntimeTests",
|
||||
dependencies: [
|
||||
.byName(name: "AWSLambdaRuntime"),
|
||||
.product(name: "NIOTestUtils", package: "swift-nio"),
|
||||
.product(name: "NIOFoundationCompat", package: "swift-nio"),
|
||||
]
|
||||
),
|
||||
// for perf testing
|
||||
.executableTarget(
|
||||
name: "MockServer",
|
||||
dependencies: [
|
||||
.product(name: "Logging", package: "swift-log"),
|
||||
.product(name: "NIOHTTP1", package: "swift-nio"),
|
||||
.product(name: "NIOCore", package: "swift-nio"),
|
||||
.product(name: "NIOPosix", package: "swift-nio"),
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
||||
@@ -201,11 +201,29 @@ struct Builder {
|
||||
let resourcesDirectoryName = artifactURL.lastPathComponent
|
||||
let relocatedResourcesDirectory = workingDirectory.appending(path: resourcesDirectoryName)
|
||||
if FileManager.default.fileExists(atPath: artifactURL.path()) {
|
||||
try FileManager.default.copyItem(
|
||||
atPath: artifactURL.path(),
|
||||
toPath: relocatedResourcesDirectory.path()
|
||||
)
|
||||
arguments.append(resourcesDirectoryName)
|
||||
do {
|
||||
try FileManager.default.copyItem(
|
||||
atPath: artifactURL.path(),
|
||||
toPath: relocatedResourcesDirectory.path()
|
||||
)
|
||||
arguments.append(resourcesDirectoryName)
|
||||
} catch let error as CocoaError {
|
||||
|
||||
// On Linux, when the build has been done with Docker,
|
||||
// the source file are owned by root
|
||||
// this causes a permission error **after** the files have been copied
|
||||
// see https://github.com/swift-server/swift-aws-lambda-runtime/issues/449
|
||||
// see https://forums.swift.org/t/filemanager-copyitem-on-linux-fails-after-copying-the-files/77282
|
||||
|
||||
// because this error happens after the files have been copied, we can ignore it
|
||||
// this code checks if the destination file exists
|
||||
// if they do, just ignore error, otherwise throw it up to the caller.
|
||||
if !(error.code == CocoaError.Code.fileWriteNoPermission
|
||||
&& FileManager.default.fileExists(atPath: relocatedResourcesDirectory.path()))
|
||||
{
|
||||
throw error
|
||||
} // else just ignore it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +249,7 @@ struct Builder {
|
||||
|
||||
USAGE: swift package --allow-network-connections docker archive
|
||||
[--help] [--verbose]
|
||||
[--output-directory <path>]
|
||||
[--output-path <path>]
|
||||
[--products <list of products>]
|
||||
[--configuration debug | release]
|
||||
[--swift-version <version>]
|
||||
@@ -241,7 +259,7 @@ struct Builder {
|
||||
|
||||
OPTIONS:
|
||||
--verbose Produce verbose output for debugging.
|
||||
--output-directory <path> The path of the binary package.
|
||||
--output-path <path> The path of the binary package.
|
||||
(default is `.build/plugins/AWSLambdaPackager/outputs/...`)
|
||||
--products <list> The list of executable targets to build.
|
||||
(default is taken from Package.swift)
|
||||
|
||||
@@ -93,7 +93,8 @@ struct ControlPlaneRequestEncoder: _EmittingChannelHandler {
|
||||
extension String {
|
||||
static let CRLF: String = "\r\n"
|
||||
|
||||
static let userAgentHeader: String = "user-agent: Swift-Lambda/Unknown\r\n"
|
||||
static let userAgent = "Swift-Lambda/Unknown"
|
||||
static let userAgentHeader: String = "user-agent: \(userAgent)\r\n"
|
||||
static let unhandledErrorHeader: String = "lambda-runtime-function-error-type: Unhandled\r\n"
|
||||
|
||||
static let nextInvocationRequestLine: String =
|
||||
@@ -1,4 +1,4 @@
|
||||
# ``AWSLambdaRuntimeCore``
|
||||
# ``AWSLambdaRuntime``
|
||||
|
||||
An AWS Lambda runtime for the Swift programming language
|
||||
|
||||
@@ -40,7 +40,7 @@ Server ecosystem is to shift to newer, more readable, Swift concurrency construc
|
||||
#### No ownership of the main() function
|
||||
|
||||
A Lambda function can currently be implemented through conformance to the various handler protocols defined in
|
||||
`AWSLambdaRuntimeCore/LambdaHandler`. Each of these protocols have an extension which implements a `static func main()`.
|
||||
``AWSLambdaRuntime/LambdaHandler``. Each of these protocols have an extension which implements a `static func main()`.
|
||||
This allows users to annotate their `LambdaHandler` conforming object with `@main`. The `static func main()` calls the
|
||||
internal `Lambda.run()` function, which starts the Lambda function. Since the `Lambda.run()` method is internal, users
|
||||
cannot override the default implementation. This has proven challenging for users who want to
|
||||
@@ -80,7 +80,7 @@ initialized services:
|
||||
struct MyLambda: LambdaHandler {
|
||||
let pgClient: PostgresClient
|
||||
|
||||
init(context: AWSLambdaRuntimeCore.LambdaInitializationContext) async throws {
|
||||
init(context: AWSLambdaRuntime.LambdaInitializationContext) async throws {
|
||||
/// Instantiate service
|
||||
let client = PostgresClient(configuration: ...)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
2025-01-02T14:59:29+0100 info LocalLambdaServer : [AWSLambdaRuntimeCore]
|
||||
2025-01-02T14:59:29+0100 info LocalLambdaServer : [AWSLambdaRuntime]
|
||||
LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke
|
||||
@@ -3,4 +3,4 @@ swift run
|
||||
Building for debugging...
|
||||
[1/1] Write swift-version--58304C5D6DBC2206.txt
|
||||
Build of product 'PalindromeLambda' complete! (0.11s)
|
||||
2025-01-02T15:12:49+0100 info LocalLambdaServer : [AWSLambdaRuntimeCore] LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke
|
||||
2025-01-02T15:12:49+0100 info LocalLambdaServer : [AWSLambdaRuntime] LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke
|
||||
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 558 KiB After Width: | Height: | Size: 558 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 803 KiB After Width: | Height: | Size: 803 KiB |
|
Before Width: | Height: | Size: 838 KiB After Width: | Height: | Size: 838 KiB |
|
Before Width: | Height: | Size: 301 KiB After Width: | Height: | Size: 301 KiB |
|
Before Width: | Height: | Size: 558 KiB After Width: | Height: | Size: 558 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 422 KiB After Width: | Height: | Size: 422 KiB |
|
Before Width: | Height: | Size: 426 KiB After Width: | Height: | Size: 426 KiB |
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 225 KiB |
|
Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 226 KiB |
|
Before Width: | Height: | Size: 363 KiB After Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 359 KiB After Width: | Height: | Size: 359 KiB |
|
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 320 KiB |
|
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 307 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |