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

feat: persistent storage, httpclient, eventpipeline #9

Merged
merged 7 commits into from
Dec 2, 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
9 changes: 9 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
disabled_rules:
- function_body_length
- type_body_length
- trailing_comma
- opening_brace
- todo
identifier_name:
allowed_symbols: "_"
min_length: 1
cyclomatic_complexity: 25
nesting:
type_level:
warning: 3
error: 6
function_level:
warning: 5
error: 10
91 changes: 91 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/Amplitude-Swift.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1410"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Amplitude-Swift"
BuildableName = "Amplitude-Swift"
BlueprintName = "Amplitude-Swift"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Amplitude-SwiftTests"
BuildableName = "Amplitude-SwiftTests"
BlueprintName = "Amplitude-SwiftTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Amplitude-SwiftTests"
BuildableName = "Amplitude-SwiftTests"
BlueprintName = "Amplitude-SwiftTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Amplitude-Swift"
BuildableName = "Amplitude-Swift"
BlueprintName = "Amplitude-Swift"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
10 changes: 5 additions & 5 deletions Sources/Amplitude/Amplitude.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ public class Amplitude {
var instanceName: String
internal var inForeground = false

lazy var storage: Storage = {
lazy var storage: any Storage = {
return self.configuration.storageProvider
}()
lazy var timeline: Timeline = {
return Timeline()
}()
lazy var logger: any Logger = {
lazy var logger: (any Logger)? = {
return self.configuration.loggerProvider
}()

Expand Down Expand Up @@ -108,7 +108,7 @@ public class Amplitude {
return self
}

func onEnterForeground(timestamp: Double) {
func onEnterForeground(timestamp: Int64) {
inForeground = true

let dummySessionStartEvent = BaseEvent(eventType: "session_start")
Expand All @@ -131,10 +131,10 @@ public class Amplitude {

private func process(event: BaseEvent) {
if configuration.optOut {
logger.log(message: "Skip event based on opt out configuration")
logger?.log(message: "Skip event based on opt out configuration")
return
}
event.timestamp = event.timestamp ?? NSDate().timeIntervalSince1970
event.timestamp = event.timestamp ?? Int64(NSDate().timeIntervalSince1970 * 1000)
timeline.process(event: event)
}
}
6 changes: 3 additions & 3 deletions Sources/Amplitude/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Configuration {
var flushIntervalMillis: Int
var instanceName: String
var optOut: Bool
var storageProvider: Storage
var storageProvider: any Storage
var logLevel: LogLevelEnum
var loggerProvider: any Logger
var minIdLength: Int?
Expand All @@ -38,7 +38,7 @@ public class Configuration {
flushIntervalMillis: Int = Constants.Configuration.FLUSH_INTERVAL_MILLIS,
instanceName: String = Constants.Configuration.DEFAULT_INSTANCE,
optOut: Bool = false,
storageProvider: Storage = PersistentStorage(),
storageProvider: (any Storage)? = nil,
logLevel: LogLevelEnum = LogLevelEnum.WARN,
loggerProvider: any Logger = ConsoleLogger(),
minIdLength: Int? = nil,
Expand All @@ -63,7 +63,7 @@ public class Configuration {
self.flushIntervalMillis = flushIntervalMillis
self.instanceName = instanceName
self.optOut = optOut
self.storageProvider = storageProvider
self.storageProvider = storageProvider ?? PersistentStorage(apiKey: apiKey)
self.logLevel = logLevel
self.loggerProvider = loggerProvider
self.minIdLength = minIdLength
Expand Down
3 changes: 1 addition & 2 deletions Sources/Amplitude/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ public struct Constants {
static let MIN_TIME_BETWEEN_SESSIONS_MILLIS = 300000
}

struct Storage {
static let STORAGE_PREFIX = "amplitude-swift"
public struct Storage {
}
}
153 changes: 149 additions & 4 deletions Sources/Amplitude/Events/BaseEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,61 @@

import Foundation

public class BaseEvent: EventOptions {
public class BaseEvent: EventOptions, Codable {
public var eventType: String
public var eventProperties: [String: Any]?
public var userProperties: [String: Any]?
public var groups: [String: Any]?
public var groupProperties: [String: Any]?

enum CodingKeys: String, CodingKey {
case eventType = "event_type"
case eventProperties = "event_properties"
case userProperties = "user_properties"
case groups
case groupProperties = "group_properties"
case userId = "user_id"
case deviceId = "device_id"
case timestamp = "time"
case eventId = "event_id"
case sessionId = "session_id"
case locationLat = "location_lat"
case locationLng = "location_lng"
case appVersion = "app_version"
case versionName = "version_name"
case platform
case osName = "os_name"
case osVersion = "os_version"
case deviceBrand = "device_brand"
case deviceManufacturer = "device_manufacturer"
case deviceModel = "device_model"
case carrier
case country
case region
case city
case dma
case idfa
case idfv
case adid
case language
case library
case ip
case plan
case ingestionMetadata = "ingestion_metadata"
case revenue
case price
case quantity
case productId = "product_id"
case revenueType = "revenue_type"
case partnerId = "partner_id"
}

init(
userId: String? = nil,
deviceId: String? = nil,
timestamp: Double? = nil,
eventId: Double? = nil,
sessionId: Double? = -1,
timestamp: Int64? = nil,
eventId: Int64? = nil,
sessionId: Int64? = -1,
insertId: String? = nil,
locationLat: Double? = nil,
locationLng: Double? = nil,
Expand Down Expand Up @@ -147,4 +189,107 @@ public class BaseEvent: EventOptions {
func isValid() -> Bool {
return userId != nil || deviceId != nil
}

required public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
eventType = try values.decode(String.self, forKey: .eventType)
eventProperties = try values.decode([String: Any].self, forKey: .eventProperties)
userProperties = try values.decode([String: Any].self, forKey: .userProperties)
groups = try values.decode([String: Any].self, forKey: .groups)
groupProperties = try values.decode([String: Any].self, forKey: .groupProperties)
super.init()
userId = try values.decode(String.self, forKey: .userId)
deviceId = try values.decode(String.self, forKey: .deviceId)
timestamp = try values.decode(Int64.self, forKey: .timestamp)
eventId = try values.decode(Int64.self, forKey: .eventId)
sessionId = try values.decode(Int64.self, forKey: .sessionId)
locationLat = try values.decode(Double.self, forKey: .locationLat)
locationLng = try values.decode(Double.self, forKey: .locationLng)
appVersion = try values.decode(String.self, forKey: .appVersion)
versionName = try values.decode(String.self, forKey: .versionName)
platform = try values.decode(String.self, forKey: .platform)
osName = try values.decode(String.self, forKey: .osName)
osVersion = try values.decode(String.self, forKey: .osVersion)
deviceBrand = try values.decode(String.self, forKey: .deviceBrand)
deviceManufacturer = try values.decode(String.self, forKey: .deviceManufacturer)
deviceModel = try values.decode(String.self, forKey: .deviceModel)
carrier = try values.decode(String.self, forKey: .carrier)
country = try values.decode(String.self, forKey: .country)
region = try values.decode(String.self, forKey: .region)
city = try values.decode(String.self, forKey: .city)
dma = try values.decode(String.self, forKey: .dma)
idfa = try values.decode(String.self, forKey: .idfa)
idfv = try values.decode(String.self, forKey: .idfv)
adid = try values.decode(String.self, forKey: .adid)
language = try values.decode(String.self, forKey: .language)
library = try values.decode(String.self, forKey: .library)
ip = try values.decode(String.self, forKey: .ip)
plan = try values.decode(Plan.self, forKey: .plan)
ingestionMetadata = try values.decode(IngestionMetadata.self, forKey: .ingestionMetadata)
revenue = try values.decode(Double.self, forKey: .revenue)
price = try values.decode(Double.self, forKey: .price)
quantity = try values.decode(Int.self, forKey: .quantity)
productId = try values.decode(String.self, forKey: .productId)
revenueType = try values.decode(String.self, forKey: .revenueType)
partnerId = try values.decode(String.self, forKey: .partnerId)
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(eventType, forKey: .eventType)
try container.encodeIfPresent(eventProperties, forKey: .eventProperties)
try container.encodeIfPresent(userProperties, forKey: .userProperties)
try container.encodeIfPresent(groups, forKey: .groups)
try container.encodeIfPresent(groupProperties, forKey: .groupProperties)
try container.encode(userId, forKey: .userId)
try container.encode(deviceId, forKey: .deviceId)
try container.encode(timestamp, forKey: .timestamp)
try container.encode(eventId, forKey: .eventId)
try container.encode(sessionId, forKey: .sessionId)
try container.encode(locationLat, forKey: .locationLat)
try container.encode(locationLng, forKey: .locationLng)
try container.encode(appVersion, forKey: .appVersion)
try container.encode(versionName, forKey: .versionName)
try container.encode(platform, forKey: .platform)
try container.encode(osName, forKey: .osName)
try container.encode(osVersion, forKey: .osVersion)
try container.encode(deviceBrand, forKey: .deviceBrand)
try container.encode(deviceManufacturer, forKey: .deviceManufacturer)
try container.encode(deviceModel, forKey: .deviceModel)
try container.encode(carrier, forKey: .carrier)
try container.encode(country, forKey: .country)
try container.encode(region, forKey: .region)
try container.encode(city, forKey: .city)
try container.encode(dma, forKey: .dma)
try container.encode(idfa, forKey: .idfa)
try container.encode(idfv, forKey: .idfv)
try container.encode(adid, forKey: .adid)
try container.encode(language, forKey: .language)
try container.encode(library, forKey: .library)
try container.encode(ip, forKey: .ip)
try container.encodeIfPresent(plan, forKey: .plan)
try container.encodeIfPresent(ingestionMetadata, forKey: .ingestionMetadata)
try container.encode(revenue, forKey: .revenue)
try container.encode(price, forKey: .price)
try container.encode(quantity, forKey: .quantity)
try container.encode(productId, forKey: .productId)
try container.encode(revenueType, forKey: .revenueType)
try container.encode(partnerId, forKey: .partnerId)
}
}

extension BaseEvent {
func toString() -> String {
var returnString = ""
do {
let encoder = JSONEncoder()
let json = try encoder.encode(self)
if let printed = String(data: json, encoding: .utf8) {
returnString = printed
}
} catch {
returnString = error.localizedDescription
}
return returnString
}
}
14 changes: 7 additions & 7 deletions Sources/Amplitude/Events/EventOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import Foundation
public class EventOptions {
var userId: String?
var deviceId: String?
var timestamp: Double?
var eventId: Double?
var sessionId: Double? = -1
var timestamp: Int64?
var eventId: Int64?
var sessionId: Int64? = -1
var insertId: String?
var locationLat: Double?
var locationLng: Double?
Expand Down Expand Up @@ -45,14 +45,14 @@ public class EventOptions {
var extra: [String: Any]?
var callback: EventCallBack?
var partnerId: String?
private var attempts: Int
internal var attempts: Int

init(
userId: String? = nil,
deviceId: String? = nil,
timestamp: Double? = nil,
eventId: Double? = nil,
sessionId: Double? = -1,
timestamp: Int64? = nil,
eventId: Int64? = nil,
sessionId: Int64? = -1,
insertId: String? = nil,
locationLat: Double? = nil,
locationLng: Double? = nil,
Expand Down
Loading