Skip to content

Commit 3e2b35b

Browse files
bsneedBrandon Sneed
andauthored
Bsneed/queueing (#24)
* added started property for destination * added event queueing plugin * added started support to example destinations. * Re-imagined startup queue. * Removed unnecessary code * A lil cleanup. * added queue limits back in. Co-authored-by: Brandon Sneed <[email protected]>
1 parent 8175947 commit 3e2b35b

File tree

11 files changed

+110
-49
lines changed

11 files changed

+110
-49
lines changed

Examples/destination_plugins/AdjustDestination.swift

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ public class AdjustDestination: NSObject, DestinationPlugin, RemoteNotifications
5757

5858
internal var settings: AdjustSettings? = nil
5959

60-
@Atomic var started = false
61-
6260
required public init(name: String) {
6361
self.name = name
6462
}
@@ -87,13 +85,9 @@ public class AdjustDestination: NSObject, DestinationPlugin, RemoteNotifications
8785
}
8886

8987
Adjust.appDidLaunch(adjustConfig)
90-
91-
started = true
9288
}
9389

9490
public func identify(event: IdentifyEvent) -> IdentifyEvent? {
95-
guard started == true else { return event }
96-
9791
if let userId = event.userId, userId.count > 0 {
9892
Adjust.addSessionPartnerParameter("user_id", value: userId)
9993
}
@@ -106,8 +100,6 @@ public class AdjustDestination: NSObject, DestinationPlugin, RemoteNotifications
106100
}
107101

108102
public func track(event: TrackEvent) -> TrackEvent? {
109-
guard started == true else { return event }
110-
111103
if let anonId = event.anonymousId, anonId.count > 0 {
112104
Adjust.addSessionPartnerParameter("anonymous_id", value: anonId)
113105
}
@@ -139,24 +131,17 @@ public class AdjustDestination: NSObject, DestinationPlugin, RemoteNotifications
139131
return event
140132
}
141133

142-
public func screen(event: ScreenEvent) -> ScreenEvent? {
143-
guard started == true else { return event }
144-
145-
return event
146-
}
147-
148134
public func reset() {
149-
guard started == true else { return }
150135
Adjust.resetSessionPartnerParameters()
151136
}
152137

153138
public func registeredForRemoteNotifications(deviceToken: Data) {
154-
guard started == true else { return }
155139
Adjust.setDeviceToken(deviceToken)
156140
}
157141
}
158142

