Skip to content

Commit

Permalink
Merge pull request #628 from CRED-CLUB/feat/proxy_server_header_capab…
Browse files Browse the repository at this point in the history
…ility

feat: Proxy server header capability
  • Loading branch information
jaredmixpanel authored Apr 8, 2024
2 parents e84dcf7 + 68ea193 commit ec92bd9
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 30 deletions.
13 changes: 8 additions & 5 deletions Sources/Flush.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ class Flush: AppLifecycle {
flushIntervalReadWriteLock = DispatchQueue(label: "com.mixpanel.flush_interval.lock", qos: .utility, attributes: .concurrent, autoreleaseFrequency: .workItem)
}

func flushQueue(_ queue: Queue, type: FlushType) {
func flushQueue(_ queue: Queue, type: FlushType, headers: [String: String], queryItems: [URLQueryItem]) {
if flushRequest.requestNotAllowed() {
return
}
flushQueueInBatches(queue, type: type)
flushQueueInBatches(queue, type: type, headers: headers, queryItems: queryItems)
}

func startFlushTimer() {
Expand Down Expand Up @@ -95,7 +95,7 @@ class Flush: AppLifecycle {
}
}

func flushQueueInBatches(_ queue: Queue, type: FlushType) {
func flushQueueInBatches(_ queue: Queue, type: FlushType, headers: [String: String], queryItems: [URLQueryItem]) {
var mutableQueue = queue
while !mutableQueue.isEmpty {
let batchSize = min(mutableQueue.count, flushBatchSize)
Expand All @@ -115,8 +115,10 @@ class Flush: AppLifecycle {
}
#endif // os(iOS)
let success = flushRequest.sendRequest(requestData,
type: type,
useIP: useIPAddressForGeoLocation)
type: type,
useIP: useIPAddressForGeoLocation,
headers: headers,
queryItems: queryItems)
#if os(iOS)
if !MixpanelInstance.isiOSAppExtension() {
delegate?.updateNetworkActivityIndicator(false)
Expand Down Expand Up @@ -156,3 +158,4 @@ class Flush: AppLifecycle {
}

}

13 changes: 10 additions & 3 deletions Sources/FlushRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ class FlushRequest: Network {

func sendRequest(_ requestData: String,
type: FlushType,
useIP: Bool) -> Bool {
useIP: Bool,
headers: [String: String],
queryItems: [URLQueryItem] = []) -> Bool {

let responseParser: (Data) -> Int? = { data in
let response = String(data: data, encoding: String.Encoding.utf8)
Expand All @@ -31,12 +33,16 @@ class FlushRequest: Network {
return nil
}

let resourceHeaders: [String: String] = ["Content-Type": "application/json"].merging(headers) {(_,new) in new }

let ipString = useIP ? "1" : "0"
var resourceQueryItems: [URLQueryItem] = [URLQueryItem(name: "ip", value: ipString)]
resourceQueryItems.append(contentsOf: queryItems)
let resource = Network.buildResource(path: type.rawValue,
method: .post,
requestBody: requestData.data(using: .utf8),
queryItems: [URLQueryItem(name: "ip", value: ipString)],
headers: ["Content-Type": "application/json"],
queryItems: resourceQueryItems,
headers: resourceHeaders,
parse: responseParser)
var result = false
let semaphore = DispatchSemaphore(value: 0)
Expand Down Expand Up @@ -97,3 +103,4 @@ class FlushRequest: Network {
}

}

129 changes: 121 additions & 8 deletions Sources/Mixpanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,49 @@ open class Mixpanel {
superProperties: superProperties,
serverURL: serverURL)
}

/**
Initializes an instance of the API with the given project token.

Returns a new Mixpanel instance API object. This allows you to create more than one instance
of the API object, which is convenient if you'd like to send data to more than
one Mixpanel project from a single app.

- parameter token: your project token
- parameter trackAutomaticEvents: Whether or not to collect common mobile events
- parameter flushInterval: Optional. Interval to run background flushing
- parameter instanceName: Optional. The name you want to uniquely identify the Mixpanel Instance.
It is useful when you want more than one Mixpanel instance under the same project token.
- parameter optOutTrackingByDefault: Optional. Whether or not to be opted out from tracking by default
- parameter useUniqueDistinctId: Optional. whether or not to use the unique device identifier as the distinct_id
- parameter superProperties: Optional. Super properties dictionary to register during initialization
- parameter proxyServerConfig: Optional. Setup for proxy server.

- important: If you have more than one Mixpanel instance, it is beneficial to initialize
the instances with an instanceName. Then they can be reached by calling getInstance with name.

- returns: returns a mixpanel instance if needed to keep throughout the project.
You can always get the instance by calling getInstance(name)
*/

@discardableResult
open class func initialize(token apiToken: String,
trackAutomaticEvents: Bool,
flushInterval: Double = 60,
instanceName: String? = nil,
optOutTrackingByDefault: Bool = false,
useUniqueDistinctId: Bool = false,
superProperties: Properties? = nil,
proxyServerConfig: ProxyServerConfig) -> MixpanelInstance {
return MixpanelManager.sharedInstance.initialize(token: apiToken,
flushInterval: flushInterval,
instanceName: ((instanceName != nil) ? instanceName! : apiToken),
trackAutomaticEvents: trackAutomaticEvents,
optOutTrackingByDefault: optOutTrackingByDefault,
useUniqueDistinctId: useUniqueDistinctId,
superProperties: superProperties,
proxyServerConfig: proxyServerConfig)
}
#else
/**
Initializes an instance of the API with the given project token (MAC OS ONLY).
Expand Down Expand Up @@ -97,6 +140,47 @@ open class Mixpanel {
superProperties: superProperties,
serverURL: serverURL)
}

/**
Initializes an instance of the API with the given project token (MAC OS ONLY).

Returns a new Mixpanel instance API object. This allows you to create more than one instance
of the API object, which is convenient if you'd like to send data to more than
one Mixpanel project from a single app.

- parameter token: your project token
- parameter flushInterval: Optional. Interval to run background flushing
- parameter instanceName: Optional. The name you want to uniquely identify the Mixpanel Instance.
It is useful when you want more than one Mixpanel instance under the same project token.
- parameter optOutTrackingByDefault: Optional. Whether or not to be opted out from tracking by default
- parameter useUniqueDistinctId: Optional. whether or not to use the unique device identifier as the distinct_id
- parameter superProperties: Optional. Super properties dictionary to register during initialization
- parameter proxyServerConfig: Optional. Setup for proxy server.

- important: If you have more than one Mixpanel instance, it is beneficial to initialize
the instances with an instanceName. Then they can be reached by calling getInstance with name.

- returns: returns a mixpanel instance if needed to keep throughout the project.
You can always get the instance by calling getInstance(name)
*/

@discardableResult
open class func initialize(token apiToken: String,
flushInterval: Double = 60,
instanceName: String? = nil,
optOutTrackingByDefault: Bool = false,
useUniqueDistinctId: Bool = false,
superProperties: Properties? = nil,
proxyServerConfig: ProxyServerConfig) -> MixpanelInstance {
return MixpanelManager.sharedInstance.initialize(token: apiToken,
flushInterval: flushInterval,
instanceName: ((instanceName != nil) ? instanceName! : apiToken),
trackAutomaticEvents: false,
optOutTrackingByDefault: optOutTrackingByDefault,
useUniqueDistinctId: useUniqueDistinctId,
superProperties: superProperties,
proxyServerConfig: proxyServerConfig)
}
#endif // os(OSX)

/**
Expand Down Expand Up @@ -178,20 +262,48 @@ final class MixpanelManager {
superProperties: Properties? = nil,
serverURL: String? = nil
) -> MixpanelInstance {
return dequeueInstance(instanceName: instanceName) {
return MixpanelInstance(apiToken: apiToken,
flushInterval: flushInterval,
name: instanceName,
trackAutomaticEvents: trackAutomaticEvents,
optOutTrackingByDefault: optOutTrackingByDefault,
useUniqueDistinctId: useUniqueDistinctId,
superProperties: superProperties,
serverURL: serverURL)
}
}

func initialize(token apiToken: String,
flushInterval: Double,
instanceName: String,
trackAutomaticEvents: Bool,
optOutTrackingByDefault: Bool = false,
useUniqueDistinctId: Bool = false,
superProperties: Properties? = nil,
proxyServerConfig: ProxyServerConfig
) -> MixpanelInstance {
return dequeueInstance(instanceName: instanceName) {
return MixpanelInstance(apiToken: apiToken,
flushInterval: flushInterval,
name: instanceName,
trackAutomaticEvents: trackAutomaticEvents,
optOutTrackingByDefault: optOutTrackingByDefault,
useUniqueDistinctId: useUniqueDistinctId,
superProperties: superProperties,
proxyServerConfig: proxyServerConfig)
}
}

private func dequeueInstance(instanceName: String, instanceCreation: () -> MixpanelInstance) -> MixpanelInstance {
instanceQueue.sync {
var instance: MixpanelInstance?
if let instance = instances[instanceName] {
mainInstance = instance
return
}
instance = MixpanelInstance(apiToken: apiToken,
flushInterval: flushInterval,
name: instanceName,
trackAutomaticEvents: trackAutomaticEvents,
optOutTrackingByDefault: optOutTrackingByDefault,
useUniqueDistinctId: useUniqueDistinctId,
superProperties: superProperties,
serverURL: serverURL)

instance = instanceCreation()
readWriteLock.write {
instances[instanceName] = instance!
mainInstance = instance!
Expand Down Expand Up @@ -245,3 +357,4 @@ final class MixpanelManager {
}

}

Loading

0 comments on commit ec92bd9

Please sign in to comment.