Skip to content

Commit ec2fa3b

Browse files
committed
fix conflicts
2 parents 83d47b8 + 80326f4 commit ec2fa3b

File tree

10 files changed

+192
-122
lines changed

10 files changed

+192
-122
lines changed

OptimizelySDK/Customization/DefaultUserProfileService.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,21 @@ import Foundation
7474
open class DefaultUserProfileService: OPTUserProfileService {
7575
public typealias UserProfileData = [String: UPProfile]
7676

77-
var profiles: UserProfileData
77+
var profiles: UserProfileData?
7878
let lock = DispatchQueue(label: "com.optimizely.UserProfileService")
7979
let kStorageName = "user-profile-service"
8080

8181
public required init() {
82-
profiles = UserDefaults.standard.dictionary(forKey: kStorageName) as? UserProfileData ?? UserProfileData()
82+
lock.async {
83+
self.profiles = UserDefaults.standard.dictionary(forKey: self.kStorageName) as? UserProfileData ?? UserProfileData()
84+
85+
}
8386
}
8487

8588
open func lookup(userId: String) -> UPProfile? {
8689
var retVal: UPProfile?
8790
lock.sync {
88-
retVal = profiles[userId]
91+
retVal = profiles?[userId]
8992
}
9093
return retVal
9194
}
@@ -94,7 +97,7 @@ open class DefaultUserProfileService: OPTUserProfileService {
9497
guard let userId = userProfile[UserProfileKeys.kUserId] as? String else { return }
9598

9699
lock.async {
97-
self.profiles[userId] = userProfile
100+
self.profiles?[userId] = userProfile
98101
let defaults = UserDefaults.standard
99102
defaults.set(self.profiles, forKey: self.kStorageName)
100103
defaults.synchronize()

OptimizelySDK/Data Model/ProjectConfig.swift

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,46 @@ import Foundation
1919
class ProjectConfig {
2020

2121
var project: Project!
22+
2223
lazy var logger = HandlerRegistryService.shared.injectLogger()
2324

2425
// local runtime forcedVariations [UserId: [ExperimentId: VariationId]]
2526
// NOTE: experiment.forcedVariations use [ExperimentKey: VariationKey] instead of ids
2627

2728
var whitelistUsers = [String: [String: String]]()
2829

30+
lazy var experimentKeyMap:[String:Experiment] = {
31+
var map = [String:Experiment]()
32+
allExperiments.forEach({map[$0.key] = $0})
33+
return map
34+
}()
35+
36+
lazy var experimentFeatureMap:[String:[String]] = {
37+
var experimentFeatureMap = [String:[String]]()
38+
project.featureFlags.forEach({ (ff) in
39+
ff.experimentIds.forEach({
40+
if var arr = experimentFeatureMap[$0] {
41+
arr.append(ff.id)
42+
experimentFeatureMap[$0] = arr
43+
}
44+
else {
45+
experimentFeatureMap[$0] = [ff.id]
46+
}
47+
})
48+
})
49+
return experimentFeatureMap
50+
}()
51+
52+
lazy var eventKeyMap:[String:Event] = {
53+
var eventKeyMap = [String:Event]()
54+
project.events.forEach({eventKeyMap[$0.key] = $0 })
55+
return eventKeyMap
56+
}()
57+
58+
lazy var allExperiments:[Experiment] = {
59+
return project.experiments + project.groups.map({$0.experiments}).flatMap({$0})
60+
}()
61+
2962
init(datafile: Data) throws {
3063
do {
3164
self.project = try JSONDecoder().decode(Project.self, from: datafile)
@@ -35,6 +68,7 @@ class ProjectConfig {
3568
if !isValidVersion(version: self.project.version) {
3669
throw OptimizelyError.dataFileVersionInvalid(self.project.version)
3770
}
71+
3872
}
3973

4074
convenience init(datafile: String) throws {
@@ -87,6 +121,7 @@ extension ProjectConfig {
87121
// old versions (< 4) of datafiles not supported
88122
return ["4"].contains(version)
89123
}
124+
90125
}
91126

92127
// MARK: - Project Access
@@ -97,7 +132,7 @@ extension ProjectConfig {
97132
* Get an Experiment object for a key.
98133
*/
99134
func getExperiment(key: String) -> Experiment? {
100-
return allExperiments.filter { $0.key == key }.first
135+
return experimentKeyMap[key]
101136
}
102137

103138
/**
@@ -139,7 +174,7 @@ extension ProjectConfig {
139174
* Gets an event for a corresponding event key
140175
*/
141176
func getEvent(key: String) -> Event? {
142-
return project.events.filter{ $0.key == key }.first
177+
return eventKeyMap[key]
143178
}
144179

145180
/**
@@ -175,12 +210,7 @@ extension ProjectConfig {
175210
* Returns true if experiment belongs to any feature, false otherwise.
176211
*/
177212
func isFeatureExperiment(id: String) -> Bool {
178-
if let _ = project.featureFlags.map({ $0.experimentIds.contains(id)}).first {
179-
return true
180-
}
181-
else {
182-
return false
183-
}
213+
return !(experimentFeatureMap[id]?.isEmpty ?? true)
184214
}
185215

186216
/**
@@ -236,8 +266,4 @@ extension ProjectConfig {
236266
return true
237267
}
238268

239-
var allExperiments:[Experiment] {
240-
return project.experiments + project.groups.map({$0.experiments}).flatMap({$0})
241-
}
242-
243269
}

OptimizelySDK/Implementation/DefaultDatafileHandler.swift

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class DefaultDatafileHandler : OPTDatafileHandler {
2222
var timers:AtomicProperty<[String:(timer:Timer, interval:Int)]> = AtomicProperty(property: [String:(Timer,Int)]())
2323
let dataStore = DataStoreUserDefaults()
2424

25+
let downloadQueue = DispatchQueue(label: "DefaultDatafileHandlerQueue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
26+
2527
required init() {
2628

2729
}
@@ -48,23 +50,54 @@ class DefaultDatafileHandler : OPTDatafileHandler {
4850
return datafile
4951
}
5052

51-
open func downloadDatafile(sdkKey: String,
52-
resourceTimeoutInterval:Double? = nil,
53-
completionHandler: @escaping DatafileDownloadCompletionHandler) {
53+
open func getSession(resourceTimeoutInterval:Double?) -> URLSession {
5454
let config = URLSessionConfiguration.ephemeral
5555
if let resourceTimeoutInterval = resourceTimeoutInterval,
5656
resourceTimeoutInterval > 0 {
5757
config.timeoutIntervalForResource = TimeInterval(resourceTimeoutInterval)
5858
}
59-
let session = URLSession(configuration: config)
59+
return URLSession(configuration: config)
60+
}
61+
62+
open func getRequest(sdkKey:String) -> URLRequest? {
6063
let str = String(format: DefaultDatafileHandler.endPointStringFormat, sdkKey)
61-
if let url = URL(string: str) {
62-
var request = URLRequest(url: url)
63-
64-
if let lastModified = dataStore.getItem(forKey: "OPTLastModified-" + sdkKey) {
65-
request.addValue(lastModified as! String, forHTTPHeaderField: "If-Modified-Since")
64+
guard let url = URL(string: str) else { return nil }
65+
66+
var request = URLRequest(url: url)
67+
68+
if let lastModified = dataStore.getItem(forKey: "OPTLastModified-" + sdkKey) {
69+
request.addValue(lastModified as! String, forHTTPHeaderField: "If-Modified-Since")
70+
}
71+
72+
return request
73+
74+
}
75+
76+
open func getResponseData(sdkKey:String, response:HTTPURLResponse, url:URL?) -> Data? {
77+
if let url = url, let data = try? Data(contentsOf: url) {
78+
if let str = String(data: data, encoding: .utf8) {
79+
self.logger?.log(level: .debug, message: str)
80+
}
81+
self.saveDatafile(sdkKey: sdkKey, dataFile: data)
82+
if let lastModified = response.allHeaderFields["Last-Modified"] {
83+
self.dataStore.saveItem(forKey: "OPTLastModified-" + sdkKey, value: lastModified)
6684
}
6785

86+
return data
87+
}
88+
89+
return nil
90+
}
91+
92+
open func downloadDatafile(sdkKey: String,
93+
resourceTimeoutInterval:Double? = nil,
94+
completionHandler: @escaping DatafileDownloadCompletionHandler) {
95+
96+
downloadQueue.async {
97+
let session = self.getSession(resourceTimeoutInterval: resourceTimeoutInterval)
98+
99+
guard let request = self.getRequest(sdkKey: sdkKey) else { return }
100+
68101
let task = session.downloadTask(with: request) { (url, response, error) in
69102
var result = OptimizelyResult<Data?>.failure(.datafileDownloadFailed("Failed to parse"))
70103

@@ -73,31 +106,22 @@ class DefaultDatafileHandler : OPTDatafileHandler {
73106
result = .failure(.datafileDownloadFailed(error.debugDescription))
74107
} else if let response = response as? HTTPURLResponse {
75108
if response.statusCode == 200 {
76-
if let url = url, let data = try? Data(contentsOf: url) {
77-
if let str = String(data: data, encoding: .utf8) {
78-
self.logger?.d(str)
79-
}
80-
self.saveDatafile(sdkKey: sdkKey, dataFile: data)
81-
if let lastModified = response.allHeaderFields["Last-Modified"] {
82-
self.dataStore.saveItem(forKey: "OPTLastModified-" + sdkKey, value: lastModified)
83-
}
84-
85-
result = .success(data)
86-
}
87-
} else if response.statusCode == 304 {
88-
self.logger?.d("The datafile was not modified and won't be downloaded again")
109+
let data = self.getResponseData(sdkKey: sdkKey, response: response, url: url)
110+
result = Result.success(data)
111+
}
112+
else if response.statusCode == 304 {
113+
self.logger?.log(level: .debug, message: "The datafile was not modified and won't be downloaded again")
89114
result = .success(nil)
90115
}
91116
}
92-
117+
93118
completionHandler(result)
94119

95120
//self.logger?.d(response.debugDescription)
96121
}
97122

98123
task.resume()
99124
}
100-
101125
}
102126

103127
func startPeriodicUpdates(sdkKey: String, updateInterval: Int, datafileChangeNotification:((Data)->Void)?) {

OptimizelySDK/Implementation/Events/BatchEventBuilder.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class BatchEventBuilder {
9191

9292
let batchEvent = BatchEvent(revision: config.project.revision,
9393
accountID: config.project.accountId,
94-
clientVersion: Utils.getSDKVersion(),
94+
clientVersion: Utils.sdkVersion,
9595
visitors: [visitor],
9696
projectID: config.project.projectId,
9797
clientName: swiftSdkClientName,

0 commit comments

Comments
 (0)