159143
// MARK: - Adjust Delegate conformance
144+
160145
extension AdjustDestination: AdjustDelegate {
161146
public func adjustAttributionChanged(_ attribution: ADJAttribution?) {
162147
let campaign: [String: Any] = [
@@ -177,6 +162,7 @@ extension AdjustDestination: AdjustDelegate {
177162
analytics?.track(name: "Install Attributed", properties: properties)
178163
}
179164
}
165+
180166
// MARK: - Support methods
181167

182168
extension AdjustDestination {
@@ -204,16 +190,3 @@ extension AdjustDestination {
204190
return result
205191
}
206192
}
207-
208-
// we are missing support for:
209-
/*
210-
reset()
211-
flush()
212-
receivedRemoteNotification
213-
failedToRegisterForRemoteNotification
214-
registerForRemoteNotifications(deviceToken:)
215-
handleActionWithIdentifier
216-
continueUserActivity
217-
openURL:options:
218-
*/
219-

Examples/destination_plugins/AmplitudeSession.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ extension AmplitudeSession {
117117

118118
@objc
119119
func handleTimerFire(_ timer: Timer) {
120-
print("Timer Fired")
121-
print("Session: \(sessionID ?? -1)")
122120
stopTimer()
123121
startTimer()
124122
}

Examples/destination_plugins/FlurryDestination.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ class FlurryDestination: DestinationPlugin {
4848
let name: String
4949
var analytics: Analytics? = nil
5050

51-
var started = false
5251
var screenTracksEvents = false
5352

5453
required init(name: String) {
@@ -70,12 +69,9 @@ class FlurryDestination: DestinationPlugin {
7069
}
7170

7271
Flurry.startSession(flurryApiKey, with: builder)
73-
started = true
7472
}
7573

7674
func identify(event: IdentifyEvent) -> IdentifyEvent? {
77-
guard started == true else { return event }
78-
7975
Flurry.setUserID(event.userId)
8076

8177
if let traits = event.traits?.dictionaryValue {
@@ -92,16 +88,12 @@ class FlurryDestination: DestinationPlugin {
9288
}
9389

9490
func track(event: TrackEvent) -> TrackEvent? {
95-
guard started == true else { return event }
96-
9791
let props = truncate(properties: event.properties?.dictionaryValue)
9892
Flurry.logEvent(event.event, withParameters: props)
9993
return event
10094
}
10195

10296
func screen(event: ScreenEvent) -> ScreenEvent? {
103-
guard started == true else { return event }
104-
10597
if screenTracksEvents {
10698
let props = truncate(properties: event.properties?.dictionaryValue)
10799
Flurry.logEvent("Viewed \(event.name ?? "") Screen", withParameters: props)

Examples/destination_plugins/MixpanelDestination.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ class MixpanelDestination: DestinationPlugin {
7676
}
7777
}
7878

79-
func identify(event: IdentifyEvent) -> IdentifyEvent? {
80-
79+
func identify(event: IdentifyEvent) -> IdentifyEvent? {
8180
// Ensure that the userID is set and valid
8281
if let eventUserID = event.userId, !eventUserID.isEmpty {
8382
mixpanel?.identify(distinctId: eventUserID)

Examples/other_plugins/ConsentTracking.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class ConsentTracking: Plugin {
117117
for instance in Self.instances {
118118
instance.replayEvents()
119119
}
120+
clearQueuedEvents()
120121
}
121122

122123
func replayEvents() {

Segment.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
46022764261E64A800A9E913 /* iOSLifecycleEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46022763261E64A800A9E913 /* iOSLifecycleEvents.swift */; };
2626
4602276C261E7BF900A9E913 /* iOSDelegation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4602276B261E7BF900A9E913 /* iOSDelegation.swift */; };
2727
46022771261F7A4800A9E913 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46022770261F7A4800A9E913 /* Atomic.swift */; };
28+
46031D65266E7C10009BA540 /* StartupQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46031D64266E7C10009BA540 /* StartupQueue.swift */; };
2829
462107F22603DA4D00EBC4A8 /* Sovran in Frameworks */ = {isa = PBXBuildFile; productRef = 462107F12603DA4D00EBC4A8 /* Sovran */; };
2930
4621080C2605332D00EBC4A8 /* KeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4621080B2605332D00EBC4A8 /* KeyPath.swift */; };
3031
46210811260538BE00EBC4A8 /* KeyPath_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46210810260538BE00EBC4A8 /* KeyPath_Tests.swift */; };
@@ -103,6 +104,7 @@
103104
46022763261E64A800A9E913 /* iOSLifecycleEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSLifecycleEvents.swift; sourceTree = "<group>"; };
104105
4602276B261E7BF900A9E913 /* iOSDelegation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSDelegation.swift; sourceTree = "<group>"; };
105106
46022770261F7A4800A9E913 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
107+
46031D64266E7C10009BA540 /* StartupQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StartupQueue.swift; sourceTree = "<group>"; };
106108
4621080B2605332D00EBC4A8 /* KeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPath.swift; sourceTree = "<group>"; };
107109
46210810260538BE00EBC4A8 /* KeyPath_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPath_Tests.swift; sourceTree = "<group>"; };
108110
46210835260BBEE400EBC4A8 /* DeviceToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceToken.swift; sourceTree = "<group>"; };
@@ -211,6 +213,7 @@
211213
46A018C125E5857D00F9CCD8 /* Context.swift */,
212214
9692726725A583A6009B5298 /* SegmentDestination.swift */,
213215
46210835260BBEE400EBC4A8 /* DeviceToken.swift */,
216+
46031D64266E7C10009BA540 /* StartupQueue.swift */,
214217
);
215218
path = Plugins;
216219
sourceTree = "<group>";
@@ -469,6 +472,7 @@
469472
46A018C225E5857D00F9CCD8 /* Context.swift in Sources */,
470473
96208650257AA83E00314F8D /* iOSLifecycleMonitor.swift in Sources */,
471474
96C33AAC25892D6D00F3D538 /* Metrics.swift in Sources */,
475+
46031D65266E7C10009BA540 /* StartupQueue.swift in Sources */,
472476
);
473477
runOnlyForDeploymentPostprocessing = 0;
474478
};

Sources/Segment/Analytics.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ public class Analytics {
1414
internal var configuration: Configuration
1515
internal var store: Store
1616
internal var storage: Storage
17-
18-
private var built = false
19-
17+
2018
/// Enabled/disables debug logging to trace your data going through the SDK.
2119
public var debugLogsEnabled = false
2220

@@ -33,7 +31,7 @@ public class Analytics {
3331
store.provide(state: System.defaultState(configuration: configuration, from: storage))
3432
store.provide(state: UserInfo.defaultState(from: storage))
3533

36-
// Get everything hot and sweaty here
34+
// Get everything running
3735
platformStartup()
3836
}
3937

Sources/Segment/Plugins.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,29 @@ extension Analytics {
141141
*/
142142
@discardableResult
143143
public func add(plugin: Plugin) -> String {
144+
// we need to know if the system is already started.
145+
var wasStarted = false
146+
if let system: System = store.currentState(), system.started {
147+
wasStarted = system.started
148+
// if it was, we need to stop it temporarily.
149+
store.dispatch(action: System.SetStartedAction(started: false))
150+
// adding the plugin to the timeline below will eventually call
151+
// update(settings:) at which point, we can start it up again.
152+
}
153+
144154
plugin.configure(analytics: self)
145155
timeline.add(plugin: plugin)
146156
if plugin is DestinationPlugin && !(plugin is SegmentDestination) {
157+
// need to maintain the list of integrations to inject into payload
147158
store.dispatch(action: System.AddIntegrationAction(pluginName: plugin.name))
148159
}
160+
161+
// if the timeline had started before, set it back to started since
162+
// update(settings:) will have been called by now.
163+
if wasStarted {
164+
store.dispatch(action: System.SetStartedAction(started: true))
165+
}
166+
149167
return plugin.name
150168
}
151169

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// StartupQueue.swift
3+
// Segment
4+
//
5+
// Created by Brandon Sneed on 6/4/21.
6+
//
7+
8+
import Foundation
9+
import Sovran
10+
11+
class StartupQueue: Plugin, Subscriber {
12+
static var specificName = "Segment_StartupQueue"
13+
static let maxSize = 1000
14+
15+
@Atomic var started: Bool = false
16+
17+
let type: PluginType = .before
18+
let name: String = specificName
19+
var analytics: Analytics? = nil {
20+
didSet {
21+
analytics?.store.subscribe(self, handler: systemUpdate)
22+
}
23+
}
24+
25+
var queuedEvents = [RawEvent]()
26+
27+
required init(name: String) {
28+
// ignore name; hardcoded above.
29+
}
30+
31+
func execute<T: RawEvent>(event: T?) -> T? {
32+
if started == false, let e = event {
33+
// timeline hasn't started, so queue it up.
34+
if queuedEvents.count >= Self.maxSize {
35+
// if we've exceeded the max queue size start dropping events
36+
queuedEvents.removeFirst()
37+
}
38+
queuedEvents.append(e)
39+
return nil
40+
}
41+
// the timeline has started, so let the event pass.
42+
return event
43+
}
44+
}
45+
46+
extension StartupQueue {
47+
internal func systemUpdate(state: System) {
48+
started = state.started
49+
if started {
50+
replayEvents()
51+
}
52+
}
53+
54+
internal func replayEvents() {
55+
// replay the queued events to the instance of Analytics we're working with.
56+
for event in queuedEvents {
57+
analytics?.process(event: event)
58+
}
59+
queuedEvents.removeAll()
60+
}
61+
}

Sources/Segment/Startup.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ extension Analytics: Subscriber {
3232
if let settings = state.settings {
3333
self.update(settings: settings)
3434
}
35+
self.store.dispatch(action: System.SetStartedAction(started: true))
3536
}
3637

3738
// plugins will receive any settings we currently have as they are added.

0 commit comments

Comments
 (0)