Skip to content

Commit 3ca2b0f

Browse files
committed
Implement COS event
1 parent f093dc0 commit 3ca2b0f

File tree

8 files changed

+461
-274
lines changed

8 files changed

+461
-274
lines changed

README.md

Lines changed: 83 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -27,107 +27,107 @@ If you have never used AWS Lambda or Docker before, check out this [getting star
2727

2828
First, create a SwiftPM project and pull Swift AWS Lambda Runtime as dependency into your project
2929

30-
```swift
31-
// swift-tools-version:5.2
32-
33-
import PackageDescription
34-
35-
let package = Package(
36-
name: "my-cloud-function",
37-
products: [
38-
.executable(name: "MyCloudFunction", targets: ["MyCloudFunction"]),
39-
],
40-
dependencies: [
41-
.package(url: "https://github.com/stevapple/swift-tencent-scf-runtime.git", from: "0.1.0"),
42-
],
43-
targets: [
44-
.target(name: "MyCloudFunction", dependencies: [
45-
.product(name: "TencentSCFRuntime", package: "tencent-scf-runtime"),
46-
]),
47-
]
48-
)
49-
```
30+
```swift
31+
// swift-tools-version:5.2
32+
33+
import PackageDescription
34+
35+
let package = Package(
36+
name: "my-cloud-function",
37+
products: [
38+
.executable(name: "MyCloudFunction", targets: ["MyCloudFunction"]),
39+
],
40+
dependencies: [
41+
.package(url: "https://github.com/stevapple/swift-tencent-scf-runtime.git", from: "0.1.0"),
42+
],
43+
targets: [
44+
.target(name: "MyCloudFunction", dependencies: [
45+
.product(name: "TencentSCFRuntime", package: "tencent-scf-runtime"),
46+
]),
47+
]
48+
)
49+
```
5050

5151
Next, create a `main.swift` and implement your Lambda.
5252

53-
### Using Closures
53+
### Using Closures
5454

55-
The simplest way to use `TencentSCFRuntime` is to pass in a closure, for example:
55+
The simplest way to use `TencentSCFRuntime` is to pass in a closure, for example:
5656

57-
```swift
58-
// Import the module
59-
import TencentSCFRuntime
57+
```swift
58+
// Import the module
59+
import TencentSCFRuntime
6060

61-
// in this example we are receiving and responding with strings
62-
Lambda.run { (context, name: String, callback: @escaping (Result<String, Error>) -> Void) in
63-
callback(.success("Hello, \(name)"))
64-
}
61+
// in this example we are receiving and responding with strings
62+
Lambda.run { (context, name: String, callback: @escaping (Result<String, Error>) -> Void) in
63+
callback(.success("Hello, \(name)"))
64+
}
6565
```
6666

67-
More commonly, the event would be a JSON, which is modeled using `Codable`, for example:
68-
69-
```swift
70-
// Import the module
71-
import TencentSCFRuntime
67+
More commonly, the event would be a JSON, which is modeled using `Codable`, for example:
7268

73-
// Request, uses Codable for transparent JSON encoding
74-
private struct Request: Codable {
75-
let name: String
76-
}
69+
```swift
70+
// Import the module
71+
import TencentSCFRuntime
7772

78-
// Response, uses Codable for transparent JSON encoding
79-
private struct Response: Codable {
80-
let message: String
81-
}
73+
// Request, uses Codable for transparent JSON encoding
74+
private struct Request: Codable {
75+
let name: String
76+
}
8277

83-
// In this example we are receiving and responding with `Codable`.
84-
Lambda.run { (context, request: Request, callback: @escaping (Result<Response, Error>) -> Void) in
85-
callback(.success(Response(message: "Hello, \(request.name)")))
86-
}
87-
```
78+
// Response, uses Codable for transparent JSON encoding
79+
private struct Response: Codable {
80+
let message: String
81+
}
8882

89-
Since most Lambda functions are triggered by events originating in the AWS platform like `SNS`, `SQS` or `APIGateway`, the package also includes a `AWSLambdaEvents` module that provides implementations for most common AWS event types further simplifying writing Lambda functions. For example, handling an `SQS` message:
83+
// In this example we are receiving and responding with `Codable`.
84+
Lambda.run { (context, request: Request, callback: @escaping (Result<Response, Error>) -> Void) in
85+
callback(.success(Response(message: "Hello, \(request.name)")))
86+
}
87+
```
9088

91-
```swift
92-
// Import the modules
93-
import TencentSCFRuntime
94-
import TencentSCFEvents
89+
Since most Lambda functions are triggered by events originating in the AWS platform like `SNS`, `SQS` or `APIGateway`, the package also includes a `TencentSCFEvents` module that provides implementations for most common AWS event types further simplifying writing Lambda functions. For example, handling an `SQS` message:
9590

96-
// In this example we are receiving an SQS Message, with no response (Void).
97-
Lambda.run { (context, message: SQS.Message, callback: @escaping (Result<Void, Error>) -> Void) in
98-
...
99-
callback(.success(Void()))
100-
}
101-
```
91+
```swift
92+
// Import the modules
93+
import TencentSCFRuntime
94+
import TencentSCFEvents
95+
96+
// In this example we are receiving an SQS Message, with no response (Void).
97+
Lambda.run { (context, message: SQS.Message, callback: @escaping (Result<Void, Error>) -> Void) in
98+
...
99+
callback(.success(Void()))
100+
}
101+
```
102102

103-
Modeling Lambda functions as Closures is both simple and safe. Swift AWS Lambda Runtime will ensure that the user-provided code is offloaded from the network processing thread such that even if the code becomes slow to respond or gets hang, the underlying process can continue to function. This safety comes at a small performance penalty from context switching between threads. In many cases, the simplicity and safety of using the Closure based API is often preferred over the complexity of the performance-oriented API.
103+
Modeling Lambda functions as Closures is both simple and safe. Swift AWS Lambda Runtime will ensure that the user-provided code is offloaded from the network processing thread such that even if the code becomes slow to respond or gets hang, the underlying process can continue to function. This safety comes at a small performance penalty from context switching between threads. In many cases, the simplicity and safety of using the Closure based API is often preferred over the complexity of the performance-oriented API.
104104

105105
### Using EventLoopLambdaHandler
106106

107-
Performance sensitive Lambda functions may choose to use a more complex API which allows user code to run on the same thread as the networking handlers. Swift AWS Lambda Runtime uses [SwiftNIO](https://github.com/apple/swift-nio) as its underlying networking engine which means the APIs are based on [SwiftNIO](https://github.com/apple/swift-nio) concurrency primitives like the `EventLoop` and `EventLoopFuture`. For example:
108-
109-
```swift
110-
// Import the modules
111-
import TencentSCFRuntime
112-
import TencentSCFEvents
113-
import NIO
107+
Performance sensitive Lambda functions may choose to use a more complex API which allows user code to run on the same thread as the networking handlers. Swift AWS Lambda Runtime uses [SwiftNIO](https://github.com/apple/swift-nio) as its underlying networking engine which means the APIs are based on [SwiftNIO](https://github.com/apple/swift-nio) concurrency primitives like the `EventLoop` and `EventLoopFuture`. For example:
114108

115-
// Our Lambda handler, conforms to EventLoopLambdaHandler
116-
struct Handler: EventLoopLambdaHandler {
117-
typealias In = SNS.Message // Request type
118-
typealias Out = Void // Response type
119-
120-
// In this example we are receiving an SNS Message, with no response (Void).
121-
func handle(context: Lambda.Context, event: In) -> EventLoopFuture<Out> {
122-
...
123-
context.eventLoop.makeSucceededFuture(Void())
124-
}
125-
}
109+
```swift
110+
// Import the modules
111+
import TencentSCFRuntime
112+
import TencentSCFEvents
113+
import NIO
114+
115+
// Our Lambda handler, conforms to EventLoopLambdaHandler
116+
struct Handler: EventLoopLambdaHandler {
117+
typealias In = SNS.Message // Request type
118+
typealias Out = Void // Response type
119+
120+
// In this example we are receiving an SNS Message, with no response (Void).
121+
func handle(context: Lambda.Context, event: In) -> EventLoopFuture<Out> {
122+
...
123+
context.eventLoop.makeSucceededFuture(Void())
124+
}
125+
}
126126

127-
Lambda.run(Handler())
128-
```
127+
Lambda.run(Handler())
128+
```
129129

130-
Beyond the small cognitive complexity of using the `EventLoopFuture` based APIs, note these APIs should be used with extra care. An `EventLoopLambdaHandler` will execute the user code on the same `EventLoop` (thread) as the library, making processing faster but requiring the user code to never call blocking APIs as it might prevent the underlying process from functioning.
130+
Beyond the small cognitive complexity of using the `EventLoopFuture` based APIs, note these APIs should be used with extra care. An `EventLoopLambdaHandler` will execute the user code on the same `EventLoop` (thread) as the library, making processing faster but requiring the user code to never call blocking APIs as it might prevent the underlying process from functioning.
131131

132132
## Deploying to AWS Lambda
133133

@@ -331,12 +331,12 @@ That loop is broken if/when an internal error occurs, such as a failure to commu
331331

332332
By default, the library also registers a Signal handler that traps `INT` and `TERM` , which are typical Signals used in modern deployment platforms to communicate shutdown request.
333333

334-
### Integration with AWS Platform Events
334+
### Integration with Tencent Cloud Platform Events
335335

336-
AWS Lambda functions can be invoked directly from the AWS Lambda console UI, AWS Lambda API, AWS SDKs, AWS CLI, and AWS toolkits. More commonly, they are invoked as a reaction to an events coming from the AWS platform. To make it easier to integrate with AWS platform events, the library includes an `AWSLambdaEvents` target which provides abstractions for many commonly used events. Additional events can be easily modeled when needed following the same patterns set by `AWSLambdaEvents`. Integration points with the AWS Platform include:
336+
Tencent SCFs can be invoked directly from the Tencent SCF console, Tencent SCF API, TCCLI and Tencent Cloud toolkit. More commonly, they are invoked as a reaction to an events coming from the Tencent Cloud platform. To make it easier to integrate with Tencent Cloud platform events, the library includes an `TencentSCFEvents` target which provides abstractions for many commonly used events. Additional events can be easily modeled when needed following the same patterns set by `TencentSCFEvents`. Integration points with the Tencent Cloud Platform include:
337337

338338
* [APIGateway Proxy](https://docs.aws.amazon.com/lambda/latest/dg/services-apigateway.html)
339-
* [S3 Events](https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html)
339+
* [COS](https://cloud.tencent.com/document/product/583/9707)
340340
* [SES Events](https://docs.aws.amazon.com/lambda/latest/dg/services-ses.html)
341341
* [SNS Events](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html)
342342
* [SQS Events](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===------------------------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftTencentSCFRuntime open source project
4+
//
5+
// Copyright (c) 2020 stevapple and the SwiftTencentSCFRuntime 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 SwiftTencentSCFRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===------------------------------------------------------------------------------------===//
14+
15+
import struct Foundation.Date
16+
import struct Foundation.URL
17+
18+
// https://cloud.tencent.com/document/product/583/9707
19+
20+
public enum COS {
21+
public struct Event: Codable, Equatable {
22+
public struct Record: Equatable {
23+
public let cos: Entity
24+
25+
public let eventName: String
26+
public let eventVersion: String
27+
public let eventTime: Date
28+
public let eventSource: String
29+
public let requestParameters: RequestParameters
30+
public let eventQueue: String
31+
public let reservedInfo: String
32+
public let requestId: UInt64
33+
}
34+
35+
public let records: [Record]
36+
37+
public enum CodingKeys: String, CodingKey {
38+
case records = "Records"
39+
}
40+
}
41+
42+
public struct RequestParameters: Codable, Equatable {
43+
public let sourceIP: String
44+
public let headers: [String: String]
45+
46+
enum CodingKeys: String, CodingKey {
47+
case sourceIP = "requestSourceIP"
48+
case headers = "requestHeaders"
49+
}
50+
}
51+
52+
public struct Entity: Codable, Equatable {
53+
public let notificationId: String
54+
public let schemaVersion: String
55+
public let bucket: Bucket
56+
public let object: Object
57+
58+
enum CodingKeys: String, CodingKey {
59+
case notificationId = "cosNotificationId"
60+
case schemaVersion = "cosSchemaVersion"
61+
case bucket = "cosBucket"
62+
case object = "cosObject"
63+
}
64+
}
65+
66+
public struct Bucket: Codable, Equatable {
67+
public let region: String
68+
public let name: String
69+
public let appid: String
70+
}
71+
72+
public struct Object: Equatable {
73+
public let url: URL
74+
public let key: String
75+
public let vid: String
76+
public let size: UInt64
77+
78+
public let contentType: String?
79+
public let cacheControl: String?
80+
public let contentDisposition: String?
81+
public let contentEncoding: String?
82+
public let requestId: String?
83+
84+
public let expireTime: Date?
85+
public let customMeta: [String: String]
86+
}
87+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===------------------------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftTencentSCFRuntime open source project
4+
//
5+
// Copyright (c) 2020 stevapple and the SwiftTencentSCFRuntime 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 SwiftTencentSCFRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===------------------------------------------------------------------------------------===//
14+
15+
import struct Foundation.Date
16+
17+
extension COS.Event.Record: Codable {
18+
enum CodingKeys: String, CodingKey {
19+
case event
20+
case cos
21+
}
22+
23+
enum EventCodingKeys: String, CodingKey {
24+
case eventName
25+
case eventVersion
26+
case eventTime
27+
case eventSource
28+
case requestParameters
29+
case eventQueue
30+
case reservedInfo
31+
case requestId = "reqid"
32+
}
33+
34+
public init(from decoder: Decoder) throws {
35+
let container = try decoder.container(keyedBy: CodingKeys.self)
36+
37+
cos = try container.decode(COS.Entity.self, forKey: .cos)
38+
39+
let eventContainer = try container.nestedContainer(keyedBy: EventCodingKeys.self, forKey: .event)
40+
eventName = try eventContainer.decode(String.self, forKey: .eventName)
41+
eventVersion = try eventContainer.decode(String.self, forKey: .eventVersion)
42+
eventSource = try eventContainer.decode(String.self, forKey: .eventSource)
43+
eventQueue = try eventContainer.decode(String.self, forKey: .eventQueue)
44+
reservedInfo = try eventContainer.decode(String.self, forKey: .reservedInfo)
45+
requestId = try eventContainer.decode(UInt64.self, forKey: .requestId)
46+
requestParameters = try eventContainer.decode(COS.RequestParameters.self, forKey: .requestParameters)
47+
eventTime = try eventContainer.decode(Date.self, forKey: .eventTime, using: DateCoding.UnixTimestamp.self)
48+
}
49+
50+
public func encode(to encoder: Encoder) throws {
51+
var container = encoder.container(keyedBy: CodingKeys.self)
52+
try container.encode(cos, forKey: .cos)
53+
54+
var eventContainer = container.nestedContainer(keyedBy: EventCodingKeys.self, forKey: .event)
55+
try eventContainer.encode(eventName, forKey: .eventName)
56+
try eventContainer.encode(eventVersion, forKey: .eventVersion)
57+
try eventContainer.encode(eventSource, forKey: .eventSource)
58+
try eventContainer.encode(eventQueue, forKey: .eventQueue)
59+
try eventContainer.encode(eventTime, forKey: .eventTime, using: DateCoding.UnixTimestamp.self)
60+
try eventContainer.encode(requestParameters, forKey: .requestParameters)
61+
try eventContainer.encode(requestId, forKey: .requestId)
62+
try eventContainer.encode(reservedInfo, forKey: .reservedInfo)
63+
}
64+
}

0 commit comments

Comments
 (0)