Skip to content

Commit 81e6f0f

Browse files
committed
Implement CMQ Topic Event
1 parent 8610b59 commit 81e6f0f

File tree

6 files changed

+216
-29
lines changed

6 files changed

+216
-29
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ Tencent SCFs can be invoked directly from the Tencent SCF console, Tencent SCF A
337337

338338
* [COS Events](https://cloud.tencent.com/document/product/583/9707)
339339
* [Timer Events](https://cloud.tencent.com/document/product/583/9708)
340+
* [CMQ Topic Messages](https://cloud.tencent.com/document/product/583/11517)
340341
* [CKafka Messages](https://cloud.tencent.com/document/product/583/17530)
341342

342343
**Note**: Each one of the integration points mentioned above includes a set of `Codable` structs that transform Tencent Cloud's data model for these APIs.

Sources/TencentSCFEvents/CKafka.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public enum CKafka {
3030
public let offset: UInt64
3131
public let key: String
3232
public let body: String
33-
33+
3434
enum WrappingCodingKeys: String, CodingKey {
3535
case ckafka = "Ckafka"
3636
}
@@ -42,25 +42,25 @@ public enum CKafka {
4242
case key = "msgKey"
4343
case body = "msgBody"
4444
}
45-
46-
public func encode(to encoder: Encoder) throws {
47-
var wrapperContainer = encoder.container(keyedBy: WrappingCodingKeys.self)
48-
var container = wrapperContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .ckafka)
49-
try container.encode(topic, forKey: .topic)
50-
try container.encode(partition, forKey: .partition)
51-
try container.encode(offset, forKey: .offset)
52-
try container.encode(key, forKey: .key)
53-
try container.encode(body, forKey: .body)
54-
}
55-
45+
5646
public init(from decoder: Decoder) throws {
5747
let wrapperContainer = try decoder.container(keyedBy: WrappingCodingKeys.self)
5848
let container = try wrapperContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .ckafka)
59-
topic = try container.decode(String.self, forKey: .topic)
60-
partition = try container.decode(UInt64.self, forKey: .partition)
61-
offset = try container.decode(UInt64.self, forKey: .offset)
62-
key = try container.decode(String.self, forKey: .key)
63-
body = try container.decode(String.self, forKey: .body)
49+
self.topic = try container.decode(String.self, forKey: .topic)
50+
self.partition = try container.decode(UInt64.self, forKey: .partition)
51+
self.offset = try container.decode(UInt64.self, forKey: .offset)
52+
self.key = try container.decode(String.self, forKey: .key)
53+
self.body = try container.decode(String.self, forKey: .body)
54+
}
55+
56+
public func encode(to encoder: Encoder) throws {
57+
var wrapperContainer = encoder.container(keyedBy: WrappingCodingKeys.self)
58+
var container = wrapperContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .ckafka)
59+
try container.encode(self.topic, forKey: .topic)
60+
try container.encode(self.partition, forKey: .partition)
61+
try container.encode(self.offset, forKey: .offset)
62+
try container.encode(self.key, forKey: .key)
63+
try container.encode(self.body, forKey: .body)
6464
}
6565
}
6666
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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+
// https://cloud.tencent.com/document/product/583/11517
18+
19+
public enum CMQ {
20+
public enum Topic {
21+
public struct Event: Codable, Equatable {
22+
public let records: [Record]
23+
24+
public enum CodingKeys: String, CodingKey {
25+
case records = "Records"
26+
}
27+
}
28+
29+
public struct Record: Codable, Equatable {
30+
internal static let type: String = "topic"
31+
32+
public let topicOwner: UInt64
33+
public let topicName: String
34+
public let subscriptionName: String
35+
public let message: Message
36+
37+
enum WrappingCodingKeys: String, CodingKey {
38+
case cmq = "CMQ"
39+
}
40+
41+
enum CodingKeys: String, CodingKey {
42+
case type
43+
case topicOwner
44+
case topicName
45+
case subscriptionName
46+
}
47+
48+
public init(from decoder: Decoder) throws {
49+
let wrapperContainer = try decoder.container(keyedBy: WrappingCodingKeys.self)
50+
let container = try wrapperContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .cmq)
51+
let type = try container.decode(String.self, forKey: .type)
52+
guard type == Self.type else {
53+
throw DecodingError.dataCorruptedError(forKey: CodingKeys.type, in: container, debugDescription: #"Expected type to be "\#(Self.type)", but `\#(type)` does not match"#)
54+
}
55+
56+
message = try .init(from: try wrapperContainer.superDecoder(forKey: .cmq))
57+
topicOwner = try container.decode(UInt64.self, forKey: .topicOwner)
58+
topicName = try container.decode(String.self, forKey: .topicName)
59+
subscriptionName = try container.decode(String.self, forKey: .subscriptionName)
60+
}
61+
62+
public func encode(to encoder: Encoder) throws {
63+
var wrapperContainer = encoder.container(keyedBy: WrappingCodingKeys.self)
64+
try wrapperContainer.encode(message, forKey: .cmq)
65+
var container = wrapperContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .cmq)
66+
try container.encode(Self.type, forKey: .type)
67+
try container.encode(topicOwner, forKey: .topicOwner)
68+
try container.encode(topicName, forKey: .topicName)
69+
try container.encode(subscriptionName, forKey: .subscriptionName)
70+
}
71+
}
72+
73+
public struct Message: Codable, Equatable {
74+
internal static let separator: Character = ","
75+
76+
public let id: String
77+
public let body: String
78+
public let tags: [String]
79+
80+
public let requestId: String
81+
public let publishTime: Date
82+
83+
enum CodingKeys: String, CodingKey {
84+
case publishTime
85+
case messageId = "msgId"
86+
case requestId
87+
case messageBody = "msgBody"
88+
case messageTags = "msgTag"
89+
}
90+
91+
public init(from decoder: Decoder) throws {
92+
let container = try decoder.container(keyedBy: CodingKeys.self)
93+
id = try container.decode(String.self, forKey: .messageId)
94+
body = try container.decode(String.self, forKey: .messageBody)
95+
96+
let tagString = try container.decode(String.self, forKey: .messageTags)
97+
tags = tagString.split(separator: Self.separator)
98+
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
99+
100+
requestId = try container.decode(String.self, forKey: .requestId)
101+
publishTime = try container.decode(Date.self, forKey: .publishTime, using: DateCoding.ISO8601WithFractionalSeconds.self)
102+
}
103+
104+
public func encode(to encoder: Encoder) throws {
105+
var container = encoder.container(keyedBy: CodingKeys.self)
106+
try container.encode(id, forKey: .messageId)
107+
try container.encode(body, forKey: .messageBody)
108+
try container.encode(tags.joined(separator: .init(Self.separator)), forKey: .messageTags)
109+
try container.encode(publishTime, forKey: .publishTime, using: DateCoding.ISO8601WithFractionalSeconds.self)
110+
try container.encode(requestId, forKey: .requestId)
111+
}
112+
}
113+
}
114+
}

