From a307b064b05002452997e2f81b12b79abe4fdf15 Mon Sep 17 00:00:00 2001 From: Adel Date: Mon, 13 Oct 2025 14:29:14 +0200 Subject: [PATCH 1/5] clean fucntion --- FlagShip/Source/Cache/FSCacheDelegate.swift | 1 + FlagShip/Source/Cache/FSCacheManager.swift | 6 +- .../Core/FSVisitor+Reconcilliation.swift | 18 +-- FlagShip/Source/Core/FSVisitor.swift | 5 + FlagShip/Source/Core/Flagship.swift | 2 +- FlagShip/Source/Logger/FSError.swift | 2 +- .../Source/Strategy/FSDefaultStrategy.swift | 120 +++++++++++++----- iOS Example/QApp/Base.lproj/Main.storyboard | 76 +++++------ iOS Example/QApp/FSConfigViewController.swift | 10 +- 9 files changed, 151 insertions(+), 89 deletions(-) diff --git a/FlagShip/Source/Cache/FSCacheDelegate.swift b/FlagShip/Source/Cache/FSCacheDelegate.swift index cf46ca47..08ca8e3c 100644 --- a/FlagShip/Source/Cache/FSCacheDelegate.swift +++ b/FlagShip/Source/Cache/FSCacheDelegate.swift @@ -17,6 +17,7 @@ import Foundation /// Called when a visitor set consent to false. Must erase visitor data related to the given visitor /// Id from the database. func flushVisitor(visitorId: String) + } @objc public protocol FSHitCacheDelegate { diff --git a/FlagShip/Source/Cache/FSCacheManager.swift b/FlagShip/Source/Cache/FSCacheManager.swift index 36561d2f..27a10a87 100644 --- a/FlagShip/Source/Cache/FSCacheManager.swift +++ b/FlagShip/Source/Cache/FSCacheManager.swift @@ -58,7 +58,7 @@ import Foundation /// - Parameters: /// - visitoId: id of the visitor /// - onCompletion: callback ob finishing the job - public func lookupVisitorCache(visitoId: String, onCompletion: @escaping (Error?, FSCacheVisitor?)->Void) { + public func lookupVisitorCache(visitoId: String, onCompletion: @escaping (FlagshipError?, FSCacheVisitor?)->Void) { /// Create a thread let fsCacheQueue = DispatchQueue(label: "com.flagshipCache.queue", attributes: .concurrent) /// Init the semaphore @@ -72,10 +72,10 @@ import Foundation let result = try JSONDecoder().decode(FSCacheVisitor.self, from: dataJson) onCompletion(nil, result) } catch { - onCompletion(error, nil) + onCompletion(FlagshipError(message: "Error on decode visitor data from cache", type: .internalError, code: 404), nil) } } else { - onCompletion(FlagshipError(type: .internalError, code: 400), nil) + onCompletion(FlagshipError(message: "The visitorId \(visitoId) not found in cache", type: .internalError, code: 400), nil) } semaphore.signal() } diff --git a/FlagShip/Source/Core/FSVisitor+Reconcilliation.swift b/FlagShip/Source/Core/FSVisitor+Reconcilliation.swift index ac2fef03..9ad5ea9d 100644 --- a/FlagShip/Source/Core/FSVisitor+Reconcilliation.swift +++ b/FlagShip/Source/Core/FSVisitor+Reconcilliation.swift @@ -15,10 +15,12 @@ public extension FSVisitor { /// - Important: After using this method, you should use Flagship.fetchFlags method to update the visitor informations /// - Requires: Make sure that the experience continuity option is enabled on the flagship platform before using this method @objc func authenticate(visitorId: String) { - if configManager.flagshipConfig.mode != .DECISION_API { - FlagshipLogManager.Log(level: .ALL, tag: .AUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_AUTHENTICATE) - return - } + + +// if configManager.flagshipConfig.mode != .DECISION_API { +// FlagshipLogManager.Log(level: .ALL, tag: .AUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_AUTHENTICATE) +// return +// } self.strategy?.getStrategy().authenticateVisitor(visitorId: visitorId) self.updateStateAndTriggerCallback(true) // Troubleshooting xpc @@ -27,10 +29,10 @@ public extension FSVisitor { /// Use authenticate methode to go from Logged in session to logged out session @objc func unauthenticate() { - if configManager.flagshipConfig.mode != .DECISION_API { - FlagshipLogManager.Log(level: .ALL, tag: .UNAUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_AUTHENTICATE) - return - } +// if configManager.flagshipConfig.mode != .DECISION_API { +// FlagshipLogManager.Log(level: .ALL, tag: .UNAUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_AUTHENTICATE) +// return +// } self.strategy?.getStrategy().unAuthenticateVisitor() self.updateStateAndTriggerCallback(false) // Troubleshooting xpc diff --git a/FlagShip/Source/Core/FSVisitor.swift b/FlagShip/Source/Core/FSVisitor.swift index 05fe1adf..5c45a8ba 100644 --- a/FlagShip/Source/Core/FSVisitor.swift +++ b/FlagShip/Source/Core/FSVisitor.swift @@ -143,6 +143,11 @@ import Foundation // Go to ING state while the fetch is ongoing self.fetchStatus = .FETCHING + + /// Look for the visitor in local storage + self.strategy?.getStrategy().lookupVisitor() + + // Synchronize the visitor self.strategy?.getStrategy().synchronize(onSyncCompleted: { state, reason in // After the synchronize completion we cache the visitor diff --git a/FlagShip/Source/Core/Flagship.swift b/FlagShip/Source/Core/Flagship.swift index 82156e6f..c464526d 100644 --- a/FlagShip/Source/Core/Flagship.swift +++ b/FlagShip/Source/Core/Flagship.swift @@ -99,7 +99,7 @@ public class Flagship: NSObject { if hasConsented { // Read the cached visitor - newVisitor.strategy?.getStrategy().lookupVisitor() + // newVisitor.strategy?.getStrategy().lookupVisitor() // Déplace la fonction dans le fetch flags // Read the cacheed hits from data base newVisitor.strategy?.getStrategy().lookupHits() diff --git a/FlagShip/Source/Logger/FSError.swift b/FlagShip/Source/Logger/FSError.swift index 129a46ba..81ebc7c0 100644 --- a/FlagShip/Source/Logger/FSError.swift +++ b/FlagShip/Source/Logger/FSError.swift @@ -15,7 +15,7 @@ enum ErrorType { } // Flagship Error -class FlagshipError: Error { +public class FlagshipError: Error { var message = "" var error: ErrorType let codeError: Int diff --git a/FlagShip/Source/Strategy/FSDefaultStrategy.swift b/FlagShip/Source/Strategy/FSDefaultStrategy.swift index f3b48465..f2d500a5 100644 --- a/FlagShip/Source/Strategy/FSDefaultStrategy.swift +++ b/FlagShip/Source/Strategy/FSDefaultStrategy.swift @@ -177,39 +177,39 @@ class FSDefaultStrategy: FSDelegateStrategy { } func authenticateVisitor(visitorId: String) { - if visitor.configManager.flagshipConfig.mode == .DECISION_API { - /// Update the visitor an anonymous id - if visitor.anonymousId == nil { - visitor.anonymousId = visitor.visitorId - } + // if visitor.configManager.flagshipConfig.mode == .DECISION_API { + /// Update the visitor an anonymous id + if visitor.anonymousId == nil { + visitor.anonymousId = visitor.visitorId + } - // Set the authenticated visitorId - visitor.visitorId = visitorId + // Set the authenticated visitorId + visitor.visitorId = visitorId - // Update fs_users for context - visitor.context.currentContext.updateValue(visitorId, forKey: FS_USERS) - #if os(iOS) - // Update the xpc info for the emotion AI - visitor.emotionCollect?.updateTupleId(visitorId: visitor.visitorId, anonymousId: visitor.anonymousId) - #endif - } else { - FlagshipLogManager.Log(level: .ALL, tag: .AUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_AUTHENTICATE) - } + // Update fs_users for context + visitor.context.currentContext.updateValue(visitorId, forKey: FS_USERS) + #if os(iOS) + // Update the xpc info for the emotion AI + visitor.emotionCollect?.updateTupleId(visitorId: visitor.visitorId, anonymousId: visitor.anonymousId) + #endif + // } else { + // FlagshipLogManager.Log(level: .ALL, tag: .AUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_AUTHENTICATE) + // } } func unAuthenticateVisitor() { - if visitor.configManager.flagshipConfig.mode == .DECISION_API { - if let anonymId = visitor.anonymousId { - visitor.visitorId = anonymId - // Update fs_users for context - visitor.context.currentContext.updateValue(anonymId, forKey: FS_USERS) - } + // if visitor.configManager.flagshipConfig.mode == .DECISION_API { + if let anonymId = visitor.anonymousId { + visitor.visitorId = anonymId + // Update fs_users for context + visitor.context.currentContext.updateValue(anonymId, forKey: FS_USERS) + } - visitor.anonymousId = nil + visitor.anonymousId = nil - } else { - FlagshipLogManager.Log(level: .ALL, tag: .AUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_UNAUTHENTICATE) - } + // } else { + // FlagshipLogManager.Log(level: .ALL, tag: .AUTHENTICATE, messageToDisplay: FSLogMessage.IGNORE_UNAUTHENTICATE) + // } #if os(iOS) // Update the xpc info for the emotion AI visitor.emotionCollect?.updateTupleId(visitorId: visitor.visitorId, anonymousId: visitor.anonymousId) @@ -226,21 +226,71 @@ class FSDefaultStrategy: FSDelegateStrategy { /// _ Lookup visitor func lookupVisitor() { - /// Read the visitor cache from storage - visitor.configManager.flagshipConfig.cacheManager.lookupVisitorCache(visitoId: visitor.visitorId) { error, cachedVisitor in + lookupVisitorWithId(visitor.visitorId) + } + + // MARK: - Private Helper Methods + + private func lookupVisitorWithId(_ visitorId: String) { + visitor.configManager.flagshipConfig.cacheManager.lookupVisitorCache(visitoId: visitorId) { [weak self] error, cachedVisitor in - if error == nil { - if let aCachedVisitor = cachedVisitor { - self.visitor.mergeCachedVisitor(aCachedVisitor) - /// Get the oldest assignation history before saving and loose the information - self.visitor.assignedVariationHistory.merge(aCachedVisitor.data?.assignationHistory ?? [:]) { _, new in new } - } + guard let strongSelf = self else { return } + + if let cachedVisitor = cachedVisitor { + strongSelf.processCachedVisitor(cachedVisitor) + } else if let error = error { + strongSelf.handleLookupError(error, for: visitorId) + } + } + } + + private func processCachedVisitor(_ cachedVisitor: FSCacheVisitor?) { + // Ensure thread safety for visitor property modifications + DispatchQueue.main.async { [weak self] in + guard let strongSelf = self else { return } + + // Cast to the appropriate cached visitor type + if let aCachedVisitor = cachedVisitor { + strongSelf.visitor.mergeCachedVisitor(aCachedVisitor) + + // Safely merge assignation history + let newHistory = aCachedVisitor.data?.assignationHistory ?? [:] + strongSelf.visitor.assignedVariationHistory.merge(newHistory) { _, new in new } + } + } + } + + private func handleLookupError(_ error: FlagshipError?, for visitorId: String) { + // Only attempt anonymous lookup for 404 errors and when anonymous ID exists + guard let fsError = error as FlagshipError?, + fsError.codeError == 404, + let anonymousId = visitor.anonymousId, + anonymousId != visitorId else { // Prevent infinite recursion + logLookupError() + return + } + + // Lookup anonymous visitor without nesting + lookupAnonymousVisitor(anonymousId) + } + + private func lookupAnonymousVisitor(_ anonymousId: String) { + visitor.configManager.flagshipConfig.cacheManager.lookupVisitorCache(visitoId: anonymousId) { [weak self] error, cachedAnonymous in + + guard let strongSelf = self else { return } + + if let cachedAnonymous = cachedAnonymous { + strongSelf.processCachedVisitor(cachedAnonymous) } else { - FlagshipLogManager.Log(level: .ALL, tag: .STORAGE, messageToDisplay: .ERROR_ON_READ_FILE) + strongSelf.logLookupError() } } } + private func logLookupError() { + FlagshipLogManager.Log(level: .ALL, tag: .STORAGE, messageToDisplay: .ERROR_ON_READ_FILE) + } + /// _ Flush visitor func flushVisitor() { /// Flush the visitor diff --git a/iOS Example/QApp/Base.lproj/Main.storyboard b/iOS Example/QApp/Base.lproj/Main.storyboard index 9f2c797c..2afc3ad4 100644 --- a/iOS Example/QApp/Base.lproj/Main.storyboard +++ b/iOS Example/QApp/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -22,7 +22,7 @@ - + @@ -277,7 +277,7 @@ - + - + - + @@ -338,7 +338,7 @@ - + @@ -349,7 +349,7 @@ @@ -414,33 +414,33 @@ - + - + - +