Skip to content

Commit fcc1a1d

Browse files
committed
Removed the Type Registry
1 parent fd09e25 commit fcc1a1d

File tree

2 files changed

+36
-68
lines changed

2 files changed

+36
-68
lines changed

Sources/AWSLambdaEvents/Cloudwatch.swift

Lines changed: 26 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,23 @@ import struct Foundation.Date
1717
/// EventBridge has the same payloads/notification types as CloudWatch
1818
typealias EventBridge = Cloudwatch
1919

20+
public protocol CloudwatchDetail: Decodable {
21+
static var name: String { get }
22+
}
23+
24+
public extension CloudwatchDetail {
25+
var detailType: String {
26+
Self.name
27+
}
28+
}
29+
2030
public enum Cloudwatch {
2131
/// CloudWatch.Event is the outer structure of an event sent via CloudWatch Events.
2232
///
2333
/// **NOTE**: For examples of events that come via CloudWatch Events, see
2434
/// https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html
2535
/// https://docs.aws.amazon.com/eventbridge/latest/userguide/event-types.html
26-
public struct Event<Detail: Decodable>: Decodable {
36+
public struct Event<Detail: CloudwatchDetail>: Decodable {
2737
public let id: String
2838
public let source: String
2939
public let accountId: String
@@ -39,6 +49,7 @@ public enum Cloudwatch {
3949
case time
4050
case region
4151
case resources
52+
case detailType = "detail-type"
4253
case detail
4354
}
4455

@@ -51,61 +62,28 @@ public enum Cloudwatch {
5162
self.time = (try container.decode(ISO8601Coding.self, forKey: .time)).wrappedValue
5263
self.region = try container.decode(AWSRegion.self, forKey: .region)
5364
self.resources = try container.decode([String].self, forKey: .resources)
54-
self.detail = (try DetailCoding(from: decoder)).guts
55-
}
5665

57-
private struct DetailCoding {
58-
public let guts: Detail
59-
60-
internal enum CodingKeys: String, CodingKey {
61-
case detailType = "detail-type"
62-
case detail
66+
let detailType = try container.decode(String.self, forKey: .detailType)
67+
guard detailType == Detail.name else {
68+
throw PayloadTypeMismatch(name: detailType, type: Detail.self)
6369
}
6470

65-
public init(from decoder: Decoder) throws {
66-
let container = try decoder.container(keyedBy: CodingKeys.self)
67-
let detailType = try container.decode(String.self, forKey: .detailType)
68-
let detailFactory: (Decoder) throws -> Decodable
69-
switch detailType {
70-
case ScheduledEvent.name:
71-
detailFactory = Empty.init
72-
case EC2.InstanceStateChangeNotificationEvent.name:
73-
detailFactory = EC2.InstanceStateChangeNotification.init
74-
case EC2.SpotInstanceInterruptionNoticeEvent.name:
75-
detailFactory = EC2.SpotInstanceInterruptionNotice.init
76-
default:
77-
guard let factory = Cloudwatch.detailPayloadRegistry[detailType] else {
78-
throw UnknownPayload(name: detailType)
79-
}
80-
detailFactory = factory
81-
}
82-
let detailsDecoder = try container.superDecoder(forKey: .detail)
83-
guard let detail = try detailFactory(detailsDecoder) as? Detail else {
84-
throw PayloadTypeMismatch(name: detailType, type: Detail.self)
85-
}
86-
self.guts = detail
87-
}
71+
self.detail = try container.decode(Detail.self, forKey: .detail)
8872
}
8973
}
9074

91-
// MARK: - Detail Payload Registry
92-
93-
// FIXME: make thread safe
94-
private static var detailPayloadRegistry = [String: (Decoder) throws -> Decodable]()
95-
96-
public static func registerDetailPayload<T: Decodable>(label: String, type: T.Type) {
97-
detailPayloadRegistry[label] = type.init
98-
}
99-
10075
// MARK: - Common Event Types
10176

102-
public typealias ScheduledEvent = Event<Empty>
103-
104-
public struct Empty: Decodable {}
77+
public typealias ScheduledEvent = Event<Scheduled>
78+
public struct Scheduled: CloudwatchDetail {
79+
public static let name = "Scheduled Event"
80+
}
10581

10682
public enum EC2 {
10783
public typealias InstanceStateChangeNotificationEvent = Event<InstanceStateChangeNotification>
108-
public struct InstanceStateChangeNotification: Decodable {
84+
public struct InstanceStateChangeNotification: CloudwatchDetail {
85+
public static let name = "EC2 Instance State-change Notification"
86+
10987
public enum State: String, Codable {
11088
case running
11189
case shuttingDown = "shutting-down"
@@ -124,7 +102,9 @@ public enum Cloudwatch {
124102
}
125103

126104
public typealias SpotInstanceInterruptionNoticeEvent = Event<SpotInstanceInterruptionNotice>
127-
public struct SpotInstanceInterruptionNotice: Decodable {
105+
public struct SpotInstanceInterruptionNotice: CloudwatchDetail {
106+
public static let name = "EC2 Spot Instance Interruption Warning"
107+
128108
public enum Action: String, Codable {
129109
case hibernate
130110
case stop
@@ -150,15 +130,3 @@ public enum Cloudwatch {
150130
let type: Any
151131
}
152132
}
153-
154-
extension Cloudwatch.ScheduledEvent {
155-
static var name: String { "Scheduled Event" }
156-
}
157-
158-
extension Cloudwatch.EC2.InstanceStateChangeNotificationEvent {
159-
static var name: String { "EC2 Instance State-change Notification" }
160-
}
161-
162-
extension Cloudwatch.EC2.SpotInstanceInterruptionNoticeEvent {
163-
static var name: String { "EC2 Spot Instance Interruption Warning" }
164-
}

Tests/AWSLambdaEventsTests/CloudwatchTests.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class CloudwatchTests: XCTestCase {
3434
}
3535

3636
func testScheduledEventFromJSON() {
37-
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.ScheduledEvent.name, details: "{}")
37+
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.Scheduled.name, details: "{}")
3838
let data = payload.data(using: .utf8)!
3939
var maybeEvent: Cloudwatch.ScheduledEvent?
4040
XCTAssertNoThrow(maybeEvent = try JSONDecoder().decode(Cloudwatch.ScheduledEvent.self, from: data))
@@ -52,7 +52,7 @@ class CloudwatchTests: XCTestCase {
5252
}
5353

5454
func testEC2InstanceStateChangeNotificationEventFromJSON() {
55-
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.EC2.InstanceStateChangeNotificationEvent.name,
55+
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.EC2.InstanceStateChangeNotification.name,
5656
details: "{ \"instance-id\": \"0\", \"state\": \"stopping\" }")
5757
let data = payload.data(using: .utf8)!
5858
var maybeEvent: Cloudwatch.EC2.InstanceStateChangeNotificationEvent?
@@ -73,7 +73,7 @@ class CloudwatchTests: XCTestCase {
7373
}
7474

7575
func testEC2SpotInstanceInterruptionNoticeEventFromJSON() {
76-
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.EC2.SpotInstanceInterruptionNoticeEvent.name,
76+
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.EC2.SpotInstanceInterruptionNotice.name,
7777
details: "{ \"instance-id\": \"0\", \"instance-action\": \"terminate\" }")
7878
let data = payload.data(using: .utf8)!
7979
var maybeEvent: Cloudwatch.EC2.SpotInstanceInterruptionNoticeEvent?
@@ -94,13 +94,13 @@ class CloudwatchTests: XCTestCase {
9494
}
9595

9696
func testCustomEventFromJSON() {
97-
struct Custom: Decodable {
97+
struct Custom: CloudwatchDetail {
98+
public static let name = "Custom"
99+
98100
let name: String
99101
}
100102

101-
Cloudwatch.registerDetailPayload(label: "Custom", type: Custom.self)
102-
103-
let payload = CloudwatchTests.eventPayload(type: "Custom", details: "{ \"name\": \"foo\" }")
103+
let payload = CloudwatchTests.eventPayload(type: Custom.name, details: "{ \"name\": \"foo\" }")
104104
let data = payload.data(using: .utf8)!
105105
var maybeEvent: Cloudwatch.Event<Custom>?
106106
XCTAssertNoThrow(maybeEvent = try JSONDecoder().decode(Cloudwatch.Event<Custom>.self, from: data))
@@ -122,16 +122,16 @@ class CloudwatchTests: XCTestCase {
122122
let payload = CloudwatchTests.eventPayload(type: UUID().uuidString, details: "{}")
123123
let data = payload.data(using: .utf8)!
124124
XCTAssertThrowsError(try JSONDecoder().decode(Cloudwatch.ScheduledEvent.self, from: data)) { error in
125-
XCTAssert(error is Cloudwatch.UnknownPayload, "expected UnknownPayload but recieved \(error)")
125+
XCTAssert(error is Cloudwatch.PayloadTypeMismatch, "expected PayloadTypeMismatch but received \(error)")
126126
}
127127
}
128128

129129
func testTypeMismatch() {
130-
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.EC2.InstanceStateChangeNotificationEvent.name,
130+
let payload = CloudwatchTests.eventPayload(type: Cloudwatch.EC2.InstanceStateChangeNotification.name,
131131
details: "{ \"instance-id\": \"0\", \"state\": \"stopping\" }")
132132
let data = payload.data(using: .utf8)!
133133
XCTAssertThrowsError(try JSONDecoder().decode(Cloudwatch.ScheduledEvent.self, from: data)) { error in
134-
XCTAssert(error is Cloudwatch.PayloadTypeMismatch, "expected PayloadTypeMismatch but recieved \(error)")
134+
XCTAssert(error is Cloudwatch.PayloadTypeMismatch, "expected PayloadTypeMismatch but received \(error)")
135135
}
136136
}
137137
}

0 commit comments

Comments
 (0)