Sources/TencentSCFEvents/SCFTimer.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import struct Foundation.Date
1818

1919
public enum SCFTimer {
2020
public struct Event: Codable, Equatable {
21+
internal static let type: String = "Timer"
22+
2123
public let trigger: String
2224
public var time: Date
2325
public let message: String
@@ -29,23 +31,23 @@ public enum SCFTimer {
2931
case message = "Message"
3032
}
3133

32-
public func encode(to encoder: Encoder) throws {
33-
var container = encoder.container(keyedBy: CodingKeys.self)
34-
try container.encode("Timer", forKey: .type)
35-
try container.encode(trigger, forKey: .trigger)
36-
try container.encode(time, forKey: .time, using: DateCoding.ISO8601.self)
37-
try container.encode(message, forKey: .message)
38-
}
39-
4034
public init(from decoder: Decoder) throws {
4135
let container = try decoder.container(keyedBy: CodingKeys.self)
4236
let type = try container.decode(String.self, forKey: .type)
43-
guard type == "Timer" else {
44-
throw DecodingError.dataCorruptedError(forKey: CodingKeys.type, in: container, debugDescription: #"Expected type to be "Timer", but `\#(type)` does not match"#)
37+
guard type == Self.type else {
38+
throw DecodingError.dataCorruptedError(forKey: CodingKeys.type, in: container, debugDescription: #"Expected type to be "\#(Self.type)", but `\#(type)` does not match"#)
4539
}
4640
trigger = try container.decode(String.self, forKey: .trigger)
4741
time = try container.decode(Date.self, forKey: .time, using: DateCoding.ISO8601.self)
4842
message = try container.decode(String.self, forKey: .message)
4943
}
44+
45+
public func encode(to encoder: Encoder) throws {
46+
var container = encoder.container(keyedBy: CodingKeys.self)
47+
try container.encode(Self.type, forKey: .type)
48+
try container.encode(trigger, forKey: .trigger)
49+
try container.encode(time, forKey: .time, using: DateCoding.ISO8601.self)
50+
try container.encode(message, forKey: .message)
51+
}
5052
}
5153
}

Tests/TencentSCFEventsTests/CKafkaTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class CKafkaTests: XCTestCase {
5050
XCTFail("Expected to have two records")
5151
return
5252
}
53-
53+
5454
if let record = event?.records.first {
5555
XCTAssertEqual(record.topic, "test-topic")
5656
XCTAssertEqual(record.partition, 1)
@@ -61,7 +61,7 @@ class CKafkaTests: XCTestCase {
6161
XCTFail("Unexpected error")
6262
return
6363
}
64-
64+
6565
if let record = event?.records.last {
6666
XCTAssertEqual(record.topic, "test-topic")
6767
XCTAssertEqual(record.partition, 1)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
@testable import TencentSCFEvents
16+
import XCTest
17+
18+
class CMQTopicTests: XCTestCase {
19+
static let eventBody = """
20+
{
21+
"Records": [
22+
{
23+
"CMQ": {
24+
"type": "topic",
25+
"topicOwner":12014223,
26+
"topicName": "testtopic",
27+
"subscriptionName":"xxxxxx",
28+
"publishTime": "1970-01-01T00:00:00.000Z",
29+
"msgId": "123345346",
30+
"requestId":"123345346",
31+
"msgBody": "Hello from CMQ!",
32+
"msgTag": "tag1,tag2"
33+
}
34+
}
35+
]
36+
}
37+
"""
38+
39+
func testSimpleEventFromJSON() {
40+
let data = Self.eventBody.data(using: .utf8)!
41+
var event: CMQ.Topic.Event?
42+
XCTAssertNoThrow(event = try JSONDecoder().decode(CMQ.Topic.Event.self, from: data))
43+
44+
guard let record = event?.records.first else {
45+
XCTFail("Expected to have one record")
46+
return
47+
}
48+
49+
XCTAssertEqual(record.topicName, "testtopic")
50+
XCTAssertEqual(record.topicOwner, 12_014_223)
51+
XCTAssertEqual(record.subscriptionName, "xxxxxx")
52+
XCTAssertEqual(record.message.id, "123345346")
53+
XCTAssertEqual(record.message.body, "Hello from CMQ!")
54+
XCTAssertEqual(record.message.requestId, "123345346")
55+
XCTAssertEqual(record.message.tags, ["tag1", "tag2"])
56+
XCTAssertEqual(record.message.publishTime.description, "1970-01-01 00:00:00 +0000")
57+
}
58+
59+
func testEventDecodeAndEncode() {
60+
let data = Self.eventBody.data(using: .utf8)!
61+
let decoder = JSONDecoder()
62+
var event: CMQ.Topic.Event?
63+
XCTAssertNoThrow(event = try decoder.decode(CMQ.Topic.Event.self, from: data))
64+
65+
var newEvent: CMQ.Topic.Event?
66+
XCTAssertNoThrow(newEvent = try decoder.decode(CMQ.Topic.Event.self, from: try JSONEncoder().encode(event)))
67+
68+
XCTAssertEqual(event, newEvent)
69+
}
70+
}

0 commit comments

Comments
 (0)