Skip to content

Commit d437b62

Browse files
committed
Updated with enum Detail
1 parent c8d2ebd commit d437b62

File tree

2 files changed

+109
-13
lines changed

2 files changed

+109
-13
lines changed

Sources/AWSLambdaEvents/Cloudwatch.swift

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,128 @@
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+
public enum Detail: Decodable {
61+
case scheduled
62+
case ec2InstanceStateChangeNotification(EC2.InstanceStateChangeNotification)
63+
case ec2SpotInstanceInterruptionWarning(EC2.SpotInstanceInterruptionNotice)
64+
case custom(label: String, detail: Decodable)
65+
66+
enum CodingKeys: String, CodingKey {
67+
case detailType = "detail-type"
68+
case detail
69+
}
70+
71+
// FIXME: make thread safe
72+
static var registry = [String: (Decoder) throws -> Decodable]()
73+
public static func register<T: Decodable>(label: String, type: T.Type) {
74+
registry[label] = type.init
75+
}
76+
77+
public init(from decoder: Decoder) throws {
78+
let container = try decoder.container(keyedBy: CodingKeys.self)
79+
let detailType = try container.decode(String.self, forKey: .detailType)
80+
switch detailType {
81+
case "Scheduled Event":
82+
self = .scheduled
83+
case "EC2 Instance State-change Notification":
84+
self = .ec2InstanceStateChangeNotification(
85+
try container.decode(EC2.InstanceStateChangeNotification.self, forKey: .detail))
86+
case "EC2 Spot Instance Interruption Warning":
87+
self = .ec2SpotInstanceInterruptionWarning(
88+
try container.decode(EC2.SpotInstanceInterruptionNotice.self, forKey: .detail))
89+
default:
90+
guard let factory = Detail.registry[detailType] else {
91+
throw UnknownPayload()
92+
}
93+
let detailsDecoder = try container.superDecoder(forKey: .detail)
94+
self = .custom(label: detailType, detail: try factory(detailsDecoder))
95+
}
96+
}
97+
}
98+
}
99+
100+
public struct CodePipelineStateChange: Decodable {
101+
let foo: String
102+
}
103+
104+
public enum EC2 {
105+
public struct InstanceStateChangeNotification: Decodable {
106+
public enum State: String, Codable {
107+
case running
108+
case shuttingDown = "shutting-down"
109+
case stopped
110+
case stopping
111+
case terminated
112+
}
113+
114+
public let instanceId: String
115+
public let state: State
116+
117+
enum CodingKeys: String, CodingKey {
118+
case instanceId = "instance-id"
119+
case state
120+
}
121+
}
122+
123+
public struct SpotInstanceInterruptionNotice: Decodable {
124+
public enum Action: String, Codable {
125+
case hibernate
126+
case stop
127+
case terminate
128+
}
129+
130+
public let instanceId: String
131+
public let action: Action
132+
133+
enum CodingKeys: String, CodingKey {
134+
case instanceId = "instance-id"
135+
case action = "instance-action"
136+
}
137+
}
44138
}
45139

46-
public struct ScheduledEvent: Codable {}
140+
struct UnknownPayload: Error {}
47141
}

Tests/AWSLambdaEventsTests/CloudwatchTests.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}
5254
}

0 commit comments

Comments
 (0)