diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 5d1577890..08a62be8a 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -7080,7 +7080,7 @@ repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 1.1.49; + version = 1.1.50; }; }; 821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = { @@ -7128,7 +7128,7 @@ repositoryURL = "https://github.com/matrix-org/matrix-analytics-events"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 0.13.0; + minimumVersion = 0.14.0; }; }; C13F55E4518415CB4C278E73 /* XCRemoteSwiftPackageReference "DTCoreText" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d20db5262..50300f4f3 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -121,8 +121,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-analytics-events", "state" : { - "revision" : "ccc4af6aa00987abe7135fa0b7cea97c8cfb3d26", - "version" : "0.13.0" + "revision" : "f756bf0756b7349a1d3ccee0d038790d1ab2ec56", + "version" : "0.14.0" } }, { @@ -130,8 +130,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-rust-components-swift", "state" : { - "revision" : "0361eac2610f0007f2a6880a88c750a1bbb405b9", - "version" : "1.1.49" + "revision" : "e6b350d257aeb7395e003c3d0c26ae65c2e2e349", + "version" : "1.1.50" } }, { diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 2403edc4b..a13c99c9f 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -139,6 +139,24 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { } } .store(in: &cancellables) + + userSession.clientProxy.actionsPublisher + .receive(on: DispatchQueue.main) + .sink { action in + guard case let .receivedDecryptionError(info) = action else { + return + } + + let timeToDecryptMs: Int + if let unsignedTimeToDecryptMs = info.timeToDecryptMs { + timeToDecryptMs = Int(unsignedTimeToDecryptMs) + } else { + timeToDecryptMs = -1 + } + + analytics.trackError(context: nil, domain: .E2EE, name: .OlmKeysNotSentError, timeToDecryptMillis: timeToDecryptMs) + } + .store(in: &cancellables) } func start() { diff --git a/ElementX/Sources/Services/Analytics/AnalyticsService.swift b/ElementX/Sources/Services/Analytics/AnalyticsService.swift index bd5700094..aa5454cc5 100644 --- a/ElementX/Sources/Services/Analytics/AnalyticsService.swift +++ b/ElementX/Sources/Services/Analytics/AnalyticsService.swift @@ -130,7 +130,18 @@ extension AnalyticsService { func trackInteraction(index: Int? = nil, name: AnalyticsEvent.Interaction.Name) { capture(event: AnalyticsEvent.Interaction(index: index, interactionType: .Touch, name: name)) } - + + /// Track the presentation of a screen + /// - Parameter context: To provide additional context or description for the error + /// - Parameter domain: The domain to which the error belongs to. + /// - Parameter name: The name of the error + /// - Parameter timeToDecryptMillis: The time it took to decrypt the event in milliseconds, needs to be used only to track UTD errors, otherwise if the error is nort related to UTD it should be nil. + /// Can be found in `UnableToDecryptInfo`. In case the `UnableToDecryptInfo` contains the value as nil, pass it as `-1` + func trackError(context: String?, domain: AnalyticsEvent.Error.Domain, name: AnalyticsEvent.Error.Name, timeToDecryptMillis: Int? = nil) { + // CryptoModule is deprecated + capture(event: AnalyticsEvent.Error(context: context, cryptoModule: nil, cryptoSDK: .Rust, domain: domain, name: name, timeToDecryptMillis: timeToDecryptMillis)) + } + /// Track the creation of a room /// - Parameter isDM: true if the created room is a direct message, false otherwise func trackCreatedRoom(isDM: Bool) { diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index e3b6052be..2bf42670c 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -589,6 +589,7 @@ class ClientProxy: ClientProxyProtocol { let syncService = try await client .syncService() .withCrossProcessLock(appIdentifier: "MainApp") + .withUtdHook(delegate: ClientDecryptionErrorDelegate(actionsSubject: actionsSubject)) .finish() let roomListService = syncService.roomListService() @@ -803,6 +804,18 @@ private class ClientDelegateWrapper: ClientDelegate { } } +private class ClientDecryptionErrorDelegate: UnableToDecryptDelegate { + private let actionsSubject: PassthroughSubject + + init(actionsSubject: PassthroughSubject) { + self.actionsSubject = actionsSubject + } + + func onUtd(info: UnableToDecryptInfo) { + actionsSubject.send(.receivedDecryptionError(info)) + } +} + private class IgnoredUsersListenerProxy: IgnoredUsersListener { private let onUpdateClosure: ([String]) -> Void diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index bb2a69b80..00c2d6bf4 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -21,6 +21,7 @@ import MatrixRustSDK enum ClientProxyAction { case receivedSyncUpdate case receivedAuthError(isSoftLogout: Bool) + case receivedDecryptionError(UnableToDecryptInfo) var isSyncUpdate: Bool { if case .receivedSyncUpdate = self { diff --git a/UnitTests/Sources/LoggingTests.swift b/UnitTests/Sources/LoggingTests.swift index ddc48ff69..32f3a8a20 100644 --- a/UnitTests/Sources/LoggingTests.swift +++ b/UnitTests/Sources/LoggingTests.swift @@ -223,9 +223,9 @@ class LoggingTests: XCTestCase { formatted: FormattedBody(format: .html, body: "\(emoteString)")) let pointer = Unmanaged.passRetained(NSURL(fileURLWithPath: "/tmp/file")).toOpaque() - let rustImageMessage = ImageMessageContent(body: "ImageString", source: MediaSource(unsafeFromRawPointer: pointer), info: nil) - let rustVideoMessage = VideoMessageContent(body: "VideoString", source: MediaSource(unsafeFromRawPointer: pointer), info: nil) - let rustFileMessage = FileMessageContent(body: "FileString", filename: "FileName", source: MediaSource(unsafeFromRawPointer: pointer), info: nil) + let rustImageMessage = ImageMessageContent(body: "ImageString", formatted: nil, filename: nil, source: MediaSource(unsafeFromRawPointer: pointer), info: nil) + let rustVideoMessage = VideoMessageContent(body: "VideoString", formatted: nil, filename: nil, source: MediaSource(unsafeFromRawPointer: pointer), info: nil) + let rustFileMessage = FileMessageContent(body: "FileString", formatted: nil, filename: "FileName", source: MediaSource(unsafeFromRawPointer: pointer), info: nil) // When logging that value MXLog.info(rustTextMessage) diff --git a/project.yml b/project.yml index 7594a6cb0..081a4abfb 100644 --- a/project.yml +++ b/project.yml @@ -48,7 +48,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/matrix-org/matrix-rust-components-swift - exactVersion: 1.1.49 + exactVersion: 1.1.50 # path: ../matrix-rust-sdk Compound: url: https://github.com/element-hq/compound-ios @@ -56,7 +56,7 @@ packages: # path: ../compound-ios AnalyticsEvents: url: https://github.com/matrix-org/matrix-analytics-events - minorVersion: 0.13.0 + minorVersion: 0.14.0 # path: ../matrix-analytics-events Emojibase: url: https://github.com/matrix-org/emojibase-bindings