Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
44 changes: 19 additions & 25 deletions Sources/Segment/Plugins.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ public enum PluginType: Int, CaseIterable {

public protocol Plugin: AnyObject {
var type: PluginType { get }
var name: String { get }
var analytics: Analytics? { get set }

init(name: String)
func configure(analytics: Analytics)
func update(settings: Settings)
func execute<T: RawEvent>(event: T?) -> T?
Expand All @@ -46,24 +44,18 @@ public protocol EventPlugin: Plugin {
}

public protocol DestinationPlugin: EventPlugin {
var key: String { get }
var timeline: Timeline { get }
func add(plugin: Plugin) -> String
func add(plugin: Plugin) -> Plugin
func apply(closure: (Plugin) -> Void)
func remove(pluginName: String)
func remove(plugin: Plugin)
}

public protocol UtilityPlugin: EventPlugin { }

// For internal platform-specific bits
internal protocol PlatformPlugin: Plugin {
static var specificName: String { get set }
}
internal protocol PlatformPlugin: Plugin { }

extension PlatformPlugin {
internal init() {
self.init(name: Self.specificName)
}
}

// MARK: - Plugin instance helpers
extension Plugin {
Expand Down Expand Up @@ -101,21 +93,21 @@ extension DestinationPlugin {

*/
@discardableResult
public func add(plugin: Plugin) -> String {
public func add(plugin: Plugin) -> Plugin {
if let analytics = self.analytics {
plugin.configure(analytics: analytics)
}
timeline.add(plugin: plugin)
return plugin.name
return plugin
}

/**
Removes and unloads plugins with a matching name from the system.

- Parameter pluginName: An plugin name.
*/
public func remove(pluginName: String) {
timeline.remove(pluginName: pluginName)
public func remove(plugin: Plugin) {
timeline.remove(plugin: plugin)
}

}
Expand All @@ -140,28 +132,30 @@ extension Analytics {

*/
@discardableResult
public func add(plugin: Plugin) -> String {
public func add(plugin: Plugin) -> Plugin {
plugin.configure(analytics: self)
timeline.add(plugin: plugin)
if plugin is DestinationPlugin && !(plugin is SegmentDestination) {
if !(plugin is SegmentDestination), let destPlugin = plugin as? DestinationPlugin {
// need to maintain the list of integrations to inject into payload
store.dispatch(action: System.AddIntegrationAction(pluginName: plugin.name))
store.dispatch(action: System.AddIntegrationAction(key: destPlugin.key))
}

return plugin.name
return plugin
}

/**
Removes and unloads plugins with a matching name from the system.

- Parameter pluginName: An plugin name.
*/
public func remove(pluginName: String) {
timeline.remove(pluginName: pluginName)
store.dispatch(action: System.RemoveIntegrationAction(pluginName: pluginName))
public func remove(plugin: Plugin) {
timeline.remove(plugin: plugin)
if !(plugin is SegmentDestination), let destPlugin = plugin as? DestinationPlugin {
store.dispatch(action: System.RemoveIntegrationAction(key: destPlugin.key))
}
}

public func find(pluginName: String) -> Plugin? {
return timeline.find(pluginName: pluginName)
public func find<T: Plugin>(pluginType: T.Type) -> T? {
return timeline.find(pluginType: pluginType)
}
}
7 changes: 0 additions & 7 deletions Sources/Segment/Plugins/Context.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,12 @@
import Foundation

public class Context: PlatformPlugin {
static var specificName: String = "Segment_Context"

public let type: PluginType = .before
public let name: String = specificName
public var analytics: Analytics?

internal var staticContext = staticContextData()
internal static var device = VendorSystem.current

public required init(name: String) {
// ignore name here; it's hardcoded above.
}

public func execute<T: RawEvent>(event: T?) -> T? {
guard var workingEvent = event else { return event }

Expand Down
13 changes: 4 additions & 9 deletions Sources/Segment/Plugins/DeviceToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@
import Foundation

public class DeviceToken: PlatformPlugin {
static var specificName = "Segment_DeviceToken"

public let type: PluginType = .before
public let name: String = specificName
public let type = PluginType.before
public var analytics: Analytics?

public var token: String? = nil

public required init(name: String) {
// ignore `name` here, it's hard coded above.
}
public required init() { }

public func execute<T: RawEvent>(event: T?) -> T? {
guard var workingEvent = event else { return event }
Expand All @@ -36,10 +31,10 @@ public class DeviceToken: PlatformPlugin {

extension Analytics {
public func setDeviceToken(_ token: String) {
if let tokenPlugin = self.find(pluginName: DeviceToken.specificName) as? DeviceToken {
if let tokenPlugin = self.find(pluginType: DeviceToken.self) {
tokenPlugin.token = token
} else {
let tokenPlugin = DeviceToken(name: DeviceToken.specificName)
let tokenPlugin = DeviceToken()
tokenPlugin.token = token
add(plugin: tokenPlugin)
}
Expand Down
11 changes: 3 additions & 8 deletions Sources/Segment/Plugins/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,14 @@ public enum LogType: Int {
}

class Logger: UtilityPlugin {
public var filterType = LogType.info

public var filterType: LogType = .info

let type: PluginType
let name: String
let type = PluginType.utility
var analytics: Analytics?

private var messages = [LogMessage]()

required init(name: String) {
self.name = name
self.type = .utility
}
required init() { }

func log(type: LogType, message: String, event: RawEvent?) {
print("\(type) -- Message: \(message)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class macOSLifecycleMonitor: PlatformPlugin {
NSApplication.willTerminateNotification,
NSApplication.didChangeScreenParametersNotification]

required init(name: String) {
required init() {
self.application = NSApplication.shared
setupListeners()
}
Expand Down
22 changes: 9 additions & 13 deletions Sources/Segment/Plugins/SegmentDestination.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ import FoundationNetworking
#endif

public class SegmentDestination: DestinationPlugin {
public let type: PluginType = .destination
public let name: String
internal enum Constants: String {
case integrationName = "Segment.io"
case apiHost = "apiHost"
case apiKey = "apiKey"
}

public let type = PluginType.destination
public let key: String = Constants.integrationName.rawValue
public let timeline = Timeline()
public var analytics: Analytics? {
didSet {
Expand All @@ -44,16 +50,6 @@ public class SegmentDestination: DestinationPlugin {
@Atomic private var eventCount: Int = 0
internal var flushTimer: QueueTimer? = nil

internal enum Constants: String {
case integrationName = "Segment.io"
case apiHost = "apiHost"
case apiKey = "apiKey"
}

required public init(name: String) {
self.name = name
}

internal func initialSetup() {
guard let analytics = self.analytics else { return }
storage = analytics.storage
Expand All @@ -64,7 +60,7 @@ public class SegmentDestination: DestinationPlugin {
}

public func update(settings: Settings) {
let segmentInfo = settings.integrationSettings(for: Self.Constants.integrationName.rawValue)
let segmentInfo = settings.integrationSettings(forKey: self.key)
apiKey = segmentInfo?[Self.Constants.apiKey.rawValue] as? String
apiHost = segmentInfo?[Self.Constants.apiHost.rawValue] as? String
if (apiHost != nil && apiKey != nil), let analytics = self.analytics {
Expand Down
7 changes: 2 additions & 5 deletions Sources/Segment/Plugins/StartupQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import Foundation
import Sovran

internal class StartupQueue: Plugin, Subscriber {
static var specificName = "Segment_StartupQueue"
static let maxSize = 1000

@Atomic var running: Bool = false

let type: PluginType = .before
let name: String = specificName

var analytics: Analytics? = nil {
didSet {
analytics?.store.subscribe(self, handler: runningUpdate)
Expand All @@ -24,9 +23,7 @@ internal class StartupQueue: Plugin, Subscriber {

var queuedEvents = [RawEvent]()

required init(name: String) {
// ignore name; hardcoded above.
}
required init() { }

func execute<T: RawEvent>(event: T?) -> T? {
if running == false, let e = event {
Expand Down
18 changes: 14 additions & 4 deletions Sources/Segment/Settings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,30 @@ public struct Settings: Codable {
* - Parameter for: The string name of the integration
* - Returns: The dictionary representing the settings for this integration as supplied by Segment.com
*/
public func integrationSettings(for name: String) -> [String: Any]? {
public func integrationSettings(forKey key: String) -> [String: Any]? {
guard let settings = integrations?.dictionaryValue else { return nil }
let result = settings[name] as? [String: Any]
let result = settings[key] as? [String: Any]
return result
}

public func integrationSettings<T: Codable>(name: String) -> T? {
public func integrationSettings<T: Codable>(forKey key: String) -> T? {
var result: T? = nil
guard let settings = integrations?.dictionaryValue else { return nil }
if let dict = settings[name], let jsonData = try? JSONSerialization.data(withJSONObject: dict) {
if let dict = settings[key], let jsonData = try? JSONSerialization.data(withJSONObject: dict) {
result = try? JSONDecoder().decode(T.self, from: jsonData)
}
return result
}

public func integrationSettings<T: Codable>(forPlugin plugin: DestinationPlugin) -> T? {
return integrationSettings(forKey: plugin.key)
}

/*
public func isDestinationEnabled(name: String) -> Bool {
return false
}
*/
}

extension Settings: Equatable {
Expand Down
19 changes: 9 additions & 10 deletions Sources/Segment/Startup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,20 @@ import Sovran
extension Analytics: Subscriber {

internal func platformStartup() {
add(plugin: StartupQueue(name: StartupQueue.specificName))
add(plugin: StartupQueue())

// add segment destination plugin unless
// asked not to via configuration.
if configuration.values.autoAddSegmentDestination {
let segmentDestination = SegmentDestination(name: "Segment.io")
let segmentDestination = SegmentDestination()
segmentDestination.analytics = self
add(plugin: segmentDestination)
}

// Setup platform specific plugins
if let platformPlugins = platformPlugins() {
for pluginType in platformPlugins {
let prebuilt = pluginType.init()
add(plugin: prebuilt)
for plugin in platformPlugins {
add(plugin: plugin)
}
}

Expand All @@ -35,23 +34,23 @@ extension Analytics: Subscriber {
setupSettingsCheck()
}

internal func platformPlugins() -> [PlatformPlugin.Type]? {
var plugins = [PlatformPlugin.Type]()
internal func platformPlugins() -> [PlatformPlugin]? {
var plugins = [PlatformPlugin]()

// setup lifecycle if desired
if configuration.values.trackApplicationLifecycleEvents {
// add context plugin as well as it's platform specific internally.
// this must come first.
plugins.append(Context.self)
plugins.append(Context())

#if os(iOS) || os(tvOS)
plugins += [iOSLifecycleMonitor.self, iOSLifecycleEvents.self, DeviceToken.self]
plugins += [iOSLifecycleMonitor(), iOSLifecycleEvents(), DeviceToken()]
#endif
#if os(watchOS)
plugins += [watchOSLifecycleMonitor.self, watchOSLifecycleEvents.self]
#endif
#if os(macOS)
plugins += [macOSLifecycleMonitor.self, DeviceToken.self]
plugins += [macOSLifecycleMonitor(), DeviceToken()]
#endif
#if os(Linux)
plugins.append(LinuxLifecycleMonitor.self)
Expand Down
8 changes: 4 additions & 4 deletions Sources/Segment/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ struct System: State {
}

struct AddIntegrationAction: Action {
let pluginName: String
let key: String

func reduce(state: System) -> System {
// we need to set any destination plugins to false in the
// integrations payload. this prevents them from being sent
// by segment.com once an event reaches segment.
if var integrations = state.integrations?.dictionaryValue {
integrations[pluginName] = false
integrations[key] = false
if let jsonIntegrations = try? JSON(integrations) {
let result = System(configuration: state.configuration,
integrations: jsonIntegrations,
Expand All @@ -50,11 +50,11 @@ struct System: State {
}

struct RemoveIntegrationAction: Action {
let pluginName: String
let key: String

func reduce(state: System) -> System {
if var integrations = state.integrations?.dictionaryValue {
integrations.removeValue(forKey: pluginName)
integrations.removeValue(forKey: key)
if let jsonIntegrations = try? JSON(integrations) {
let result = System(configuration: state.configuration,
integrations: jsonIntegrations,
Expand Down
Loading