Skip to content
Draft
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
36 changes: 36 additions & 0 deletions RudderStackAnalytics.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@
53DEA68F2E03D06F00D6C371 /* group_with_all_values.json in Resources */ = {isa = PBXBuildFile; fileRef = 53DEA62D2E03D06F00D6C371 /* group_with_all_values.json */; };
53DEA6902E03D06F00D6C371 /* screen_with_default_arguments.json in Resources */ = {isa = PBXBuildFile; fileRef = 53DEA6392E03D06F00D6C371 /* screen_with_default_arguments.json */; };
53E112DA2E7C4B9E005FEF67 /* Connectivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E112D92E7C4B9E005FEF67 /* Connectivity.swift */; };
859CEE102E9CC58C00519C90 /* DestinationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859CEE0F2E9CC58C00519C90 /* DestinationResult.swift */; };
859CEE122E9CDDE900519C90 /* MockIntegrationPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859CEE112E9CDDE900519C90 /* MockIntegrationPlugin.swift */; };
859CEE142E9CDE5700519C90 /* IntegrationPluginStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859CEE132E9CDE5700519C90 /* IntegrationPluginStoreTests.swift */; };
859CEE162E9CDE9B00519C90 /* IntegrationPluginTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859CEE152E9CDE9B00519C90 /* IntegrationPluginTests.swift */; };
85E7C4EE2E9BB53200520FDB /* IntegrationPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E7C4ED2E9BB53200520FDB /* IntegrationPlugin.swift */; };
85E7C4F02E9BB6A000520FDB /* IntegrationsManagementPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E7C4EF2E9BB6A000520FDB /* IntegrationsManagementPlugin.swift */; };
85E7C4F22E9BB95100520FDB /* IntegrationPluginStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85E7C4F12E9BB95100520FDB /* IntegrationPluginStore.swift */; };
8CCA98822E8178D0006C3537 /* HttpClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CCA98812E8178D0006C3537 /* HttpClientTests.swift */; };
8CCA98852E817966006C3537 /* EventUploaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CCA98842E817966006C3537 /* EventUploaderTests.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -321,6 +328,13 @@
53DEA65C2E03D06F00D6C371 /* LoggerAnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggerAnalyticsTests.swift; sourceTree = "<group>"; };
53DEA65D2E03D06F00D6C371 /* StorageModuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageModuleTests.swift; sourceTree = "<group>"; };
53E112D92E7C4B9E005FEF67 /* Connectivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Connectivity.swift; sourceTree = "<group>"; };
859CEE0F2E9CC58C00519C90 /* DestinationResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DestinationResult.swift; sourceTree = "<group>"; };
859CEE112E9CDDE900519C90 /* MockIntegrationPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockIntegrationPlugin.swift; sourceTree = "<group>"; };
859CEE132E9CDE5700519C90 /* IntegrationPluginStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationPluginStoreTests.swift; sourceTree = "<group>"; };
859CEE152E9CDE9B00519C90 /* IntegrationPluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationPluginTests.swift; sourceTree = "<group>"; };
85E7C4ED2E9BB53200520FDB /* IntegrationPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationPlugin.swift; sourceTree = "<group>"; };
85E7C4EF2E9BB6A000520FDB /* IntegrationsManagementPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationsManagementPlugin.swift; sourceTree = "<group>"; };
85E7C4F12E9BB95100520FDB /* IntegrationPluginStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationPluginStore.swift; sourceTree = "<group>"; };
8CCA98812E8178D0006C3537 /* HttpClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpClientTests.swift; sourceTree = "<group>"; };
8CCA98842E817966006C3537 /* EventUploaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventUploaderTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -495,6 +509,7 @@
children = (
539D87342E5888C7009FC144 /* MockURLProtocol.swift */,
53DEA6422E03D06F00D6C371 /* MockProvider.swift */,
859CEE112E9CDDE900519C90 /* MockIntegrationPlugin.swift */,
);
path = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -618,6 +633,7 @@
53DEA5C42E03D05A00D6C371 /* Plugins */ = {
isa = PBXGroup;
children = (
85E7C4EC2E9BB51D00520FDB /* DeviceMode */,
53DEA5B82E03D05A00D6C371 /* Base */,
53DEA5B92E03D05A00D6C371 /* AppInfoPlugin.swift */,
53DEA5BA2E03D05A00D6C371 /* DeviceInfoPlugin.swift */,
Expand Down Expand Up @@ -804,6 +820,8 @@
53DEA64B2E03D06F00D6C371 /* ScreenInfoPluginTests.swift */,
53DEA64C2E03D06F00D6C371 /* SessionTrackingPluginTests.swift */,
53DEA64D2E03D06F00D6C371 /* TimeZoneInfoPluginTests.swift */,
859CEE132E9CDE5700519C90 /* IntegrationPluginStoreTests.swift */,
859CEE152E9CDE9B00519C90 /* IntegrationPluginTests.swift */,
);
path = PluginTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -838,6 +856,17 @@
path = Tests;
sourceTree = "<group>";
};
85E7C4EC2E9BB51D00520FDB /* DeviceMode */ = {
isa = PBXGroup;
children = (
85E7C4ED2E9BB53200520FDB /* IntegrationPlugin.swift */,
85E7C4EF2E9BB6A000520FDB /* IntegrationsManagementPlugin.swift */,
85E7C4F12E9BB95100520FDB /* IntegrationPluginStore.swift */,
859CEE0F2E9CC58C00519C90 /* DestinationResult.swift */,
);
path = DeviceMode;
sourceTree = "<group>";
};
8CCA98802E817881006C3537 /* Network */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1017,8 +1046,10 @@
53DEA5E92E03D05A00D6C371 /* DataStore.swift in Sources */,
53E112DA2E7C4B9E005FEF67 /* Connectivity.swift in Sources */,
53DEA5EA2E03D05A00D6C371 /* TrackEvent.swift in Sources */,
85E7C4F02E9BB6A000520FDB /* IntegrationsManagementPlugin.swift in Sources */,
53DEA5EB2E03D05A00D6C371 /* RudderOption.swift in Sources */,
538F82C72E79583900C7ECEB /* UpdateSourceConfigAction.swift in Sources */,
859CEE102E9CC58C00519C90 /* DestinationResult.swift in Sources */,
53DEA5EC2E03D05A00D6C371 /* HttpNetwork.swift in Sources */,
53DEA5ED2E03D05A00D6C371 /* ObjCAnalytics.swift in Sources */,
53DEA5EE2E03D05A00D6C371 /* SessionActions.swift in Sources */,
Expand Down Expand Up @@ -1085,9 +1116,11 @@
53DEA61C2E03D05A00D6C371 /* FrequencyFlushPolicy.swift in Sources */,
530939D32E78299100E22EE1 /* SourceConfigProvider.swift in Sources */,
539D87202E55B8DD009FC144 /* ProcessingEvent.swift in Sources */,
85E7C4F22E9BB95100520FDB /* IntegrationPluginStore.swift in Sources */,
53DEA61D2E03D05A00D6C371 /* Plugin.swift in Sources */,
53DEA61E2E03D05A00D6C371 /* ObjCLoggerAnalytics.swift in Sources */,
53DEA61F2E03D05A00D6C371 /* GroupEvent.swift in Sources */,
85E7C4EE2E9BB53200520FDB /* IntegrationPlugin.swift in Sources */,
53DEA6202E03D05A00D6C371 /* LifecycleTrackingPlugin.swift in Sources */,
5328B8812E3C939D0051A202 /* ObjCAliasEvent.swift in Sources */,
);
Expand All @@ -1108,6 +1141,7 @@
8CCA98822E8178D0006C3537 /* HttpClientTests.swift in Sources */,
53DEA6662E03D06F00D6C371 /* GroupEventTests.swift in Sources */,
53DEA6672E03D06F00D6C371 /* UserIdActionTests.swift in Sources */,
859CEE122E9CDDE900519C90 /* MockIntegrationPlugin.swift in Sources */,
53DEA6682E03D06F00D6C371 /* FlushPolicyModuleTests.swift in Sources */,
8CCA98852E817966006C3537 /* EventUploaderTests.swift in Sources */,
531F0D2F2E79CA6E00180C05 /* SourceConfigTests.swift in Sources */,
Expand All @@ -1123,8 +1157,10 @@
53DEA6712E03D06F00D6C371 /* MockProvider.swift in Sources */,
53DEA6722E03D06F00D6C371 /* RudderStackAnalyticsTests.swift in Sources */,
5393019E2E65562100DAEAD1 /* BackoffPolicyTests.swift in Sources */,
859CEE162E9CDE9B00519C90 /* IntegrationPluginTests.swift in Sources */,
53DEA6732E03D06F00D6C371 /* AliasEventTests.swift in Sources */,
53DEA6742E03D06F00D6C371 /* StorageModuleTests.swift in Sources */,
859CEE142E9CDE5700519C90 /* IntegrationPluginStoreTests.swift in Sources */,
53DEA6752E03D06F00D6C371 /* OSInfoPluginTests.swift in Sources */,
53DEA6762E03D06F00D6C371 /* SessionTrackingPluginTests.swift in Sources */,
53DEA6772E03D06F00D6C371 /* LibraryInfoPluginTests.swift in Sources */,
Expand Down
8 changes: 8 additions & 0 deletions Sources/RudderStackAnalytics/Base/Analytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ public class Analytics {
A flag indicating whether the write key provided is invalid.
*/
var isInvalidWriteKey: Bool = false

/**
Management plugin for all integrations.
*/
var integrationManager: IntegrationsManagementPlugin

/**
Initializes the `Analytics` with the given configuration.
Expand All @@ -75,6 +80,7 @@ public class Analytics {
self.processEventChannel = AsyncChannel()
self.userIdentityState = createState(initialState: UserIdentity.initializeState(configuration.storage))
self.sourceConfigState = createState(initialState: SourceConfig.initialState())
self.integrationManager = IntegrationsManagementPlugin()
self.setup()
}
}
Expand Down Expand Up @@ -349,6 +355,8 @@ extension Analytics {
self.pluginChain = PluginChain(analytics: self)
self.lifecycleSessionWrapper = LifecycleSessionWrapper(analytics: self)

self.pluginChain?.add(plugin: self.integrationManager)

// Add default plugins
self.pluginChain?.add(plugin: RudderStackDataPlanePlugin())
self.pluginChain?.add(plugin: DeviceInfoPlugin())
Expand Down
49 changes: 26 additions & 23 deletions Sources/RudderStackAnalytics/Plugins/Base/Plugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,60 +112,55 @@ public extension Plugin {

- Conforms to: `Plugin`
*/
protocol EventPlugin: Plugin {
public protocol EventPlugin: Plugin {

/**
Processes a `IdentifyEvent` payload.

- Parameter payload: The `IdentifyEvent` payload to be processed.
- Returns: A modified `Event` or `nil` if the event is to be filtered out.
*/
func identify(payload: IdentifyEvent) -> Event?
func identify(payload: IdentifyEvent)

/**
Processes a `TrackEvent` payload.

- Parameter payload: The `TrackEvent` payload to be processed.
- Returns: A modified `Event` or `nil` if the event is to be filtered out.
*/
func track(payload: TrackEvent) -> Event?
func track(payload: TrackEvent)

/**
Processes a `ScreenEvent` payload.

- Parameter payload: The `ScreenEvent` payload to be processed.
- Returns: A modified `Event` or `nil` if the event is to be filtered out.
*/
func screen(payload: ScreenEvent) -> Event?
func screen(payload: ScreenEvent)

/**
Processes a `GroupEvent` payload.

- Parameter payload: The `GroupEvent` payload to be processed.
- Returns: A modified `Event` or `nil` if the event is to be filtered out.
*/
func group(payload: GroupEvent) -> Event?
func group(payload: GroupEvent)

/**
Processes a `AliasEvent` payload.

- Parameter payload: The `AliasEvent` payload to be processed.
- Returns: A modified `Event` or `nil` if the event is to be filtered out.
*/
func alias(payload: AliasEvent) -> Event?
func alias(payload: AliasEvent)
}

extension EventPlugin {
public extension EventPlugin {

func identify(payload: IdentifyEvent) -> Event? { payload }
func identify(payload: IdentifyEvent) { }

func track(payload: TrackEvent) -> Event? { payload }
func track(payload: TrackEvent) { }

func screen(payload: ScreenEvent) -> Event? { payload }
func screen(payload: ScreenEvent) { }

func group(payload: GroupEvent) -> Event? { payload }
func group(payload: GroupEvent) { }

func alias(payload: AliasEvent) -> Event? { payload }
func alias(payload: AliasEvent) { }

/**
Intercepts the appropriate method based on the event type.
Expand All @@ -178,19 +173,27 @@ extension EventPlugin {
- Returns: A processed `Event`, or `nil` if the event type is unsupported.
*/
func intercept(event: any Event) -> (any Event)? {
self.handleEvent(event: event)
return event
}

/**
Executes the appropriate method for the given event.
*/
func handleEvent(event: any Event) {
switch event {
case let event as IdentifyEvent:
return self.identify(payload: event)
self.identify(payload: event)
case let event as TrackEvent:
return self.track(payload: event)
self.track(payload: event)
case let event as ScreenEvent:
return self.screen(payload: event)
self.screen(payload: event)
case let event as GroupEvent:
return self.group(payload: event)
self.group(payload: event)
case let event as AliasEvent:
return self.alias(payload: event)
self.alias(payload: event)
default:
return nil
return
}
}
}
36 changes: 33 additions & 3 deletions Sources/RudderStackAnalytics/Plugins/Base/PluginChain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,49 @@ class PluginChain {
mediator.removeAll()
}
}

func find<T: Plugin>(type: T.Type) -> T? {
for pluginType in PluginType.allCases {
if let mediator = pluginList[pluginType],
let found = mediator.find(type) {
return found
}
}
return nil
}
}

// MARK: - Private functions
extension PluginChain {

/**
Applies plugins of a specific type to an event.

- Parameter pluginType: The type of plugins to apply
- Parameter event: The event to process
- Returns: The processed event or nil
*/
@discardableResult
private func applyPlugins(pluginType: PluginType, event: Event?) -> Event? {
func applyPlugins(pluginType: PluginType, event: Event?) -> Event? {
guard let mediator = self.pluginList[pluginType] else { return event }
return self.applyPlugins(mediator: mediator, event: event)
}

@discardableResult
private func applyPlugins(mediator: PluginInteractor, event: Event?) -> Event? {
func applyPlugins(mediator: PluginInteractor, event: Event?) -> Event? {
guard let event else { return nil }
return mediator.execute(event)
}
}

extension PluginChain {
func find(key: String) -> IntegrationPlugin? {
var found = [Plugin]()
if let mediator = pluginList[.terminal] {
found.append(contentsOf: mediator.pluginList.filter{ plugin in
guard let p = plugin as? IntegrationPlugin else { return false }
return p.key == key
})
}
return found.first as? IntegrationPlugin
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// DestinationResult.swift
// RudderStackAnalytics
//
// Created by Vishal Gupta on 13/10/25.
//

import Foundation

/**
Represents the result of a destination initialization operation.
*/
public enum DestinationResult {
/// Represents a successful destination initialization.
case success

/// Represents a failed destination initialization with an associated error.
case failure(Error)
}
Loading