From 5970aac15dd6068667830af48353ad879cedfc3c Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 11:55:02 -0800 Subject: [PATCH 01/22] Adds property to determine if any events are pending being sent. --- Sources/Segment/Analytics.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index b53539ff..7465becf 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -149,3 +149,10 @@ extension Analytics { } } + +extension Analytics { + /// Determine if there are any events that have yet to be sent to Segment + var pendingEvents: Bool { + return storage.eventFiles(includeUnfinished: true).count > 0 + } +} From ebbe3cf5a316fbdb57244979e7b90dd6682ed369 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 11:56:49 -0800 Subject: [PATCH 02/22] Make public and rename --- Sources/Segment/Analytics.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 7465becf..1d1ec806 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -152,7 +152,7 @@ extension Analytics { extension Analytics { /// Determine if there are any events that have yet to be sent to Segment - var pendingEvents: Bool { + public var hasUnsentEvents: Bool { return storage.eventFiles(includeUnfinished: true).count > 0 } } From 9202cb1870293083a13987b1cbc69ca5eba2a985 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 12:01:27 -0800 Subject: [PATCH 03/22] refactro --- Sources/Segment/Analytics.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 1d1ec806..1b4a88cd 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -153,6 +153,7 @@ extension Analytics { extension Analytics { /// Determine if there are any events that have yet to be sent to Segment public var hasUnsentEvents: Bool { - return storage.eventFiles(includeUnfinished: true).count > 0 + let result = storage.eventFiles(includeUnfinished: true).count > 0 + return result } } From accb888fc903ca4f2615df923c3dec896cd771af Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 12:08:44 -0800 Subject: [PATCH 04/22] fine tuning --- Sources/Segment/Analytics.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 1b4a88cd..26472aaf 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -153,7 +153,15 @@ extension Analytics { extension Analytics { /// Determine if there are any events that have yet to be sent to Segment public var hasUnsentEvents: Bool { - let result = storage.eventFiles(includeUnfinished: true).count > 0 + var result = true + + let hasFiles = storage.eventFiles(includeUnfinished: true).count > 0 + var pendingUploads = false + if let segmentDest = self.find(pluginType: SegmentDestination.self) { + pendingUploads = segmentDest.pendingUploads != 0 + } + + result = (hasFiles && pendingUploads) return result } } From 340acaa016d65bd682320e831a4f3f801c5e0e4b Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 14:29:43 -0800 Subject: [PATCH 05/22] additional checks --- Sources/Segment/Analytics.swift | 4 +++- Sources/Segment/Plugins/SegmentDestination.swift | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 26472aaf..14a690cf 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -157,11 +157,13 @@ extension Analytics { let hasFiles = storage.eventFiles(includeUnfinished: true).count > 0 var pendingUploads = false + var queuedEvents = false if let segmentDest = self.find(pluginType: SegmentDestination.self) { pendingUploads = segmentDest.pendingUploads != 0 + queuedEvents = segmentDest.eventCount != 0 } - result = (hasFiles && pendingUploads) + result = (hasFiles && pendingUploads && queuedEvents) return result } } diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index f2685be1..c310ed2b 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -48,7 +48,7 @@ public class SegmentDestination: DestinationPlugin { private var apiKey: String? = nil private var apiHost: String? = nil - @Atomic private var eventCount: Int = 0 + @Atomic internal var eventCount: Int = 0 internal var flushTimer: QueueTimer? = nil internal func initialSetup() { From 066de0c7092e5e48a075cb46b32cb5d8db7d2833 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 14:34:43 -0800 Subject: [PATCH 06/22] logic fix --- Sources/Segment/Analytics.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 14a690cf..f759e1ec 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -163,7 +163,7 @@ extension Analytics { queuedEvents = segmentDest.eventCount != 0 } - result = (hasFiles && pendingUploads && queuedEvents) + result = (hasFiles || pendingUploads || queuedEvents) return result } } From a27cf29444957496d1dd6e33aea4aabc8a2d50a8 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 15:07:34 -0800 Subject: [PATCH 07/22] optimization --- Sources/Segment/Analytics.swift | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index f759e1ec..23a10671 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -153,17 +153,19 @@ extension Analytics { extension Analytics { /// Determine if there are any events that have yet to be sent to Segment public var hasUnsentEvents: Bool { - var result = true - - let hasFiles = storage.eventFiles(includeUnfinished: true).count > 0 - var pendingUploads = false - var queuedEvents = false if let segmentDest = self.find(pluginType: SegmentDestination.self) { - pendingUploads = segmentDest.pendingUploads != 0 - queuedEvents = segmentDest.eventCount != 0 + if segmentDest.pendingUploads > 0 { + return true + } + if segmentDest.eventCount > 0 { + return true + } } - - result = (hasFiles || pendingUploads || queuedEvents) - return result + + if storage.eventFiles(includeUnfinished: true).count > 0 { + return true + } + + return false } } From 9a621b58aaa5e30335a61892cd4f2d0b9b6155bd Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 15:12:28 -0800 Subject: [PATCH 08/22] fixed event count set --- Sources/Segment/Plugins/SegmentDestination.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index c310ed2b..b3568b3b 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -98,7 +98,6 @@ public class SegmentDestination: DestinationPlugin { storage.write(.events, value: event) eventCount += 1 if eventCount >= analytics.configuration.values.flushAt { - eventCount = 0 flush() } } @@ -111,6 +110,7 @@ public class SegmentDestination: DestinationPlugin { // Read events from file system guard let data = storage.read(Storage.Constants.events) else { return } + eventCount = 0 cleanupUploads() analytics.log(message: "Uploads in-progress: \(pendingUploads)") From 9cfa8badbf54a6d442e3fd50a66b59e496396ddd Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 15:29:27 -0800 Subject: [PATCH 09/22] stop bypassing sync queue --- Sources/Segment/Analytics.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 23a10671..a3c36994 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -162,7 +162,7 @@ extension Analytics { } } - if storage.eventFiles(includeUnfinished: true).count > 0 { + if storage.read(Storage.Constants.events)?.count > 0 { return true } From 8a27b87bdb58f7e9a30cb64bca26e19b0a288e57 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 15:31:14 -0800 Subject: [PATCH 10/22] fixed optional --- Sources/Segment/Analytics.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index a3c36994..90b15e6a 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -162,8 +162,10 @@ extension Analytics { } } - if storage.read(Storage.Constants.events)?.count > 0 { - return true + if let files = storage.read(Storage.Constants.events) { + if files.count > 0 { + return true + } } return false From a1c36027505fe345ce191e9e1164d4badbd13a52 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 15:44:21 -0800 Subject: [PATCH 11/22] added another convenience method --- Sources/Segment/Analytics.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 90b15e6a..89eb644c 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -170,4 +170,8 @@ extension Analytics { return false } + + public var pendingUploads: [URL]? { + return storage.read(Storage.Constants.events) + } } From e78bfe48e82a8f1775eedbdf4785e17c8de44f39 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:06:05 -0800 Subject: [PATCH 12/22] fix missing file handle --- Sources/Segment/Utilities/Storage.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/Segment/Utilities/Storage.swift b/Sources/Segment/Utilities/Storage.swift index d0455fff..88aeca2d 100644 --- a/Sources/Segment/Utilities/Storage.swift +++ b/Sources/Segment/Utilities/Storage.swift @@ -279,10 +279,14 @@ extension Storage { } private func finish(file: URL) { + if self.fileHandle == nil { + self.fileHandle = try FileHandle(forWritingTo: file) + } + guard let fileHandle = self.fileHandle else { // we haven't actually started a file yet and being told to flush // so ignore it and get out. - return + //return } let sentAt = Date().iso8601() From bf60c04de9bb5282f50fd18b58ea96eae553b3a4 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:07:15 -0800 Subject: [PATCH 13/22] fix missing optional --- Sources/Segment/Utilities/Storage.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Segment/Utilities/Storage.swift b/Sources/Segment/Utilities/Storage.swift index 88aeca2d..d48f04fa 100644 --- a/Sources/Segment/Utilities/Storage.swift +++ b/Sources/Segment/Utilities/Storage.swift @@ -280,13 +280,13 @@ extension Storage { private func finish(file: URL) { if self.fileHandle == nil { - self.fileHandle = try FileHandle(forWritingTo: file) + self.fileHandle = try? FileHandle(forWritingTo: file) } guard let fileHandle = self.fileHandle else { // we haven't actually started a file yet and being told to flush // so ignore it and get out. - //return + return } let sentAt = Date().iso8601() From d36c810bc1833ba595b8628704df51cfa77ff3c9 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:12:37 -0800 Subject: [PATCH 14/22] another fix --- Sources/Segment/Plugins/SegmentDestination.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index b3568b3b..6fa41748 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -123,6 +123,7 @@ public class SegmentDestination: DestinationPlugin { switch result { case .success(_): storage.remove(file: url) + self.cleanupUploads() default: analytics.logFlush() } From 0b102dc7fdb1a70dd7e92b708340e16574c6ee64 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:50:12 -0800 Subject: [PATCH 15/22] fixes --- Sources/Segment/Plugins/SegmentDestination.swift | 2 +- Sources/Segment/Plugins/StartupQueue.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index 6fa41748..ce317bab 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -123,7 +123,7 @@ public class SegmentDestination: DestinationPlugin { switch result { case .success(_): storage.remove(file: url) - self.cleanupUploads() + self.cleanupUploads() default: analytics.logFlush() } diff --git a/Sources/Segment/Plugins/StartupQueue.swift b/Sources/Segment/Plugins/StartupQueue.swift index fcc9a6a1..0200f5ce 100644 --- a/Sources/Segment/Plugins/StartupQueue.swift +++ b/Sources/Segment/Plugins/StartupQueue.swift @@ -8,7 +8,7 @@ import Foundation import Sovran -internal class StartupQueue: Plugin, Subscriber { +public class StartupQueue: Plugin, Subscriber { static let maxSize = 1000 @Atomic var running: Bool = false From f72627a52c62c2ccf0d96aa402f1022ae1d84397 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:52:02 -0800 Subject: [PATCH 16/22] more fixes --- Sources/Segment/Plugins/StartupQueue.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Segment/Plugins/StartupQueue.swift b/Sources/Segment/Plugins/StartupQueue.swift index 0200f5ce..41cc60b8 100644 --- a/Sources/Segment/Plugins/StartupQueue.swift +++ b/Sources/Segment/Plugins/StartupQueue.swift @@ -13,9 +13,9 @@ public class StartupQueue: Plugin, Subscriber { @Atomic var running: Bool = false - let type: PluginType = .before + public let type: PluginType = .before - var analytics: Analytics? = nil { + public var analytics: Analytics? = nil { didSet { analytics?.store.subscribe(self, handler: runningUpdate) } @@ -26,7 +26,7 @@ public class StartupQueue: Plugin, Subscriber { required init() { } - func execute(event: T?) -> T? { + public func execute(event: T?) -> T? { if running == false, let e = event { // timeline hasn't started, so queue it up. syncQueue.sync { From 4d70c7e6b54b33bea5d2607ca79c2731a0739ac5 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:53:09 -0800 Subject: [PATCH 17/22] and another --- Sources/Segment/Plugins/StartupQueue.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Plugins/StartupQueue.swift b/Sources/Segment/Plugins/StartupQueue.swift index 41cc60b8..c29a08ed 100644 --- a/Sources/Segment/Plugins/StartupQueue.swift +++ b/Sources/Segment/Plugins/StartupQueue.swift @@ -11,7 +11,7 @@ import Sovran public class StartupQueue: Plugin, Subscriber { static let maxSize = 1000 - @Atomic var running: Bool = false + @Atomic public var running: Bool = false public let type: PluginType = .before From 7c9924a1488a62a699afaf167cf50d6afd3d6b20 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 16:59:05 -0800 Subject: [PATCH 18/22] utility method --- Sources/Segment/Analytics.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index 89eb644c..a62dab85 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -171,7 +171,20 @@ extension Analytics { return false } + /// Provides a list of finished, but unsent events. public var pendingUploads: [URL]? { return storage.read(Storage.Constants.events) } + + /// Wait until the Analytics object has completed startup. + /// This method is primarily useful for command line utilities where + /// it's desirable to wait until the system is up and running + /// before executing commands. + func waitUntilStarted() { + if let startupQueue = find(pluginType: StartupQueue.self) { + while startupQueue.running != true { + RunLoop.main.run(until: Date.distantPast) + } + } + } } From dc609d2432add3f28c9ba4884b5df57f6819eeff Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 6 Dec 2021 17:01:14 -0800 Subject: [PATCH 19/22] docs update --- Sources/Segment/Analytics.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index a62dab85..86becb53 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -179,8 +179,9 @@ extension Analytics { /// Wait until the Analytics object has completed startup. /// This method is primarily useful for command line utilities where /// it's desirable to wait until the system is up and running - /// before executing commands. - func waitUntilStarted() { + /// before executing commands. GUI apps could potentially use this via + /// a background thread if needed. + public func waitUntilStarted() { if let startupQueue = find(pluginType: StartupQueue.self) { while startupQueue.running != true { RunLoop.main.run(until: Date.distantPast) From 916c391f157d50edfa697adb115249cfbb03506d Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Thu, 6 Jan 2022 10:49:41 -0800 Subject: [PATCH 20/22] Add screen call to example --- .../SegmentUIKitExample/SegmentUIKitExample/AppDelegate.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Examples/apps/SegmentUIKitExample/SegmentUIKitExample/AppDelegate.swift b/Examples/apps/SegmentUIKitExample/SegmentUIKitExample/AppDelegate.swift index bb966a22..0a53104f 100644 --- a/Examples/apps/SegmentUIKitExample/SegmentUIKitExample/AppDelegate.swift +++ b/Examples/apps/SegmentUIKitExample/SegmentUIKitExample/AppDelegate.swift @@ -24,6 +24,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Analytics.support.track(name: "test event") + Analytics.main.screen(title: "home screen shown", category: nil, properties: nil) return true } From 355d0c3ab6cacee52196b0f141bb0a4a84c89f09 Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Thu, 7 Jul 2022 10:04:57 -0700 Subject: [PATCH 21/22] Improve error message for path lookup failure. --- Sources/Segment/Utilities/JSON.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Segment/Utilities/JSON.swift b/Sources/Segment/Utilities/JSON.swift index 6d35d76a..5f67ad48 100644 --- a/Sources/Segment/Utilities/JSON.swift +++ b/Sources/Segment/Utilities/JSON.swift @@ -397,7 +397,7 @@ extension JSON { do { result = try JSONDecoder().decode(T.self, from: jsonData) } catch { - Analytics.segmentLog(message: "Unable to decode object to a Codable: \(error)", kind: .error) + Analytics.segmentLog(message: "Unable to decode object (\(keyPath)) to a Codable: \(error)", kind: .error) } } if result == nil { From 431100f3b6becf434bb764556f3d3069ac25bb1f Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Thu, 7 Jul 2022 10:05:11 -0700 Subject: [PATCH 22/22] Fixed cellular carrier path. --- Examples/other_plugins/CellularCarrier.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/other_plugins/CellularCarrier.swift b/Examples/other_plugins/CellularCarrier.swift index 3285bb87..31fc74ea 100644 --- a/Examples/other_plugins/CellularCarrier.swift +++ b/Examples/other_plugins/CellularCarrier.swift @@ -59,7 +59,7 @@ class CellularCarrier: Plugin { func execute(event: T?) -> T? { guard var workingEvent = event else { return event } - if let isCellular: Bool = workingEvent.context?[keyPath: "network"], + if let isCellular: Bool = workingEvent.context?[keyPath: "network.cellular"], isCellular, let carriers = self.carriers {