-
Notifications
You must be signed in to change notification settings - Fork 184
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1380 from WalletConnect/events-sdk
Events sdk
- Loading branch information
Showing
40 changed files
with
934 additions
and
85 deletions.
There are no files selected for viewing
54 changes: 54 additions & 0 deletions
54
.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Scheme | ||
LastUpgradeVersion = "1540" | ||
version = "1.7"> | ||
<BuildAction | ||
parallelizeBuildables = "YES" | ||
buildImplicitDependencies = "YES" | ||
buildArchitectures = "Automatic"> | ||
</BuildAction> | ||
<TestAction | ||
buildConfiguration = "Debug" | ||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
shouldUseLaunchSchemeArgsEnv = "YES" | ||
shouldAutocreateTestPlan = "YES"> | ||
<Testables> | ||
<TestableReference | ||
skipped = "NO"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "EventsTests" | ||
BuildableName = "EventsTests" | ||
BlueprintName = "EventsTests" | ||
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"> | ||
</ProfileAction> | ||
<AnalyzeAction | ||
buildConfiguration = "Debug"> | ||
</AnalyzeAction> | ||
<ArchiveAction | ||
buildConfiguration = "Release" | ||
revealArchiveInOrganizer = "YES"> | ||
</ArchiveAction> | ||
</Scheme> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Foundation | ||
|
||
struct Event: Codable { | ||
let eventId: String | ||
let bundleId: String | ||
let timestamp: Int64 | ||
let props: Props | ||
} | ||
|
||
struct Props: Codable { | ||
let event: String | ||
let type: String | ||
let properties: Properties? | ||
} | ||
|
||
struct Properties: Codable { | ||
let topic: String? | ||
let trace: [String]? | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
|
||
import Foundation | ||
|
||
protocol EventStorage { | ||
func saveErrorEvent(_ event: Event) | ||
func fetchErrorEvents() -> [Event] | ||
func clearErrorEvents() | ||
} | ||
|
||
class UserDefaultsEventStorage: EventStorage { | ||
private let errorEventsKey = "com.walletconnect.sdk.errorEvents" | ||
private let maxEvents = 30 | ||
|
||
func saveErrorEvent(_ event: Event) { | ||
var existingEvents = fetchErrorEvents() | ||
existingEvents.append(event) | ||
// Ensure we keep only the last 30 events | ||
if existingEvents.count > maxEvents { | ||
existingEvents = Array(existingEvents.suffix(maxEvents)) | ||
} | ||
if let encoded = try? JSONEncoder().encode(existingEvents) { | ||
UserDefaults.standard.set(encoded, forKey: errorEventsKey) | ||
} | ||
} | ||
|
||
func fetchErrorEvents() -> [Event] { | ||
if let data = UserDefaults.standard.data(forKey: errorEventsKey), | ||
let events = try? JSONDecoder().decode([Event].self, from: data) { | ||
// Return only the last 30 events | ||
return Array(events.suffix(maxEvents)) | ||
} | ||
return [] | ||
} | ||
|
||
func clearErrorEvents() { | ||
UserDefaults.standard.removeObject(forKey: errorEventsKey) | ||
} | ||
} | ||
|
||
#if DEBUG | ||
class MockEventStorage: EventStorage { | ||
private(set) var savedEvents: [Event] = [] | ||
|
||
func saveErrorEvent(_ event: Event) { | ||
savedEvents.append(event) | ||
} | ||
|
||
func fetchErrorEvents() -> [Event] { | ||
return savedEvents | ||
} | ||
|
||
func clearErrorEvents() { | ||
savedEvents.removeAll() | ||
} | ||
} | ||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import Foundation | ||
|
||
public class Events { | ||
/// Singleton instance of EventsClient | ||
public static var instance: EventsClient = { | ||
return EventsClientFactory.create( | ||
projectId: Networking.projectId, | ||
sdkVersion: EnvironmentInfo.sdkName | ||
) | ||
}() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import Foundation | ||
|
||
public protocol EventsClientProtocol { | ||
func startTrace(topic: String) | ||
func saveEvent(_ event: TraceEvent) | ||
func setTopic(_ topic: String) | ||
func setTelemetryEnabled(_ enabled: Bool) | ||
} | ||
|
||
public class EventsClient: EventsClientProtocol { | ||
private let eventsCollector: EventsCollector | ||
private let eventsDispatcher: EventsDispatcher | ||
private let logger: ConsoleLogging | ||
private var stateStorage: TelemetryStateStorage | ||
|
||
init( | ||
eventsCollector: EventsCollector, | ||
eventsDispatcher: EventsDispatcher, | ||
logger: ConsoleLogging, | ||
stateStorage: TelemetryStateStorage | ||
) { | ||
self.eventsCollector = eventsCollector | ||
self.eventsDispatcher = eventsDispatcher | ||
self.logger = logger | ||
self.stateStorage = stateStorage | ||
|
||
if stateStorage.telemetryEnabled { | ||
Task { await sendStoredEvents() } | ||
} else { | ||
self.eventsCollector.storage.clearErrorEvents() | ||
} | ||
} | ||
|
||
public func setLogging(level: LoggingLevel) { | ||
logger.setLogging(level: level) | ||
} | ||
|
||
// Public method to start trace | ||
public func startTrace(topic: String) { | ||
guard stateStorage.telemetryEnabled else { return } | ||
logger.debug("Will start trace with topic: \(topic)") | ||
eventsCollector.startTrace(topic: topic) | ||
} | ||
|
||
public func setTopic(_ topic: String) { | ||
guard stateStorage.telemetryEnabled else { return } | ||
eventsCollector.setTopic(topic) | ||
} | ||
|
||
// Public method to save event | ||
public func saveEvent(_ event: TraceEvent) { | ||
guard stateStorage.telemetryEnabled else { return } | ||
logger.debug("Will store an event: \(event)") | ||
eventsCollector.saveEvent(event) | ||
} | ||
|
||
// Public method to set telemetry enabled or disabled | ||
public func setTelemetryEnabled(_ enabled: Bool) { | ||
stateStorage.telemetryEnabled = enabled | ||
if enabled { | ||
Task { await sendStoredEvents() } | ||
} else { | ||
eventsCollector.storage.clearErrorEvents() | ||
} | ||
} | ||
|
||
private func sendStoredEvents() async { | ||
guard stateStorage.telemetryEnabled else { return } | ||
let events = eventsCollector.storage.fetchErrorEvents() | ||
guard !events.isEmpty else { return } | ||
|
||
logger.debug("Will send events") | ||
do { | ||
let success: Bool = try await eventsDispatcher.executeWithRetry(events: events) | ||
if success { | ||
logger.debug("Events sent successfully") | ||
self.eventsCollector.storage.clearErrorEvents() | ||
} | ||
} catch { | ||
logger.debug("Failed to send events after multiple attempts: \(error)") | ||
} | ||
} | ||
} | ||
|
||
#if DEBUG | ||
public class MockEventsClient: EventsClientProtocol { | ||
var startTraceCalled = false | ||
var saveEventCalled = false | ||
var telemetryEnabled = true | ||
|
||
public init() {} | ||
|
||
public func startTrace(topic: String) { | ||
startTraceCalled = true | ||
} | ||
|
||
public func setTopic(_ topic: String) {} | ||
|
||
public func saveEvent(_ event: TraceEvent) { | ||
saveEventCalled = true | ||
} | ||
|
||
public func setTelemetryEnabled(_ enabled: Bool) { | ||
telemetryEnabled = enabled | ||
} | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import Foundation | ||
|
||
public class EventsClientFactory { | ||
static func create( | ||
projectId: String, | ||
sdkVersion: String, | ||
storage: EventStorage = UserDefaultsEventStorage() | ||
) -> EventsClient { | ||
let networkingService = NetworkingService( | ||
projectId: projectId, | ||
sdkVersion: sdkVersion | ||
) | ||
let logger = ConsoleLogger(prefix: "🧚🏻♂️", loggingLevel: .off) | ||
let retryPolicy = RetryPolicy(maxAttempts: 3, initialDelay: 5, multiplier: 2) | ||
let eventsDispatcher = EventsDispatcher(networkingService: networkingService, retryPolicy: retryPolicy) | ||
let eventsCollector = EventsCollector(storage: storage, logger: logger) | ||
return EventsClient( | ||
eventsCollector: eventsCollector, | ||
eventsDispatcher: eventsDispatcher, | ||
logger: logger, | ||
stateStorage: UserDefaultsTelemetryStateStorage() | ||
) | ||
} | ||
} | ||
|
Oops, something went wrong.