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

Link mode sr #1404

Merged
merged 10 commits into from
Aug 23, 2024
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
19 changes: 0 additions & 19 deletions Sources/Events/Event.swift

This file was deleted.

18 changes: 9 additions & 9 deletions Sources/Events/EventStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
import Foundation

protocol EventStorage {
func saveErrorEvent(_ event: Event)
func fetchErrorEvents() -> [Event]
func saveErrorEvent(_ event: TraceEvent)
func fetchErrorEvents() -> [TraceEvent]
func clearErrorEvents()
}

class UserDefaultsEventStorage: EventStorage {
class UserDefaultsTraceEventStorage: EventStorage {
private let errorEventsKey = "com.walletconnect.sdk.errorEvents"
private let maxEvents = 30

func saveErrorEvent(_ event: Event) {
func saveErrorEvent(_ event: TraceEvent) {
var existingEvents = fetchErrorEvents()
existingEvents.append(event)
// Ensure we keep only the last 30 events
Expand All @@ -23,9 +23,9 @@ class UserDefaultsEventStorage: EventStorage {
}
}

func fetchErrorEvents() -> [Event] {
func fetchErrorEvents() -> [TraceEvent] {
if let data = UserDefaults.standard.data(forKey: errorEventsKey),
let events = try? JSONDecoder().decode([Event].self, from: data) {
let events = try? JSONDecoder().decode([TraceEvent].self, from: data) {
// Return only the last 30 events
return Array(events.suffix(maxEvents))
}
Expand All @@ -39,13 +39,13 @@ class UserDefaultsEventStorage: EventStorage {

#if DEBUG
class MockEventStorage: EventStorage {
private(set) var savedEvents: [Event] = []
private(set) var savedEvents: [TraceEvent] = []

func saveErrorEvent(_ event: Event) {
func saveErrorEvent(_ event: TraceEvent) {
savedEvents.append(event)
}

func fetchErrorEvents() -> [Event] {
func fetchErrorEvents() -> [TraceEvent] {
return savedEvents
}

Expand Down
46 changes: 36 additions & 10 deletions Sources/Events/EventsClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@ import Foundation

public protocol EventsClientProtocol {
func startTrace(topic: String)
func saveEvent(_ event: TraceEvent)
func saveTraceEvent(_ event: TraceEventItem)
func setTopic(_ topic: String)
func setTelemetryEnabled(_ enabled: Bool)
func saveMessageEvent(_ event: MessageEventType)
}

public class EventsClient: EventsClientProtocol {
private let eventsCollector: EventsCollector
private let eventsDispatcher: EventsDispatcher
private let logger: ConsoleLogging
private var stateStorage: TelemetryStateStorage
private let messageEventsStorage: MessageEventsStorage

init(
eventsCollector: EventsCollector,
eventsDispatcher: EventsDispatcher,
logger: ConsoleLogging,
stateStorage: TelemetryStateStorage
stateStorage: TelemetryStateStorage,
messageEventsStorage: MessageEventsStorage
) {
self.eventsCollector = eventsCollector
self.eventsDispatcher = eventsDispatcher
self.logger = logger
self.stateStorage = stateStorage
self.messageEventsStorage = messageEventsStorage

if stateStorage.telemetryEnabled {
Task { await sendStoredEvents() }
Expand All @@ -48,12 +52,17 @@ public class EventsClient: EventsClientProtocol {
}

// Public method to save event
public func saveEvent(_ event: TraceEvent) {
public func saveTraceEvent(_ event: TraceEventItem) {
guard stateStorage.telemetryEnabled else { return }
logger.debug("Will store an event: \(event)")
logger.debug("Will store a trace event: \(event)")
eventsCollector.saveEvent(event)
}

public func saveMessageEvent(_ event: MessageEventType) {
logger.debug("Will store a message event: \(event)")
messageEventsStorage.saveMessageEvent(event)
}

// Public method to set telemetry enabled or disabled
public func setTelemetryEnabled(_ enabled: Bool) {
stateStorage.telemetryEnabled = enabled
Expand All @@ -66,15 +75,27 @@ public class EventsClient: EventsClientProtocol {

private func sendStoredEvents() async {
guard stateStorage.telemetryEnabled else { return }
let events = eventsCollector.storage.fetchErrorEvents()
guard !events.isEmpty else { return }

logger.debug("Will send events")
let traceEvents = eventsCollector.storage.fetchErrorEvents()
let messageEvents = messageEventsStorage.fetchMessageEvents()

guard !traceEvents.isEmpty || !messageEvents.isEmpty else { return }

var combinedEvents: [AnyCodable] = []

// Wrap trace events
combinedEvents.append(contentsOf: traceEvents.map { AnyCodable($0) })

// Wrap message events
combinedEvents.append(contentsOf: messageEvents.map { AnyCodable($0) })

logger.debug("Will send combined events")
do {
let success: Bool = try await eventsDispatcher.executeWithRetry(events: events)
let success: Bool = try await eventsDispatcher.executeWithRetry(events: combinedEvents)
if success {
logger.debug("Events sent successfully")
logger.debug("Combined events sent successfully")
self.eventsCollector.storage.clearErrorEvents()
self.messageEventsStorage.clearMessageEvents()
}
} catch {
logger.debug("Failed to send events after multiple attempts: \(error)")
Expand All @@ -96,12 +117,17 @@ public class MockEventsClient: EventsClientProtocol {

public func setTopic(_ topic: String) {}

public func saveEvent(_ event: TraceEvent) {
public func saveTraceEvent(_ event: TraceEventItem) {
saveEventCalled = true
}

public func setTelemetryEnabled(_ enabled: Bool) {
telemetryEnabled = enabled
}

public func saveMessageEvent(_ event: MessageEventType) {

}

}
#endif
5 changes: 3 additions & 2 deletions Sources/Events/EventsClientFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public class EventsClientFactory {
static func create(
projectId: String,
sdkVersion: String,
storage: EventStorage = UserDefaultsEventStorage()
storage: EventStorage = UserDefaultsTraceEventStorage()
) -> EventsClient {
let networkingService = NetworkingService(
projectId: projectId,
Expand All @@ -18,7 +18,8 @@ public class EventsClientFactory {
eventsCollector: eventsCollector,
eventsDispatcher: eventsDispatcher,
logger: logger,
stateStorage: UserDefaultsTelemetryStateStorage()
stateStorage: UserDefaultsTelemetryStateStorage(),
messageEventsStorage: UserDefaultsMessageEventsStorage()
)
}
}
Expand Down
12 changes: 6 additions & 6 deletions Sources/Events/EventsCollector.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Foundation

// Protocol for TraceEvent
public protocol TraceEvent: CustomStringConvertible {
public protocol TraceEventItem: CustomStringConvertible {
var description: String { get }
}

// Protocol for ErrorEvent
protocol ErrorEvent: TraceEvent {}
protocol ErrorEvent: TraceEventItem {}


class EventsCollector {
Expand Down Expand Up @@ -34,7 +34,7 @@ class EventsCollector {
}

// Function to save event
func saveEvent(_ event: TraceEvent) {
func saveEvent(_ event: TraceEventItem) {
trace.append(event.description)
if let errorEvent = event as? ErrorEvent {
saveErrorEvent(errorEvent)
Expand All @@ -51,14 +51,14 @@ class EventsCollector {
// Private function to save error event
private func saveErrorEvent(_ errorEvent: ErrorEvent) {
let bundleId = Bundle.main.bundleIdentifier ?? "Unknown"
let event = Event(
let event = TraceEvent(
eventId: UUID().uuidString,
bundleId: bundleId,
timestamp: Int64(Date().timeIntervalSince1970 * 1000),
props: Props(
props: TraceEvent.Props(
event: "ERROR",
type: errorEvent.description,
properties: Properties(
properties: TraceEvent.Properties(
topic: topic,
trace: trace
)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Events/EventsDispatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class EventsDispatcher {
self.retryPolicy = retryPolicy
}

func executeWithRetry(events: [Event]) async throws -> Bool {
func executeWithRetry<T: Encodable>(events: [T]) async throws -> Bool {
var attempts = 0
var delay = retryPolicy.initialDelay

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import Foundation

public enum PairingExecutionTraceEvents: String, TraceEvent {
public enum PairingExecutionTraceEvents: String, TraceEventItem {
case pairingUriValidationSuccess = "pairing_uri_validation_success"
case pairingStarted = "pairing_started"
case noWssConnection = "no_wss_connection"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import Foundation

public enum SessionApproveExecutionTraceEvents: String, TraceEvent {
public enum SessionApproveExecutionTraceEvents: String, TraceEventItem {
case approvingSessionProposal = "approving_session_proposal"
case sessionNamespacesValidationStarted = "session_namespaces_validation_started"
case sessionNamespacesValidationSuccess = "session_namespaces_validation_success"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import Foundation

public enum SessionAuthenticateTraceEvents: String, TraceEvent {
public enum SessionAuthenticateTraceEvents: String, TraceEventItem {
case signatureVerificationStarted = "signature_verification_started"
case signatureVerificationSuccess = "signature_verification_success"
case requestParamsRetrieved = "request_params_retrieved"
Expand Down
33 changes: 33 additions & 0 deletions Sources/Events/MessageEvent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

import Foundation

struct MessageEvent: Codable {
struct Props: Codable {
let event: String = "SUCCESS"

Check warning on line 6 in Sources/Events/MessageEvent.swift

View workflow job for this annotation

GitHub Actions / prepare

immutable property will not be decoded because it is declared with an initial value which cannot be overwritten

Check warning on line 6 in Sources/Events/MessageEvent.swift

View workflow job for this annotation

GitHub Actions / prepare

immutable property will not be decoded because it is declared with an initial value which cannot be overwritten
let type: String
let properties: Properties
}

struct Properties: Codable {
let correlationId: Int64
let clientId: String
let direction: Direction

// Custom CodingKeys to map Swift property names to JSON keys
enum CodingKeys: String, CodingKey {
case correlationId = "correlation_id"
case clientId = "client_id"
case direction
}
}

enum Direction: String, Codable {
case sent
case received
}

let eventId: String
let bundleId: String
let timestamp: Int64
let props: Props
}
62 changes: 62 additions & 0 deletions Sources/Events/MessageEventProperties.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Foundation

protocol MessageEventsStorage {
func saveMessageEvent(_ eventType: MessageEventType)
func fetchMessageEvents() -> [MessageEvent]
func clearMessageEvents()
}

class UserDefaultsMessageEventsStorage: MessageEventsStorage {
private let messageEventsKey = "com.walletconnect.sdk.messageEvents"
private let maxEvents = 200

func saveMessageEvent(_ eventType: MessageEventType) {
let correlationId = eventType.rpcId.integer
let type = "\(eventType.tag)"
let bundleId = Bundle.main.bundleIdentifier ?? "Unknown"
let clientId = (try? Networking.interactor.getClientId()) ?? "Unknown"

let props = MessageEvent.Props(
type: type,
properties: MessageEvent.Properties(
correlationId: correlationId,
clientId: clientId,
direction: eventType.direction
)
)

let event = MessageEvent(
eventId: UUID().uuidString,
bundleId: bundleId,
timestamp: Int64(Date().timeIntervalSince1970 * 1000),
props: props
)

// Fetch existing events from UserDefaults
var existingEvents = fetchMessageEvents()
existingEvents.append(event)

// Ensure we keep only the last 200 events
if existingEvents.count > maxEvents {
existingEvents = Array(existingEvents.suffix(maxEvents))
}

// Save updated events back to UserDefaults
if let encoded = try? JSONEncoder().encode(existingEvents) {
UserDefaults.standard.set(encoded, forKey: messageEventsKey)
}
}

func fetchMessageEvents() -> [MessageEvent] {
if let data = UserDefaults.standard.data(forKey: messageEventsKey),
let events = try? JSONDecoder().decode([MessageEvent].self, from: data) {
// Return only the last 200 events
return Array(events.suffix(maxEvents))
}
return []
}

func clearMessageEvents() {
UserDefaults.standard.removeObject(forKey: messageEventsKey)
}
}
Loading
Loading