Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified Analytics References #19

Merged
merged 1 commit into from
Mar 18, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
45 changes: 15 additions & 30 deletions FlagsmithClient/Classes/Flagsmith.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,30 @@ public class Flagsmith {
/// Shared singleton client object
public static let shared = Flagsmith()
private let apiManager = APIManager()
private lazy var analytics = FlagsmithAnalytics(apiManager: apiManager)

/// Base URL
public var baseURL: URL {
set {
apiManager.baseURL = newValue
}
get {
return apiManager.baseURL
}
set { apiManager.baseURL = newValue }
get { apiManager.baseURL }
}

/// API Key
public var apiKey: String? {
set {
apiManager.apiKey = newValue
}
get {
return apiManager.apiKey
}
set { apiManager.apiKey = newValue }
get { apiManager.apiKey }
}

/// Is flag analytics enabled?
public var enableAnalytics: Bool = true
public var enableAnalytics: Bool {
set { analytics.enableAnalytics = newValue }
get { analytics.enableAnalytics }
}

/// How often to send the flag analytics, in seconds
public var analyticsFlushPeriod: Int = 10 {
didSet {
FlagsmithAnalytics.shared.setupTimer()
}
public var analyticsFlushPeriod: Int {
set { analytics.flushPeriod = newValue }
get { analytics.flushPeriod }
}

private init() {}
Expand Down Expand Up @@ -76,7 +71,7 @@ public class Flagsmith {
public func hasFeatureFlag(withID id: String,
forIdentity identity: String? = nil,
completion: @escaping (Result<Bool, Error>) -> Void) {
FlagsmithAnalytics.shared.trackEvent(flagName: id)
analytics.trackEvent(flagName: id)
getFeatureFlags(forIdentity: identity) { (result) in
switch result {
case .success(let flags):
Expand All @@ -98,7 +93,7 @@ public class Flagsmith {
public func getFeatureValue(withID id: String,
forIdentity identity: String? = nil,
completion: @escaping (Result<String?, Error>) -> Void) {
FlagsmithAnalytics.shared.trackEvent(flagName: id)
analytics.trackEvent(flagName: id)
getFeatureFlags(forIdentity: identity) { (result) in
switch result {
case .success(let flags):
Expand All @@ -119,7 +114,7 @@ public class Flagsmith {
public func getValueForFeature(withID id: String,
forIdentity identity: String? = nil,
completion: @escaping (Result<TypedValue?, Error>) -> Void) {
FlagsmithAnalytics.shared.trackEvent(flagName: id)
analytics.trackEvent(flagName: id)
getFeatureFlags(forIdentity: identity) { (result) in
switch result {
case .success(let flags):
Expand Down Expand Up @@ -200,14 +195,4 @@ public class Flagsmith {
completion(result)
}
}

/// Post analytics
///
/// - Parameters:
/// - completion: Closure with Result which contains empty String in case of success or Error in case of failure
func postAnalytics(completion: @escaping (Result<String, Error>) -> Void) {
apiManager.request(.postAnalytics(events: FlagsmithAnalytics.shared.events), emptyResponse: true) { (result: Result<String, Error>) in
completion(result)
}
}
}
113 changes: 69 additions & 44 deletions FlagsmithClient/Classes/FlagsmithAnalytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,77 @@
import Foundation

class FlagsmithAnalytics {

static let shared = FlagsmithAnalytics()

let EVENTS_KEY = "events"
var events:[String:Int] = [:]

var timer:Timer?

init() {
events = UserDefaults.standard.dictionary(forKey: EVENTS_KEY) as? [String:Int] ?? [:]
setupTimer()

/// Indicates if analytics are enabled.
var enableAnalytics: Bool = true
/// How often analytics events are processed (in seconds).
var flushPeriod: Int = 10 {
didSet {
setupTimer()
}

func setupTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(timeInterval: TimeInterval(Flagsmith.shared.analyticsFlushPeriod), target: self, selector: #selector(postAnalytics(_:)), userInfo: nil, repeats: true)
}

private unowned let apiManager: APIManager
private let EVENTS_KEY = "events"
private var events:[String:Int] = [:]
private var timer:Timer?

init(apiManager: APIManager) {
self.apiManager = apiManager
events = UserDefaults.standard.dictionary(forKey: EVENTS_KEY) as? [String:Int] ?? [:]
setupTimer()
}

/// Counts the instances of a `Flag` being queried.
func trackEvent(flagName:String) {
let current = events[flagName] ?? 0
events[flagName] = current + 1
saveEvents()
}

/// Invalidate and re-schedule timer for processing events
private func setupTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(
timeInterval: TimeInterval(flushPeriod),
target: self,
selector: #selector(postAnalytics(_:)),
userInfo: nil,
repeats: true
)
}

/// Reset events after successful processing.
private func reset() {
events = [:]
saveEvents()
}

/// Persist the events to storage.
private func saveEvents() {
UserDefaults.standard.set(events, forKey: EVENTS_KEY)
}

/// Send analytics to the api when enabled.
@objc private func postAnalytics(_ timer: Timer) {
guard enableAnalytics else {
return
}

func trackEvent(flagName:String) {
let current = events[flagName] ?? 0
events[flagName] = current + 1
saveEvents()

guard !events.isEmpty else {
return
}

func reset() {
events = [:]
saveEvents()
}

func saveEvents() {
UserDefaults.standard.set(events, forKey: EVENTS_KEY)
}

@objc func postAnalytics(_ timer: Timer) {
if Flagsmith.shared.enableAnalytics {
if !events.isEmpty {
Flagsmith.shared.postAnalytics() {
(result) in
switch result {
case .success( _):
self.reset()
case .failure( _):
print("Upload analytics failed")
}
}
}
}

apiManager.request(
.postAnalytics(events: events),
emptyResponse: true
) { [weak self] (result: Result<String, Error>) in
switch result {
case .failure:
print("Upload analytics failed")
case .success:
self?.reset()
}
}
}
}