Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion FlagShip.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = "FlagShip"
s.version = "5.0.0-beta.6"
s.version = "5.1.0-beta.1"
s.summary = "Flagship SDK"

# This description is used to generate tags and improve search results.
Expand Down
4 changes: 2 additions & 2 deletions FlagShip/Flagship.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1880,7 +1880,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = "5.0.0-beta.6";
MARKETING_VERSION = "5.1.0-beta.1";
OTHER_LDFLAGS = "";
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = ABTasty.FlagShip;
Expand Down Expand Up @@ -1914,7 +1914,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = "5.0.0-beta.6";
MARKETING_VERSION = "5.1.0-beta.1";
OTHER_LDFLAGS = "";
OTHER_SWIFT_FLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = ABTasty.FlagShip;
Expand Down
4 changes: 4 additions & 0 deletions FlagShip/Source/Cache/FSCacheDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ 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)

/// Called to check if the visitor data is already in the database
@objc optional
func isVisitorCacheExist(visitorId: String) -> Bool
}

@objc public protocol FSHitCacheDelegate {
Expand Down
28 changes: 24 additions & 4 deletions FlagShip/Source/Cache/FSCacheManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,26 @@ import Foundation
}

/// Cache the visitor
///
///

/// Check if visitor cache exists for the given visitor ID
/// - Parameter visitorId: The visitor identifier to check
/// - Returns: `true` if cache exists, `false` otherwise (including if delegate is not set)
func isVisitorCacheExist(_ visitorId: String) -> Bool {
guard let visitorDelegate = cacheVisitorDelegate else {
FlagshipLogManager.Log(
level: .WARNING,
tag: .STORAGE,
messageToDisplay: FSLogMessage.MESSAGE("Cache delegate is not set")
)
return false
}

// Call optional protocol method with safe unwrapping
return visitorDelegate.isVisitorCacheExist?(visitorId: visitorId) ?? false
}

/// - Parameter visitor: visitor instance
func cacheVisitor(_ visitor: FSVisitor) {
/// Create visitor cache object
Expand All @@ -58,7 +78,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
Expand All @@ -72,10 +92,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()
}
Expand All @@ -102,7 +122,7 @@ import Foundation
hitCacheDelegate?.cacheHits(hits: hits)
}

func lookupHits(onCompletion: @escaping (Error?, [FSTrackingProtocol]?)->Void) {
func lookupHits(onCompletion: @escaping (Error?, [FSTrackingProtocol]?) -> Void) {
/// Create a Thread
let fsHitCacheQueue = DispatchQueue(label: "com.flagshipLookupHitCache.queue", attributes: .concurrent)
/// Init the semaphore
Expand Down
4 changes: 4 additions & 0 deletions FlagShip/Source/Cache/FSDefaultCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public class FSDefaultCacheVisitor: FSVisitorCacheDelegate {
public func flushVisitor(visitorId: String) {
dbMgt_visitor.delete(idItemToDelete: visitorId)
}

public func isVisitorCacheExist(visitorId: String) -> Bool {
return dbMgt_visitor.isVisitorExist(visitorId)
}
}

////////////////////////////||
Expand Down
39 changes: 31 additions & 8 deletions FlagShip/Source/Core/FSVisitor+Reconcilliation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ 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
}
self.strategy?.getStrategy().authenticateVisitor(visitorId: visitorId)
self.updateStateAndTriggerCallback(true)
// Troubleshooting xpc
Expand All @@ -27,10 +23,6 @@ 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
}
self.strategy?.getStrategy().unAuthenticateVisitor()
self.updateStateAndTriggerCallback(false)
// Troubleshooting xpc
Expand All @@ -43,4 +35,35 @@ public extension FSVisitor {
// Set the fetch state to required state
self.fetchStatus = .FETCH_REQUIRED
}

