Skip to content

Commit b70a7b9

Browse files
committed
[FSSDK-11454] Swift - Add SDK Multi-Region Support for Data Hosting
1 parent 6fd56c3 commit b70a7b9

File tree

7 files changed

+412
-13
lines changed

7 files changed

+412
-13
lines changed

Sources/Data Model/DispatchEvents/BatchEvent.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct BatchEvent: Codable, Equatable {
2525
let clientName: String
2626
let anonymizeIP: Bool
2727
let enrichDecisions: Bool
28+
let region: String
2829

2930
enum CodingKeys: String, CodingKey {
3031
case revision
@@ -35,6 +36,7 @@ struct BatchEvent: Codable, Equatable {
3536
case clientName = "client_name"
3637
case anonymizeIP = "anonymize_ip"
3738
case enrichDecisions = "enrich_decisions"
39+
case region
3840
}
3941

4042
func getEventAttribute(key: String) -> EventAttribute? {

Sources/Data Model/DispatchEvents/EventForDispatch.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,23 @@ import Foundation
1818

1919
@objcMembers public class EventForDispatch: NSObject, Codable {
2020
public static var eventEndpoint = "https://logx.optimizely.com/v1/events"
21+
public static var euEventEndpoint = "https://eu.logx.optimizely.com/v1/events"
22+
23+
public static func getEndpoint(for region: Region) -> String {
24+
switch region {
25+
case .EU:
26+
return euEventEndpoint
27+
case .US:
28+
return eventEndpoint
29+
}
30+
}
2131

2232
public let url: URL
2333
public let body: Data
2434

25-
public init(url: URL? = nil, body: Data) {
26-
self.url = url ?? URL(string: EventForDispatch.eventEndpoint)!
35+
public init(url: URL? = nil, body: Data, region: Region = .US) {
36+
let endpoint = url?.absoluteString ?? EventForDispatch.getEndpoint(for: region)
37+
self.url = URL(string: endpoint)!
2738
self.body = body
2839
}
2940

Sources/Data Model/Project.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616

1717
import Foundation
1818

19+
/// Optimizely region identifiers
20+
public enum Region: String, Codable, Equatable {
21+
case US
22+
case EU
23+
}
24+
1925
protocol ProjectProtocol {
2026
func evaluateAudience(audienceId: String, user: OptimizelyUserContext) throws -> Bool
2127
}
@@ -48,6 +54,8 @@ struct Project: Codable, Equatable {
4854
var environmentKey: String?
4955
// Holdouts
5056
var holdouts: [Holdout]
57+
// Region
58+
var region: Region?
5159
let logger = OPTLoggerFactory.getLogger()
5260

5361
// Required since logger is not decodable
@@ -57,7 +65,7 @@ struct Project: Codable, Equatable {
5765
// V3
5866
case anonymizeIP
5967
// V4
60-
case rollouts, integrations, typedAudiences, featureFlags, botFiltering, sendFlagDecisions, sdkKey, environmentKey, holdouts
68+
case rollouts, integrations, typedAudiences, featureFlags, botFiltering, sendFlagDecisions, sdkKey, environmentKey, holdouts, region
6169
}
6270

6371
init(from decoder: Decoder) throws {
@@ -88,6 +96,8 @@ struct Project: Codable, Equatable {
8896
environmentKey = try container.decodeIfPresent(String.self, forKey: .environmentKey)
8997
// Holdouts - defaults to empty array if key is not present
9098
holdouts = try container.decodeIfPresent([Holdout].self, forKey: .holdouts) ?? []
99+
// Region - defaults to US if not present
100+
region = try container.decodeIfPresent(Region.self, forKey: .region)
91101
}
92102

93103
// Required since logger is not equatable
@@ -97,7 +107,9 @@ struct Project: Codable, Equatable {
97107
lhs.accountId == rhs.accountId && lhs.events == rhs.events && lhs.revision == rhs.revision &&
98108
lhs.anonymizeIP == rhs.anonymizeIP && lhs.rollouts == rhs.rollouts &&
99109
lhs.integrations == rhs.integrations && lhs.typedAudiences == rhs.typedAudiences &&
100-
lhs.featureFlags == rhs.featureFlags && lhs.botFiltering == rhs.botFiltering && lhs.sendFlagDecisions == rhs.sendFlagDecisions && lhs.sdkKey == rhs.sdkKey && lhs.environmentKey == rhs.environmentKey
110+
lhs.featureFlags == rhs.featureFlags && lhs.botFiltering == rhs.botFiltering &&
111+
lhs.sendFlagDecisions == rhs.sendFlagDecisions && lhs.sdkKey == rhs.sdkKey &&
112+
lhs.environmentKey == rhs.environmentKey && lhs.region == rhs.region
101113
}
102114
}
103115

Sources/Data Model/ProjectConfig.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ extension ProjectConfig {
215215

216216
extension ProjectConfig {
217217

218+
/**
219+
* Get the region value. Defaults to US if not specified in the project.
220+
*/
221+
public var region: Region {
222+
return project.region ?? .US
223+
}
224+
218225
/**
219226
* Get sendFlagDecisions value.
220227
*/

Sources/Extensions/ArrayEventForDispatch+Extension.swift

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ extension Array where Element == EventForDispatch {
4545
var url: URL?
4646
var projectId: String?
4747
var revision: String?
48+
var region: String?
4849

4950
let checkUrl = { (event: EventForDispatch) -> Bool in
5051
if url == nil {
@@ -69,10 +70,18 @@ extension Array where Element == EventForDispatch {
6970
}
7071
return revision == batchEvent.revision
7172
}
73+
74+
let checkRegion = { (batchEvent: BatchEvent) -> Bool in
75+
if region == nil {
76+
region = batchEvent.region
77+
return region != nil
78+
}
79+
return region == batchEvent.region
80+
}
7281

7382
for event in self {
7483
if let batchEvent = try? JSONDecoder().decode(BatchEvent.self, from: event.body) {
75-
if !checkUrl(event) || !checkProjectId(batchEvent) || !checkRevision(batchEvent) {
84+
if !checkUrl(event) || !checkProjectId(batchEvent) || !checkRevision(batchEvent) || !checkRegion(batchEvent) {
7685
break
7786
}
7887

@@ -101,12 +110,14 @@ extension Array where Element == EventForDispatch {
101110
projectID: base.projectID,
102111
clientName: base.clientName,
103112
anonymizeIP: base.anonymizeIP,
104-
enrichDecisions: true)
113+
enrichDecisions: true,
114+
region: base.region)
105115

106116
guard let data = try? JSONEncoder().encode(batchEvent) else {
107117
return nil
108118
}
109-
110-
return EventForDispatch(url: url, body: data)
119+
120+
let regionValue = base.region == Region.EU.rawValue ? Region.EU : Region.US
121+
return EventForDispatch(url: url, body: data, region: regionValue)
111122
}
112123
}

Sources/Implementation/Events/BatchEventBuilder.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ class BatchEventBuilder {
4747
userId: userId,
4848
attributes: attributes,
4949
decisions: [decision],
50-
dispatchEvents: [dispatchEvent])
50+
dispatchEvents: [dispatchEvent],
51+
region: config.region)
5152
}
5253

5354
// MARK: - Converison Event
@@ -77,7 +78,8 @@ class BatchEventBuilder {
7778
userId: userId,
7879
attributes: attributes,
7980
decisions: nil,
80-
dispatchEvents: [dispatchEvent])
81+
dispatchEvents: [dispatchEvent],
82+
region: config.region)
8183
}
8284

8385
// MARK: - Create Event
@@ -86,7 +88,9 @@ class BatchEventBuilder {
8688
userId: String,
8789
attributes: OptimizelyAttributes?,
8890
decisions: [Decision]?,
89-
dispatchEvents: [DispatchEvent]) -> Data? {
91+
dispatchEvents: [DispatchEvent],
92+
region: Region? = nil) -> Data? {
93+
let eventRegion = region ?? config.region
9094
let snapShot = Snapshot(decisions: decisions, events: dispatchEvents)
9195

9296
let eventAttributes = getEventAttributes(config: config, attributes: attributes)
@@ -100,9 +104,13 @@ class BatchEventBuilder {
100104
projectID: config.project.projectId,
101105
clientName: Utils.swiftSdkClientName,
102106
anonymizeIP: config.project.anonymizeIP,
103-
enrichDecisions: true)
107+
enrichDecisions: true,
108+
region: eventRegion.rawValue)
109+
110+
let data = try? JSONEncoder().encode(batchEvent)
111+
let eventForDispatch = EventForDispatch(url: nil, body: data ?? Data(), region: eventRegion)
104112

105-
return try? JSONEncoder().encode(batchEvent)
113+
return eventForDispatch.body
106114
}
107115

108116
// MARK: - Event Tags

0 commit comments

Comments
 (0)