Skip to content

Commit

Permalink
fix: WIP update types
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathannorris committed Aug 17, 2023
1 parent 63a63b8 commit 3c71668
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 77 deletions.
11 changes: 7 additions & 4 deletions DevCycle/DVCVariable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,8 @@ public class DVCVariable<T> {
let oldValue = self.value
self.value = value
self.isDefaulted = false
if let handler = self.handler,
!isEqual(oldValue, variable.value)
{

if let handler = self.handler, !isEqual(oldValue, variable.value) {
handler(value)
}
} else {
Expand Down Expand Up @@ -85,7 +84,11 @@ public class DVCVariable<T> {
}

private func addNotificationObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(propertyChange(notification:)), name: Notification.Name(NotificationNames.NewUserConfig), object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(propertyChange(notification:)),
name: Notification.Name(NotificationNames.NewUserConfig),
object: nil)
}

public func onUpdate(handler: @escaping VariableValueHandler<T>) -> DVCVariable {
Expand Down
91 changes: 59 additions & 32 deletions DevCycle/DevCycleClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public typealias IdentifyCompletedHandler = (Error?, [String: Variable]?) -> Voi
public typealias FlushCompletedHandler = (Error?) -> Void
public typealias CloseCompletedHandler = () -> Void

internal typealias VariableInstanceDic = [String: NSMapTable<AnyObject, AnyObject>]


public class DevCycleClient {
var sdkKey: String?
Expand All @@ -51,7 +53,7 @@ public class DevCycleClient {
private var flushTimer: Timer?
private var closed: Bool = false
private var inactivityWorkItem: DispatchWorkItem?
private var variableInstanceDictonary = [String: NSMapTable<AnyObject, AnyObject>]()
private var variableInstanceDictonary = VariableInstanceDic()
private var isConfigCached: Bool = false
private var disableAutomaticEventLogging: Bool = false
private var disableCustomEventLogging: Bool = false
Expand Down Expand Up @@ -154,21 +156,17 @@ public class DevCycleClient {
if let config = config {
Log.debug("Config: \(config)", tags: ["setup"])
}
self.config?.userConfig = config
self.isConfigCached = false

self.cacheUser(user: user)
self.setUserConfig(config)
self.cacheUser(user)

if (self.checkIfEdgeDBEnabled(config: config!, enableEdgeDB: self.enableEdgeDB)) {
if (!(user.isAnonymous ?? false)) {
self.service?.saveEntity(user: user, completion: { data, response, error in
if error != nil {
Log.error("Error saving user entity for \(user). Error: \(String(describing: error))")
} else {
Log.info("Saved user entity")
}
})
}
if (self.checkIfEdgeDBEnabled(config: config!, enableEdgeDB: self.enableEdgeDB) && !(user.isAnonymous ?? false)) {
self.service?.saveEntity(user: user, completion: { data, response, error in
if error != nil {
Log.error("Error saving user entity for \(user). Error: \(String(describing: error))")
} else {
Log.info("Saved user entity")
}
})
}
}

Expand Down Expand Up @@ -216,17 +214,40 @@ public class DevCycleClient {
let extraParams = RequestParams(sse: sse, lastModified: lastModified, etag: etag)
self.service?.getConfig(user: lastIdentifiedUser, enableEdgeDB: self.enableEdgeDB, extraParams: extraParams, completion: { [weak self] config, error in
guard let self = self else { return }

if let error = error {
Log.error("Error getting config: \(error)", tags: ["refetchConfig"])
self.eventEmitter.emit(EventEmitValues.error(error))
} else {
self.config?.userConfig = config
self.isConfigCached = false
self.setUserConfig(config)
}
})
}
}

private func setUserConfig(_ config: UserConfig?) {
let oldConfig = self.config
self.config?.userConfig = config
self.isConfigCached = false

if let config = config {
self.eventEmitter.emitFeatureUpdates(
oldFeatures: oldConfig?.userConfig?.features,
newFeatures: config.features
)
self.eventEmitter.emitVariableUpdates(
oldVariables: oldConfig?.userConfig?.variables,
newVariables: config.variables,
variableInstanceDic: self.variableInstanceDictonary
)

if oldConfig == nil || config.etag != oldConfig?.userConfig?.etag {
self.eventEmitter.emit(EventEmitValues.configUpdated(config.variables))
}
}
}

private func cacheUser(user: DevCycleUser) {
private func cacheUser(_ user: DevCycleUser) {
self.cacheService.save(user: user)
if user.isAnonymous == true, let userId = user.userId {
self.cacheService.setAnonUserId(anonUserId: userId)
Expand Down Expand Up @@ -274,9 +295,10 @@ public class DevCycleClient {
return variable(key: key, defaultValue: defaultValue).value
}

private let regex = try? NSRegularExpression(pattern: ".*[^a-z0-9(\\-)(_)].*")

public func variable<T>(key: String, defaultValue: T) -> DVCVariable<T> {
let regex = try? NSRegularExpression(pattern: ".*[^a-z0-9(\\-)(_)].*")
if (regex?.firstMatch(in: key, range: NSMakeRange(0, key.count)) != nil) {
if (self.regex?.firstMatch(in: key, range: NSMakeRange(0, key.count)) != nil) {
Log.error("The variable key \(key) is invalid. It must contain only lowercase letters, numbers, hyphens and underscores. The default value will always be returned for this call.")
return DVCVariable(
key: key,
Expand All @@ -292,6 +314,7 @@ public class DevCycleClient {
if (self.variableInstanceDictonary[key] == nil) {
self.variableInstanceDictonary[key] = NSMapTable<AnyObject, AnyObject>(valueOptions: .weakMemory)
}

if let variableFromDictionary = self.variableInstanceDictonary[key]?.object(forKey: defaultValue as AnyObject) as? DVCVariable<T> {
variable = variableFromDictionary
} else {
Expand All @@ -307,15 +330,16 @@ public class DevCycleClient {
evalReason: nil
)
}
self.variableInstanceDictonary[key]?.setObject(variable, forKey: defaultValue as AnyObject)

self.variableInstanceDictonary[key]?.setObject(variable, forKey: defaultValue as AnyObject)
}

if (!self.closed) {
if(!self.disableAutomaticEventLogging){
self.eventQueue.updateAggregateEvents(variableKey: variable.key, variableIsDefaulted: variable.isDefaulted)
}
if (!self.closed && !self.disableAutomaticEventLogging) {
self.eventQueue.updateAggregateEvents(variableKey: variable.key, variableIsDefaulted: variable.isDefaulted)
}


self.eventEmitter.emit(EventEmitValues.variableEvaluated(variable.key, variable))
return variable
}
}
Expand All @@ -336,18 +360,19 @@ public class DevCycleClient {

self.service?.getConfig(user: updateUser, enableEdgeDB: self.enableEdgeDB, extraParams: nil, completion: { [weak self] config, error in
guard let self = self else { return }

if let error = error {
Log.error("Error getting config: \(error)", tags: ["identify"])
self.cache = self.cacheService.load()
self.eventEmitter.emit(EventEmitValues.error(error))
} else {
if let config = config {
Log.debug("Config: \(config)", tags: ["identify"])
}
self.config?.userConfig = config
self.isConfigCached = false
self.setUserConfig(config)
}
self.user = user
self.cacheUser(user: user)
self.cacheUser(user)
callback?(error, config?.variables)
})
}
Expand All @@ -364,21 +389,23 @@ public class DevCycleClient {

self.service?.getConfig(user: anonUser, enableEdgeDB: self.enableEdgeDB, extraParams: nil, completion: { [weak self] config, error in
guard let self = self else { return }
guard error == nil else {

if let error = error {
if let previousAnonUserId = cachedAnonUserId {
self.cacheService.setAnonUserId(anonUserId: previousAnonUserId)
}
self.eventEmitter.emit(EventEmitValues.error(error))
callback?(error, nil)
return
}

if let config = config {
Log.debug("Config: \(config)", tags: ["reset"])
self.eventEmitter.emit(EventEmitValues.configUpdated(config.variables))
}
self.config?.userConfig = config
self.isConfigCached = false
self.setUserConfig(config)
self.user = anonUser
self.cacheUser(user: anonUser)
self.cacheUser(anonUser)
callback?(error, config?.variables)
})
}
Expand Down
Loading

0 comments on commit 3c71668

Please sign in to comment.