Skip to content

Commit cc89338

Browse files
committed
move service conformance to a separate class
1 parent ba85f5b commit cc89338

File tree

3 files changed

+93
-5
lines changed

3 files changed

+93
-5
lines changed

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ let package = Package(
2727
dependencies: [
2828
.byName(name: "AWSLambdaRuntimeCore"),
2929
.product(name: "NIOCore", package: "swift-nio"),
30+
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
3031
]
3132
),
3233
.target(
@@ -37,7 +38,6 @@ let package = Package(
3738
.product(name: "NIOCore", package: "swift-nio"),
3839
.product(name: "NIOConcurrencyHelpers", package: "swift-nio"),
3940
.product(name: "NIOPosix", package: "swift-nio"),
40-
.product(name: "ServiceLifecycle", package: "swift-service-lifecycle"),
4141
],
4242
swiftSettings: [.swiftLanguageMode(.v5)]
4343
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
@_exported import AWSLambdaRuntimeCore
16+
import NIOCore
17+
18+
import ServiceLifecycle
19+
#if canImport(FoundationEssentials)
20+
import FoundationEssentials
21+
#else
22+
import struct Foundation.Data
23+
import class Foundation.JSONDecoder
24+
import class Foundation.JSONEncoder
25+
#endif
26+
27+
///
28+
/// Encapsulate a LambdaRuntime+Codable to offer the same API but this time exposed as a Swift Service
29+
/// This allows to continue to avoid the Service payload for Lambda functions that doesn't need it
30+
///
31+
public class LambdaRuntimeService<Handler>: Service, @unchecked Sendable where Handler: StreamingLambdaHandler {
32+
33+
private let runtime: LambdaRuntime<Handler>
34+
35+
/// Initialize an instance with a `LambdaHandler` defined in the form of a closure **with a non-`Void` return type**.
36+
/// - Parameters:
37+
/// - decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. `JSONDecoder()` used as default.
38+
/// - encoder: The encoder object that will be used to encode the generic `Output` into a `ByteBuffer`. `JSONEncoder()` used as default.
39+
/// - body: The handler in the form of a closure.
40+
public init<Event: Decodable, Output>(
41+
decoder: JSONDecoder = JSONDecoder(),
42+
encoder: JSONEncoder = JSONEncoder(),
43+
body: sending @escaping (Event, LambdaContext) async throws -> Output
44+
)
45+
where
46+
Handler == LambdaCodableAdapter<
47+
LambdaHandlerAdapter<Event, Output, ClosureHandler<Event, Output>>,
48+
Event,
49+
Output,
50+
LambdaJSONEventDecoder,
51+
LambdaJSONOutputEncoder<Output>
52+
>
53+
{
54+
let handler = LambdaCodableAdapter(
55+
encoder: encoder,
56+
decoder: decoder,
57+
handler: LambdaHandlerAdapter(handler: ClosureHandler(body: body))
58+
)
59+
60+
self.runtime = LambdaRuntime(handler: handler)
61+
}
62+
63+
/// Initialize an instance with a `LambdaHandler` defined in the form of a closure **with a `Void` return type**.
64+
/// - Parameter body: The handler in the form of a closure.
65+
/// - Parameter decoder: The decoder object that will be used to decode the incoming `ByteBuffer` event into the generic `Event` type. `JSONDecoder()` used as default.
66+
public init<Event: Decodable>(
67+
decoder: JSONDecoder = JSONDecoder(),
68+
body: sending @escaping (Event, LambdaContext) async throws -> Void
69+
)
70+
where
71+
Handler == LambdaCodableAdapter<
72+
LambdaHandlerAdapter<Event, Void, ClosureHandler<Event, Void>>,
73+
Event,
74+
Void,
75+
LambdaJSONEventDecoder,
76+
VoidEncoder
77+
>
78+
{
79+
let handler = LambdaCodableAdapter(
80+
decoder: LambdaJSONEventDecoder(decoder),
81+
handler: LambdaHandlerAdapter(handler: ClosureHandler(body: body))
82+
)
83+
84+
self.runtime = LambdaRuntime(handler: handler)
85+
}
86+
87+
public func run() async throws {
88+
try await self.runtime.run()
89+
}
90+
}

Sources/AWSLambdaRuntimeCore/LambdaRuntime.swift

+2-4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import Logging
1616
import NIOConcurrencyHelpers
1717
import NIOCore
18-
import ServiceLifecycle
1918

2019
#if canImport(FoundationEssentials)
2120
import FoundationEssentials
@@ -26,12 +25,11 @@ import Foundation
2625
// We need `@unchecked` Sendable here, as `NIOLockedValueBox` does not understand `sending` today.
2726
// We don't want to use `NIOLockedValueBox` here anyway. We would love to use Mutex here, but this
2827
// sadly crashes the compiler today.
29-
public final class LambdaRuntime<Handler>: Service, @unchecked Sendable where Handler: StreamingLambdaHandler {
28+
public final class LambdaRuntime<Handler>: @unchecked Sendable where Handler: StreamingLambdaHandler {
3029
// TODO: We want to change this to Mutex as soon as this doesn't crash the Swift compiler on Linux anymore
3130
let handlerMutex: NIOLockedValueBox<Handler?>
3231

33-
// logger is accessible from the outside, but only mutable from the inside
34-
public private(set) var logger: Logger
32+
let logger: Logger
3533
let eventLoop: EventLoop
3634

3735
public init(

0 commit comments

Comments
 (0)