Skip to content

Commit 5e94817

Browse files
committed
Updated with enum Detail
1 parent e601cac commit 5e94817

File tree

2 files changed

+112
-15
lines changed

2 files changed

+112
-15
lines changed

Sources/AWSLambdaEvents/Cloudwatch.swift

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,129 @@
1414

1515
import struct Foundation.Date
1616

17+
/// EventBridge has the same payloads/notification types as CloudWatch
18+
typealias EventBridge = Cloudwatch
19+
1720
public enum Cloudwatch {
1821
/// CloudWatch.Event is the outer structure of an event sent via CloudWatch Events.
1922
///
20-
/// **NOTE**: For examples of events that come via CloudWatch Events, see https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html
21-
public struct Event<Detail: Decodable>: Decodable {
23+
/// **NOTE**: For examples of events that come via CloudWatch Events, see
24+
/// https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html
25+
/// https://docs.aws.amazon.com/eventbridge/latest/userguide/event-types.html
26+
public struct Event: Decodable {
2227
public let id: String
2328
public let source: String
2429
public let accountId: String
25-
26-
@ISO8601Coding
27-
public var time: Date
30+
public let time: Date
2831
public let region: AWSRegion
2932
public let resources: [String]
3033

31-
public let detailType: String
3234
public let detail: Detail
3335

3436
enum CodingKeys: String, CodingKey {
3537
case id
36-
case detailType = "detail-type"
3738
case source
3839
case accountId = "account"
3940
case time
4041
case region
4142
case resources
4243
case detail
4344
}
45+
46+
public init(from decoder: Decoder) throws {
47+
let container = try decoder.container(keyedBy: CodingKeys.self)
48+
49+
self.id = try container.decode(String.self, forKey: .id)
50+
self.source = try container.decode(String.self, forKey: .source)
51+
self.accountId = try container.decode(String.self, forKey: .accountId)
52+
let time = try container.decode(ISO8601Coding.self, forKey: .time)
53+
self.time = time.wrappedValue
54+
self.region = try container.decode(AWSRegion.self, forKey: .region)
55+
self.resources = try container.decode([String].self, forKey: .resources)
56+
57+
self.detail = try Detail(from: decoder)
58+
}
59+
60+
61+
public enum Detail: Decodable {
62+
case scheduled
63+
case ec2InstanceStateChangeNotification(EC2.InstanceStateChangeNotification)
64+
case ec2SpotInstanceInterruptionWarning(EC2.SpotInstanceInterruptionNotice)
65+
case custom(label: String, detail: Decodable)
66+
67+
enum CodingKeys: String, CodingKey {
68+
case detailType = "detail-type"
69+
case detail
70+
}
71+
72+
// FIXME: make thread safe
73+
static var registry = [String: (Decoder) throws -> Decodable]()
74+
public static func register<T: Decodable>(label: String, type: T.Type) {
75+
registry[label] = type.init
76+
}
77+
78+
public init(from decoder: Decoder) throws {
79+
let container = try decoder.container(keyedBy: CodingKeys.self)
80+
let detailType = try container.decode(String.self, forKey: .detailType)
81+
switch detailType {
82+
case "Scheduled Event":
83+
self = .scheduled
84+
case "EC2 Instance State-change Notification":
85+
self = .ec2InstanceStateChangeNotification(
86+
try container.decode(EC2.InstanceStateChangeNotification.self, forKey: .detail))
87+
case "EC2 Spot Instance Interruption Warning":
88+
self = .ec2SpotInstanceInterruptionWarning(
89+
try container.decode(EC2.SpotInstanceInterruptionNotice.self, forKey: .detail))
90+
default:
91+
guard let factory = Detail.registry[detailType] else {
92+
throw UnknownPayload()
93+
}
94+
let detailsDecoder = try container.superDecoder(forKey: .detail)
95+
self = .custom(label: detailType, detail: try factory(detailsDecoder))
96+
}
97+
}
98+
}
4499
}
45100

46-
public struct ScheduledEvent: Codable {}
101+
public struct CodePipelineStateChange: Decodable {
102+
let foo: String
103+
}
104+
105+
public enum EC2 {
106+
public struct InstanceStateChangeNotification: Decodable {
107+
public enum State: String, Codable {
108+
case running
109+
case shuttingDown = "shutting-down"
110+
case stopped
111+
case stopping
112+
case terminated
113+
}
114+
115+
public let instanceId: String
116+
public let state: State
117+
118+
enum CodingKeys: String, CodingKey {
119+
case instanceId = "instance-id"
120+
case state
121+
}
122+
}
123+
124+
public struct SpotInstanceInterruptionNotice: Decodable {
125+
public enum Action: String, Codable {
126+
case hibernate
127+
case stop
128+
case terminate
129+
}
130+
131+
public let instanceId: String
132+
public let action: Action
133+
134+
enum CodingKeys: String, CodingKey {
135+
case instanceId = "instance-id"
136+
case action = "instance-action"
137+
}
138+
}
139+
}
140+
141+
struct UnknownPayload: Error {}
47142
}

Tests/AWSLambdaEventsTests/CloudwatchTests.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
@testable import AWSLambdaEvents
1616
import XCTest
1717

18-
class CloudwatchTests: XCTestCase {
18+
class CloudwatchTests: XCTestCase {
1919
static let scheduledEventPayload = """
2020
{
2121
"id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c",
@@ -33,20 +33,22 @@ class CloudwatchTests: XCTestCase {
3333

3434
func testScheduledEventFromJSON() {
3535
let data = CloudwatchTests.scheduledEventPayload.data(using: .utf8)!
36-
var maybeEvent: Cloudwatch.Event<Cloudwatch.ScheduledEvent>?
37-
XCTAssertNoThrow(maybeEvent = try JSONDecoder().decode(Cloudwatch.Event<Cloudwatch.ScheduledEvent>.self, from: data))
36+
var maybeEvent: Cloudwatch.Event?
37+
XCTAssertNoThrow(maybeEvent = try JSONDecoder().decode(Cloudwatch.Event.self, from: data))
3838

3939
guard let event = maybeEvent else {
40-
XCTFail("Expected to have an event")
41-
return
40+
XCTFail("Expected to have an event"); return
4241
}
4342

4443
XCTAssertEqual(event.id, "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c")
45-
XCTAssertEqual(event.detailType, "Scheduled Event")
4644
XCTAssertEqual(event.source, "aws.events")
4745
XCTAssertEqual(event.accountId, "123456789012")
4846
XCTAssertEqual(event.time, Date(timeIntervalSince1970: 0))
4947
XCTAssertEqual(event.region, .us_east_1)
5048
XCTAssertEqual(event.resources, ["arn:aws:events:us-east-1:123456789012:rule/ExampleRule"])
49+
50+
guard case Cloudwatch.Event.Detail.scheduled = event.detail else {
51+
XCTFail("Unexpected detail: \(event.detail)"); return
52+
}
5153
}
52-
}
54+
}

0 commit comments

Comments
 (0)