// Cpy method actually used only in bucketin mode - that expalin why we put here in this extension
func copy() -> FSVisitor {
let copiedVisitor = FSVisitor(
aVisitorId: self.visitorId,
aContext: self.context.getCurrentContext(),
aConfigManager: self.configManager,
aHasConsented: self.hasConsented,
aIsAuthenticated: self.isAuthenticated,
pOnFlagStatusChanged: self._onFlagStatusChanged,
pOnFlagStatusFetchRequired: self._onFlagStatusFetchRequired,
pOnFlagStatusFetched: self._onFlagStatusFetched
)

// Copy additional properties
copiedVisitor.anonymousId = self.anonymousId
copiedVisitor.currentFlags = self.currentFlags
copiedVisitor.assignedVariationHistory = self.assignedVariationHistory
copiedVisitor.requiredFetchReason = self.requiredFetchReason
copiedVisitor.eaiVisitorScored = self.eaiVisitorScored
copiedVisitor.emotionScoreAI = self.emotionScoreAI
copiedVisitor.fetchStatus = self.fetchStatus

// Copy strategy if needed
if let strategy = self.strategy {
copiedVisitor.strategy = FSStrategy(copiedVisitor)
}
return copiedVisitor
}


}
15 changes: 15 additions & 0 deletions FlagShip/Source/Core/FSVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -154,6 +159,16 @@ import Foundation
self.sendHit(FSSegment(self.getContext()))
self.context.needToUpload = false
}

// Another task for bucketin fin xcp mode is to save the anonymous when hase no cache

if let ano = self.anonymousId {
if !self.configManager.flagshipConfig.cacheManager.isVisitorCacheExist(ano) {
let anoVisitor: FSVisitor = self.copy()
anoVisitor.visitorId = ano
self.configManager.flagshipConfig.cacheManager.cacheVisitor(anoVisitor)
}
}
}
// Update the reason status
self.requiredFetchReason = reason
Expand Down
6 changes: 1 addition & 5 deletions FlagShip/Source/Core/Flagship.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,7 @@ public class Flagship: NSObject {
newVisitor.strategy = FSStrategy(newVisitor)

if hasConsented {
// Read the cached visitor
newVisitor.strategy?.getStrategy().lookupVisitor()
// Read the cacheed hits from data base
newVisitor.strategy?.getStrategy().lookupHits()

newVisitor.strategy?.getStrategy().lookupHits()
} else {
// user not consent then flush the cache related
newVisitor.strategy?.getStrategy().flushVisitor()
Expand Down
2 changes: 1 addition & 1 deletion FlagShip/Source/Logger/FSError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ enum ErrorType {
}

// Flagship Error
class FlagshipError: Error {
public class FlagshipError: Error {
var message = ""
var error: ErrorType
let codeError: Int
Expand Down
33 changes: 33 additions & 0 deletions FlagShip/Source/Storage/FSVisitorDbMgt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,37 @@ class FSVisitorDbMgt: FSQLiteWrapper {
}
return nil
}

// Add this function to FSVisitorDbMgt class
public func isVisitorExist(_ visitorId: String) -> Bool {
var queryPointer: OpaquePointer?
let queryStatementString = "SELECT COUNT(*) FROM table_visitors WHERE id = ?;"

// Prepare the query with parameter binding for safety
guard sqlite3_prepare_v2(db_opaquePointer, queryStatementString, -1, &queryPointer, nil) == SQLITE_OK else {
FlagshipLogManager.Log(level: .ERROR, tag: .STORAGE, messageToDisplay: FSLogMessage.MESSAGE("sqlite3 prepare error"))
return false
}

defer {
// Always cleanup the prepared statement
sqlite3_finalize(queryPointer)
}

// Bind the visitor ID parameter (safer than string interpolation)
guard sqlite3_bind_text(queryPointer, 1, (visitorId as NSString).utf8String, -1, nil) == SQLITE_OK else {
FlagshipLogManager.Log(level: .ERROR, tag: .STORAGE, messageToDisplay: FSLogMessage.MESSAGE("sqlite3 binding error"))
return false
}

// Execute the query and get the count
if sqlite3_step(queryPointer) == SQLITE_ROW {
let count = sqlite3_column_int(queryPointer, 0)
return count > 0
}

return false
}


}
Loading
Loading