Skip to content

Commit 32da3d8

Browse files
committed
more fixups.
1 parent e138a6a commit 32da3d8

File tree

15 files changed

+300
-199
lines changed

15 files changed

+300
-199
lines changed
Lines changed: 105 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//
22
// File.swift
3-
//
3+
//
44
//
55
// Created by Brandon Sneed on 5/5/22.
66
//
@@ -14,8 +14,6 @@ public class AnalyticsJS: JSExport {
1414

1515
internal weak var analytics: Analytics?
1616

17-
internal var addedPlugins = [(String?, LivePlugin)]()
18-
1917
internal lazy var currentLivePluginVersion: String? = {
2018
return LivePlugins.currentLivePluginVersion()
2119
}()
@@ -36,9 +34,13 @@ public class AnalyticsJS: JSExport {
3634
Self.existingInstances.removeAll(where: { $0 === self.analytics })
3735
}
3836

37+
3938
static func insertOrigin(event: RawEvent?, data: [String: Any]) -> RawEvent? {
4039
guard var working = event else { return event }
41-
if let newContext = try? working.context?.add(value: data, forKey: "__eventOrigin") {
40+
if let newContext = try? working.context?.add(
41+
value: data,
42+
forKey: "__eventOrigin"
43+
) {
4244
working.context = newContext
4345
}
4446
return working
@@ -51,45 +53,76 @@ public class AnalyticsJS: JSExport {
5153
])
5254
}
5355

56+
private func contextEnrichment(with context: [String: Any]?) -> EnrichmentClosure {
57+
return { event in
58+
guard var working = event, let context = context else {
59+
return event
60+
}
61+
62+
// Get existing context as dictionary and merge with new context
63+
var mergedContext = working.context?.dictionaryValue ?? [:]
64+
mergedContext.merge(context) { _, new in new }
65+
66+
do {
67+
working.context = try JSON(mergedContext)
68+
} catch {
69+
// If JSON creation fails, return original event
70+
return event
71+
}
72+
return working
73+
}
74+
}
75+
76+
private func enrichments(with context: [String: Any]?) -> [EnrichmentClosure] {
77+
var enrichments = [originMarkerEnrichment]
78+
if let context = context {
79+
enrichments.append(contextEnrichment(with: context))
80+
}
81+
return enrichments
82+
}
83+
5484
internal func setupExports() {
5585
exportProperty(named: "traits") { [weak self] in
56-
guard let self else { return nil }
57-
let traits: [String: Any]? = analytics?.traits()
86+
guard let self, let analytics = self.analytics else { return nil }
87+
let traits: [String: Any]? = analytics.traits()
5888
return traits as? JSConvertible
5989
}
6090

6191
exportProperty(named: "userId") { [weak self] in
62-
guard let self else { return nil }
63-
return analytics?.userId
92+
return self?.analytics?.userId
6493
}
6594

6695
exportProperty(named: "anonymousId") { [weak self] in
67-
guard let self else { return nil }
68-
return analytics?.anonymousId
96+
return self?.analytics?.anonymousId
6997
}
7098

7199
exportMethod(named: "track") { [weak self] in self?.track(args: $0) }
72-
exportMethod(named: "identify") { [weak self] in self?.identify(args: $0) }
100+
exportMethod(named: "identify") {
101+
[weak self] in self?.identify(args: $0)
102+
}
73103
exportMethod(named: "screen") { [weak self] in self?.screen(args: $0) }
74104
exportMethod(named: "group") { [weak self] in self?.group(args: $0) }
75-
exportMethod(named: "alias") { [weak self] in self?.alias(args: $0) }
76105
exportMethod(named: "add") { [weak self] in self?.add(args: $0) }
77106
exportMethod(named: "flush") { [weak self] in self?.flush(args: $0) }
78107
exportMethod(named: "reset") { [weak self] in self?.reset(args: $0) }
79-
exportMethod(named: "removeLivePlugins") { [weak self] in self?.removeLivePlugins(args: $0) }
80108
}
81109

82110
public override func construct(args: [JSConvertible?]) {
83111
if let writeKey = args.typed(as: String.self, index: 0) {
84-
let existing = Self.existingInstances.first(where: { $0.writeKey == writeKey })
112+
let existing = Self.existingInstances.first(
113+
where: { $0.writeKey == writeKey
114+
})
85115
if let existing {
86116
self.analytics = existing
87117
return
88118
} else {
89119
// we do some work on user-created instances to avoid multiple instances of the same write key
90120
// by just attaching whatever existing instance that might exist with that write key.
91-
let createdAnalytics = Analytics(configuration: Configuration(writeKey: writeKey)
92-
.trackApplicationLifecycleEvents(false)
121+
let createdAnalytics = Analytics(
122+
configuration: Configuration(
123+
writeKey: writeKey
124+
)
125+
.setTrackedApplicationLifecycleEvents(.none)
93126
)
94127
Self.existingInstances.append(createdAnalytics)
95128
self.analytics = createdAnalytics
@@ -99,113 +132,109 @@ public class AnalyticsJS: JSExport {
99132

100133
public func track(args: [JSConvertible?]) -> JSConvertible? {
101134
guard let analytics else { return nil }
102-
guard let name = args.typed(as: String.self, index: 0) else { return nil }
103-
let properties = args.typed(as: Dictionary.self, index: 1)
104-
105-
let addEventOrigin: EnrichmentClosure = { [weak self] event in
106-
return Self.insertOrigin(event: event, data: [
107-
"type": "signals",
108-
"version": self?.currentLivePluginVersion ?? ""
109-
])
135+
guard let name = args.typed(as: String.self, index: 0) else {
136+
return nil
110137
}
138+
let properties = args.typed(as: Dictionary.self, index: 1)
139+
let context = args.typed(as: Dictionary.self, index: 2)
111140

112-
analytics.track(name: name, properties: properties, enrichments: [addEventOrigin])
141+
analytics
142+
.track(
143+
name: name,
144+
properties: properties,
145+
enrichments: enrichments(with: context)
146+
)
113147
return nil
114148
}
115149

116150
public func identify(args: [JSConvertible?]) -> JSConvertible? {
117151
guard let analytics else { return nil }
118-
guard let userId = args.typed(as: String.self, index: 0) else { return nil }
152+
guard let userId = args.typed(as: String.self, index: 0) else {
153+
return nil
154+
}
119155
let traits = args.typed(as: Dictionary.self, index: 1)
120-
analytics.identify(userId: userId, traits: traits, enrichments: [originMarkerEnrichment])
156+
let context = args.typed(as: Dictionary.self, index: 2)
157+
analytics
158+
.identify(
159+
userId: userId,
160+
traits: traits,
161+
enrichments: enrichments(with: context)
162+
)
121163
return nil
122164
}
123165

124166
public func screen(args: [JSConvertible?]) -> JSConvertible? {
125167
guard let analytics else { return nil }
126-
guard let title = args.typed(as: String.self, index: 0) else { return nil }
168+
guard let title = args.typed(as: String.self, index: 0) else {
169+
return nil
170+
}
127171
let category = args.typed(as: String.self, index: 1)
128172
let properties = args.typed(as: Dictionary.self, index: 2)
129-
analytics.screen(title: title, category: category, properties: properties, enrichments: [originMarkerEnrichment])
173+
let context = args.typed(as: Dictionary.self, index: 3)
174+
analytics
175+
.screen(
176+
title: title,
177+
category: category,
178+
properties: properties,
179+
enrichments: enrichments(with: context)
180+
)
130181
return nil
182+
131183
}
132184

133185
public func group(args: [JSConvertible?]) -> JSConvertible? {
134186
guard let analytics else { return nil }
135-
guard let groupId = args.typed(as: String.self, index: 0) else { return nil }
187+
guard let groupId = args.typed(as: String.self, index: 0) else {
188+
return nil
189+
}
136190
let traits = args.typed(as: Dictionary.self, index: 1)
137-
analytics.group(groupId: groupId, traits: traits, enrichments: [originMarkerEnrichment])
138-
return nil
139-
}
140-
141-
public func alias(args: [JSConvertible?]) -> JSConvertible? {
142-
guard let analytics else { return nil }
143-
guard let newId = args.typed(as: String.self, index: 0) else { return nil }
144-
analytics.alias(newId: newId, enrichments: [originMarkerEnrichment])
191+
let context = args.typed(as: Dictionary.self, index: 2)
192+
analytics
193+
.group(
194+
groupId: groupId,
195+
traits: traits,
196+
enrichments: enrichments(with: context)
197+
)
145198
return nil
199+
146200
}
147201

148202
public func flush(args: [JSConvertible?]) -> JSConvertible? {
149203
guard let analytics else { return nil }
150204
analytics.flush()
151205
return nil
206+
152207
}
153208

154209
public func reset(args: [JSConvertible?]) -> JSConvertible? {
155210
guard let analytics else { return nil }
156211
analytics.reset()
157212
return nil
213+
158214
}
159215

160216
public func add(args: [JSConvertible?]) -> JSConvertible? {
161-
var result = false
162-
163-
guard let analytics else { return result }
164-
guard let plugin = args.typed(as: JSClass.self, index: 0) else { return result }
217+
guard let analytics else { return nil }
218+
guard let plugin = args.typed(as: JSClass.self, index: 0) else {
219+
return false
220+
}
165221

166222
let type = plugin["type"]?.typed(as: Int.self)
167223
let destination = plugin["destination"]?.typed(as: String.self)
168224

169-
guard let type = type else { return result }
225+
guard let type = type else { return false }
226+
guard let pluginType = PluginType(rawValue: type) else { return false }
170227

171-
guard let pluginType = PluginType(rawValue: type) else { return result }
172228
let edgeFn = LivePlugin(jsPlugin: plugin, type: pluginType)
173229

174230
if let dest = destination {
175231
// we have a destination specified, so add it there
176-
if let d = analytics.find(key: dest) {
177-
DispatchQueue.main.async {
178-
_ = d.add(plugin: edgeFn)
179-
}
180-
result = true
181-
self.addedPlugins.append((dest, edgeFn))
182-
}
232+
guard let d = analytics.find(key: dest) else { return false }
233+
_ = d.add(plugin: edgeFn)
234+
return true
183235
} else {
184-
DispatchQueue.main.async {
185-
_ = analytics.add(plugin: edgeFn)
186-
}
187-
result = true
188-
self.addedPlugins.append((nil, edgeFn))
236+
_ = analytics.add(plugin: edgeFn)
237+
return true
189238
}
190-
return result
191-
}
192-
193-
public func removeLivePlugins(args: [JSConvertible?]) -> JSConvertible? {
194-
guard let analytics else { return nil }
195-
196-
for tuple in self.addedPlugins {
197-
let (dest, p) = tuple
198-
if let dst = dest {
199-
// Remove from destination
200-
if let d = analytics.find(key: dst) {
201-
d.remove(plugin: p)
202-
}
203-
} else {
204-
// Remove from main timeline
205-
analytics.remove(plugin: p)
206-
}
207-
}
208-
self.addedPlugins.removeAll()
209-
return nil
210239
}
211240
}

Sources/AnalyticsLive/Signals/AutoTracking/Networking/SignalsNetworkTracking.swift

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class SignalsNetworkProtocol: URLProtocol, URLSessionDataDelegate {
3838

3939
internal var session: URLSession? = nil
4040
internal var sessionTask: URLSessionDataTask? = nil
41+
internal let requestId: String = UUID().uuidString
4142
@Atomic internal var receivedData: Data? = nil
4243
@Atomic internal var response: URLResponse? = nil
4344

@@ -73,7 +74,18 @@ public class SignalsNetworkProtocol: URLProtocol, URLSessionDataDelegate {
7374
sessionTask?.resume()
7475

7576
// emit our request signal since it's about to go out.
76-
emit(action: .request)
77+
let contentType = newRequest.value(forHTTPHeaderField: "Content-Type")
78+
let data = NetworkSignal.NetworkData(
79+
action: .request,
80+
url: newRequest.url,
81+
body: deserialize(contentType: contentType, data: newRequest.httpBody),
82+
contentType: contentType,
83+
method: newRequest.httpMethod,
84+
status: nil,
85+
requestId: requestId
86+
)
87+
let signal = NetworkSignal(data: data)
88+
Signals.shared.emit(signal: signal, source: .autoNetwork)
7789
}
7890

7991
override public func stopLoading() {
@@ -104,7 +116,20 @@ public class SignalsNetworkProtocol: URLProtocol, URLSessionDataDelegate {
104116
}
105117

106118
client?.urlProtocolDidFinishLoading(self)
107-
emit(action: .response)
119+
120+
let httpResponse = self.response as? HTTPURLResponse
121+
let contentType = httpResponse?.value(forHTTPHeaderField: "Content-Type")
122+
let data = NetworkSignal.NetworkData(
123+
action: .response,
124+
url: request.url,
125+
body: deserialize(contentType: contentType, data: request.httpBody),
126+
contentType: contentType,
127+
method: request.httpMethod,
128+
status: httpResponse?.statusCode,
129+
requestId: requestId
130+
)
131+
let signal = NetworkSignal(data: data)
132+
Signals.shared.emit(signal: signal, source: .autoNetwork)
108133
}
109134

110135
}
@@ -137,7 +162,7 @@ extension SignalsNetworkProtocol {
137162
}
138163

139164
extension SignalsNetworkProtocol {
140-
func deserialize(contentType: String?) -> [String: Any]? {
165+
func deserialize(contentType: String?, data: Data?) -> [String: Any]? {
141166
guard let contentType else { return nil }
142167
let parts = contentType.components(separatedBy: ";")
143168
// strip any params off .. we can't really evaluate them that well
@@ -146,18 +171,6 @@ extension SignalsNetworkProtocol {
146171
let deserializer = Self.deserializers[ct] ?? Self.deserializers[contentType] ?? Self.textPlain
147172
return deserializer(receivedData)
148173
}
149-
150-
func emit(action: NetworkSignal.NetworkAction) {
151-
guard let url = request.url else { return }
152-
let httpResponse = self.response as? HTTPURLResponse
153-
let statusCode = httpResponse?.statusCode
154-
155-
let contentType = httpResponse?.value(forHTTPHeaderField: "Content-Type")
156-
let data = deserialize(contentType: contentType)
157-
158-
let s = NetworkSignal(action: action, url: url, statusCode: statusCode, data: data)
159-
Signals.shared.emit(signal: s, source: .autoNetwork)
160-
}
161174
}
162175

163176
final class SignalsAuthenticationChallengeSender: NSObject, URLAuthenticationChallengeSender {

0 commit comments

Comments
 (0)