mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 08:15:24 +00:00
Clean up the Signposter implementation and align on new metrics
This commit is contained in:
committed by
Stefan Ceriu
parent
8b768f74f8
commit
a2a8527ffc
@@ -76,6 +76,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
appMediator = AppMediator(windowManager: windowManager, networkMonitor: networkMonitor)
|
||||
|
||||
let appSettings = appHooks.appSettingsHook.configure(AppSettings())
|
||||
ServiceLocator.shared.register(appSettings: appSettings)
|
||||
|
||||
targetConfiguration = Target.mainApp.configure(logLevel: appSettings.logLevel,
|
||||
traceLogPacks: appSettings.traceLogPacks,
|
||||
@@ -95,8 +96,16 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
self.appDelegate = appDelegate
|
||||
self.appSettings = appSettings
|
||||
self.appHooks = appHooks
|
||||
|
||||
appRouteURLParser = AppRouteURLParser(appSettings: appSettings)
|
||||
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
|
||||
|
||||
let posthogAnalyticsClient = PostHogAnalyticsClient()
|
||||
posthogAnalyticsClient.updateSuperProperties(AnalyticsEvent.SuperProperties(appPlatform: .EXI, cryptoSDK: .Rust, cryptoSDKVersion: sdkGitSha()))
|
||||
let analyticsService = AnalyticsService(client: posthogAnalyticsClient, appSettings: appSettings)
|
||||
ServiceLocator.shared.register(analytics: analyticsService)
|
||||
|
||||
elementCallService = ElementCallService()
|
||||
|
||||
navigationRootCoordinator = NavigationRootCoordinator()
|
||||
@@ -107,7 +116,11 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
let keychainController = KeychainController(service: .sessions,
|
||||
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
||||
userSessionStore = UserSessionStore(keychainController: keychainController, appSettings: appSettings, appHooks: appHooks, networkMonitor: networkMonitor)
|
||||
userSessionStore = UserSessionStore(keychainController: keychainController,
|
||||
appSettings: appSettings,
|
||||
analyticsService: analyticsService,
|
||||
appHooks: appHooks,
|
||||
networkMonitor: networkMonitor)
|
||||
|
||||
let appLockService = AppLockService(keychainController: keychainController, appSettings: appSettings)
|
||||
let appLockNavigationCoordinator = NavigationRootCoordinator()
|
||||
@@ -123,11 +136,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
sdkGitSHA: sdkGitSha(),
|
||||
maxUploadSize: appSettings.bugReportMaxUploadSize,
|
||||
appHooks: appHooks)
|
||||
Self.setupServiceLocator(appSettings: appSettings, appHooks: appHooks)
|
||||
|
||||
Self.setupSentry(bugReportService: bugReportService, appSettings: appSettings)
|
||||
|
||||
ServiceLocator.shared.analytics.signpost.start()
|
||||
ServiceLocator.shared.analytics.startIfEnabled()
|
||||
analyticsService.startIfEnabled()
|
||||
|
||||
windowManager.delegate = self
|
||||
|
||||
@@ -356,6 +368,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
} else if appSettings.threadsEnabled, let threadRootEventID = content.threadRootEventID {
|
||||
handleAppRoute(.thread(roomID: roomID, threadRootEventID: threadRootEventID, focusEventID: eventID))
|
||||
} else if let eventID {
|
||||
// Only track main timeline event deeplinking
|
||||
ServiceLocator.shared.analytics.signpost.startTransaction(.notificationToMessage)
|
||||
handleAppRoute(.event(eventID: eventID, roomID: roomID, via: []))
|
||||
} else {
|
||||
handleAppRoute(.room(roomID: roomID, via: []))
|
||||
@@ -380,16 +394,6 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private static func setupServiceLocator(appSettings: AppSettings, appHooks: AppHooks) {
|
||||
ServiceLocator.shared.register(userIndicatorController: UserIndicatorController())
|
||||
ServiceLocator.shared.register(appSettings: appSettings)
|
||||
|
||||
let posthogAnalyticsClient = PostHogAnalyticsClient()
|
||||
posthogAnalyticsClient.updateSuperProperties(AnalyticsEvent.SuperProperties(appPlatform: .EXI, cryptoSDK: .Rust, cryptoSDKVersion: sdkGitSha()))
|
||||
ServiceLocator.shared.register(analytics: AnalyticsService(client: posthogAnalyticsClient,
|
||||
appSettings: appSettings))
|
||||
}
|
||||
|
||||
/// Perform any required migrations for the app to function correctly.
|
||||
private func performMigrationsIfNecessary(from oldVersion: Version, to newVersion: Version) {
|
||||
guard oldVersion != newVersion else { return }
|
||||
@@ -693,6 +697,14 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
fatalError("User session not setup")
|
||||
}
|
||||
|
||||
if let serverName = userSession.clientProxy.userIDServerName {
|
||||
ServiceLocator.shared.analytics.signpost.addGlobalTag(.homeserver, value: serverName)
|
||||
}
|
||||
|
||||
if !isNewLogin {
|
||||
ServiceLocator.shared.analytics.signpost.startTransaction(.cachedRoomList)
|
||||
}
|
||||
|
||||
let flowParameters = CommonFlowParameters(userSession: userSession,
|
||||
bugReportService: bugReportService,
|
||||
elementCallService: elementCallService,
|
||||
@@ -1061,9 +1073,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
private func startSync() {
|
||||
guard let userSession else { return }
|
||||
|
||||
let serverName = String(userSession.clientProxy.userIDServerName ?? "Unknown")
|
||||
ServiceLocator.shared.analytics.signpost.startTransaction(.upToDateRoomList)
|
||||
|
||||
ServiceLocator.shared.analytics.signpost.beginFirstSync(serverName: serverName)
|
||||
userSession.clientProxy.startSync()
|
||||
|
||||
guard clientProxyObserver == nil else {
|
||||
@@ -1072,6 +1083,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
|
||||
clientProxyObserver = userSession.clientProxy
|
||||
.loadingStatePublisher
|
||||
.dropFirst()
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] state in
|
||||
@@ -1084,7 +1096,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg
|
||||
ServiceLocator.shared.userIndicatorController.submitIndicator(.init(id: toastIdentifier, type: .toast(progress: .indeterminate), title: L10n.commonSyncing, persistent: true))
|
||||
}
|
||||
case .notLoading:
|
||||
ServiceLocator.shared.analytics.signpost.endFirstSync()
|
||||
ServiceLocator.shared.analytics.signpost.finishTransaction(.upToDateRoomList)
|
||||
ServiceLocator.shared.userIndicatorController.retractIndicatorWithId(toastIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,8 +111,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.flowParameters = flowParameters
|
||||
|
||||
setupStateMachine()
|
||||
|
||||
flowParameters.analytics.signpost.beginRoomFlow(roomID)
|
||||
}
|
||||
|
||||
// MARK: - FlowCoordinatorProtocol
|
||||
@@ -129,6 +127,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
switch appRoute {
|
||||
case .room(let roomID, let via):
|
||||
flowParameters.analytics.signpost.startTransaction(.openRoom)
|
||||
Task {
|
||||
await handleRoomRoute(roomID: roomID, via: via, animated: animated)
|
||||
}
|
||||
@@ -897,7 +896,6 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
} else {
|
||||
actionsSubject.send(.finished)
|
||||
}
|
||||
flowParameters.analytics.signpost.endRoomFlow()
|
||||
}
|
||||
|
||||
private func presentRoomDetails(isRoot: Bool, animated: Bool) async {
|
||||
|
||||
@@ -87,6 +87,12 @@ extension SDKListener: SendQueueRoomErrorListener where T == (String, ClientErro
|
||||
}
|
||||
}
|
||||
|
||||
extension SDKListener: SendQueueRoomUpdateListener where T == (String, RoomSendQueueUpdate) {
|
||||
func onUpdate(roomId: String, update: RoomSendQueueUpdate) {
|
||||
onUpdateClosure((roomId, update))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: SecureBackupController
|
||||
|
||||
extension SDKListener: BackupStateListener where T == BackupState {
|
||||
|
||||
@@ -95,18 +95,15 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
|
||||
startLoading(isInteractionBlocking: true)
|
||||
|
||||
Task {
|
||||
analytics.signpost.beginLogin()
|
||||
switch await authenticationService.login(username: state.bindings.username,
|
||||
password: state.bindings.password,
|
||||
initialDeviceName: UIDevice.current.initialDeviceName,
|
||||
deviceID: nil) {
|
||||
case .success(let userSession):
|
||||
actionsSubject.send(.signedIn(userSession))
|
||||
analytics.signpost.endLogin()
|
||||
stopLoading()
|
||||
case .failure(let error):
|
||||
stopLoading()
|
||||
analytics.signpost.endLogin()
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,8 +292,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
analyticsService.signpost.beginFirstRooms()
|
||||
|
||||
roomSummaryProvider.statePublisher
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] state in
|
||||
@@ -329,7 +327,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
}
|
||||
|
||||
if roomListMode == .rooms, state.roomListMode == .skeletons {
|
||||
analyticsService.signpost.endFirstRooms()
|
||||
analyticsService.signpost.finishTransaction(.cachedRoomList)
|
||||
}
|
||||
|
||||
state.roomListMode = roomListMode
|
||||
|
||||
@@ -256,7 +256,9 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
}
|
||||
|
||||
showFocusLoadingIndicator()
|
||||
defer { hideFocusLoadingIndicator() }
|
||||
defer {
|
||||
hideFocusLoadingIndicator()
|
||||
}
|
||||
|
||||
switch await timelineController.focusOnEvent(eventID, timelineSize: Constants.detachedTimelineSize) {
|
||||
case .success:
|
||||
@@ -318,6 +320,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
focussedEvent.appearance = .hasAppeared
|
||||
state.timelineState.focussedEvent = focussedEvent
|
||||
hideFocusLoadingIndicator()
|
||||
analyticsService.signpost.finishTransaction(.notificationToMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,6 +430,10 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
switch callback {
|
||||
case .updatedTimelineItems(let updatedItems, let isSwitchingTimelines):
|
||||
buildTimelineViews(timelineItems: updatedItems, isSwitchingTimelines: isSwitchingTimelines)
|
||||
|
||||
if !updatedItems.isEmpty {
|
||||
analyticsService.signpost.finishTransaction(.openRoom)
|
||||
}
|
||||
case .paginationState(let paginationState):
|
||||
if state.timelineState.paginationState != paginationState {
|
||||
state.timelineState.paginationState = paginationState
|
||||
|
||||
@@ -6,140 +6,106 @@
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import OSLog
|
||||
import CryptoKit
|
||||
import Sentry
|
||||
|
||||
/// A simple wrapper around OSSignposter for easy performance testing.
|
||||
/// A simple wrapper around Sentry for easy instrumentation
|
||||
class Signposter {
|
||||
/// The underlying signposter.
|
||||
private let signposter = OSSignposter(subsystem: subsystem, category: category)
|
||||
/// A logger instance to capture any errors.
|
||||
private let logger = Logger(subsystem: subsystem, category: category)
|
||||
private var transactions = [TransactionName: any Sentry.Span]()
|
||||
|
||||
/// Signpost name constants.
|
||||
enum Name {
|
||||
static let login: StaticString = "Login"
|
||||
static let firstSync: StaticString = "FirstSync"
|
||||
static let firstRooms: StaticString = "FirstRooms"
|
||||
static let roomFlow: StaticString = "RoomFlow"
|
||||
private var globalTags = [TagName: String]()
|
||||
|
||||
static let appStartup = "AppStartup"
|
||||
static let appStarted = "AppStarted"
|
||||
enum TransactionName: Hashable {
|
||||
case cachedRoomList
|
||||
case upToDateRoomList
|
||||
case notificationToMessage
|
||||
case openRoom
|
||||
case sendMessage(uuid: String)
|
||||
|
||||
static let homeserver = "homeserver"
|
||||
var id: String {
|
||||
switch self {
|
||||
case .cachedRoomList:
|
||||
"Cached room list"
|
||||
case .upToDateRoomList:
|
||||
"Up-to-date room list"
|
||||
case .notificationToMessage:
|
||||
"Notification to message"
|
||||
case .openRoom:
|
||||
"Open a room"
|
||||
case .sendMessage:
|
||||
"Send a message"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static let subsystem = "ElementX"
|
||||
static let category = "PerformanceTests"
|
||||
|
||||
// MARK: - App Startup
|
||||
|
||||
private var appStartupTransaction: Span?
|
||||
|
||||
/// We have a manual start method because we need to configure the ServiceLocator *before* we configure
|
||||
/// Sentry but this class is created in the AnalyticsService and so spans and transactions are dropped
|
||||
/// until Sentry has been configured. Therefore doing this in the init doesn't work.
|
||||
func start() {
|
||||
appStartupTransaction = SentrySDK.startTransaction(name: Name.appStartup, operation: Name.appStarted)
|
||||
enum SpanName: String {
|
||||
case timelineLoad = "Timeline load"
|
||||
}
|
||||
|
||||
// MARK: - Login
|
||||
struct Span {
|
||||
fileprivate let innerSpan: Sentry.Span
|
||||
|
||||
private var loginState: OSSignpostIntervalState?
|
||||
private var loginTransaction: Span?
|
||||
private var loginSpan: Span?
|
||||
|
||||
func beginLogin() {
|
||||
loginState = signposter.beginInterval(Name.login)
|
||||
loginTransaction = SentrySDK.startTransaction(name: "\(Name.login)", operation: "\(Name.login)")
|
||||
loginSpan = appStartupTransaction?.startChild(operation: "\(Name.login)", description: "\(Name.login)")
|
||||
func finish() {
|
||||
innerSpan.finish()
|
||||
}
|
||||
}
|
||||
|
||||
func endLogin() {
|
||||
guard let loginState else {
|
||||
logger.error("Missing login state.")
|
||||
return
|
||||
enum TagName: String {
|
||||
case homeserver = "Homeserver"
|
||||
}
|
||||
|
||||
// MARK: - Transactions
|
||||
|
||||
func startTransaction(_ transactionName: TransactionName, operation: String = "ux", tags: [TagName: String] = [:]) {
|
||||
let span = SentrySDK.startTransaction(name: transactionName.id, operation: operation)
|
||||
|
||||
tags
|
||||
.merging(globalTags) { tagValue, _ in
|
||||
tagValue
|
||||
}
|
||||
.forEach { (key: TagName, value: String) in
|
||||
span.setTag(value: value, key: key.rawValue)
|
||||
}
|
||||
|
||||
transactions[transactionName] = span
|
||||
}
|
||||
|
||||
func finishTransaction(_ transactionName: TransactionName) {
|
||||
transactions[transactionName]?.finish()
|
||||
transactions[transactionName] = nil
|
||||
}
|
||||
|
||||
// MARK: - Spans
|
||||
|
||||
func addSpan(_ spanName: SpanName, toTransaction transactionName: TransactionName) -> Span? {
|
||||
guard let transaction = transactions[transactionName] else {
|
||||
MXLog.error("Transaction not started or already finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
signposter.endInterval(Name.login, loginState)
|
||||
loginTransaction?.finish()
|
||||
loginSpan?.finish()
|
||||
|
||||
self.loginState = nil
|
||||
loginTransaction = nil
|
||||
loginSpan = nil
|
||||
return Span(innerSpan: transaction.startChild(operation: spanName.rawValue))
|
||||
}
|
||||
|
||||
// MARK: - FirstSync
|
||||
// MARK: - Tags
|
||||
|
||||
private var firstSyncState: OSSignpostIntervalState?
|
||||
private var firstSyncTransaction: Span?
|
||||
private var firstSyncSpan: Span?
|
||||
|
||||
func beginFirstSync(serverName: String) {
|
||||
appStartupTransaction?.setTag(value: serverName, key: Name.homeserver)
|
||||
|
||||
firstSyncState = signposter.beginInterval(Name.firstSync)
|
||||
|
||||
firstSyncTransaction = SentrySDK.startTransaction(name: "\(Name.firstSync)", operation: "\(Name.firstSync)")
|
||||
firstSyncTransaction?.setTag(value: serverName, key: Name.homeserver)
|
||||
|
||||
firstSyncSpan = appStartupTransaction?.startChild(operation: "\(Name.firstSync)", description: "\(Name.firstSync)")
|
||||
}
|
||||
|
||||
func endFirstSync() {
|
||||
guard let firstSyncState else { return }
|
||||
|
||||
signposter.endInterval(Name.firstSync, firstSyncState)
|
||||
firstSyncTransaction?.finish()
|
||||
firstSyncSpan?.finish()
|
||||
|
||||
self.firstSyncState = nil
|
||||
firstSyncTransaction = nil
|
||||
firstSyncSpan = nil
|
||||
}
|
||||
|
||||
// MARK: - FirstRooms
|
||||
|
||||
private var firstRoomsState: OSSignpostIntervalState?
|
||||
private var firstRoomsTransaction: Span?
|
||||
private var firstRoomsSpan: Span?
|
||||
|
||||
func beginFirstRooms() {
|
||||
firstRoomsState = signposter.beginInterval(Name.firstRooms)
|
||||
firstRoomsTransaction = SentrySDK.startTransaction(name: "\(Name.firstRooms)", operation: "\(Name.firstRooms)")
|
||||
firstRoomsSpan = appStartupTransaction?.startChild(operation: "\(Name.firstRooms)", description: "\(Name.firstRooms)")
|
||||
}
|
||||
|
||||
func endFirstRooms() {
|
||||
defer {
|
||||
appStartupTransaction?.finish()
|
||||
func addGlobalTag(_ tagName: TagName, value: String) {
|
||||
let value = switch tagName {
|
||||
case .homeserver:
|
||||
sha512(value)
|
||||
}
|
||||
|
||||
guard let firstRoomsState else { return }
|
||||
|
||||
signposter.endInterval(Name.firstRooms, firstRoomsState)
|
||||
firstRoomsTransaction?.finish()
|
||||
firstRoomsSpan?.finish()
|
||||
|
||||
self.firstRoomsState = nil
|
||||
firstRoomsTransaction = nil
|
||||
firstRoomsSpan = nil
|
||||
globalTags[tagName] = value
|
||||
}
|
||||
|
||||
// MARK: - Room Flow
|
||||
|
||||
private var roomFlowState: OSSignpostIntervalState?
|
||||
|
||||
func beginRoomFlow(_ name: String) {
|
||||
roomFlowState = signposter.beginInterval(Name.roomFlow)
|
||||
signposter.emitEvent("RoomName", "\(name, privacy: .auto(mask: .hash))")
|
||||
func removeGlobalTag(_ tagName: TagName) {
|
||||
globalTags[tagName] = nil
|
||||
}
|
||||
|
||||
func endRoomFlow() {
|
||||
guard let roomFlowState else { return }
|
||||
// MARK: - Private
|
||||
|
||||
signposter.endInterval(Name.roomFlow, roomFlowState)
|
||||
self.roomFlowState = nil
|
||||
func sha512(_ string: String) -> String {
|
||||
let data = Data(string.utf8)
|
||||
let hash = SHA512.hash(data: data)
|
||||
return hash.map { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@ import Foundation
|
||||
import MatrixRustSDK
|
||||
import OrderedCollections
|
||||
|
||||
// swiftlint:disable:next type_body_length
|
||||
class ClientProxy: ClientProxyProtocol {
|
||||
private let client: ClientProtocol
|
||||
private let networkMonitor: NetworkMonitorProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let analyticsService: AnalyticsService
|
||||
|
||||
let mediaLoader: MediaLoaderProtocol
|
||||
private let clientQueue: DispatchQueue
|
||||
@@ -37,7 +39,10 @@ class ClientProxy: ClientProxyProtocol {
|
||||
private var verificationStateListenerTaskHandle: TaskHandle?
|
||||
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private var sendQueueListenerTaskHandle: TaskHandle?
|
||||
private var sendQueueStatusListenerTaskHandle: TaskHandle?
|
||||
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private var sendQueueUpdatesListenerTaskHandle: TaskHandle?
|
||||
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private var mediaPreviewConfigListenerTaskHandle: TaskHandle?
|
||||
@@ -184,10 +189,12 @@ class ClientProxy: ClientProxyProtocol {
|
||||
|
||||
init(client: ClientProtocol,
|
||||
networkMonitor: NetworkMonitorProtocol,
|
||||
appSettings: AppSettings) async throws {
|
||||
appSettings: AppSettings,
|
||||
analyticsService: AnalyticsService) async throws {
|
||||
self.client = client
|
||||
self.networkMonitor = networkMonitor
|
||||
self.appSettings = appSettings
|
||||
self.analyticsService = analyticsService
|
||||
|
||||
clientQueue = .init(label: "ClientProxyQueue", attributes: .concurrent)
|
||||
|
||||
@@ -243,11 +250,22 @@ class ClientProxy: ClientProxyProtocol {
|
||||
Task { await self?.updateVerificationState(verificationState) }
|
||||
})
|
||||
|
||||
sendQueueListenerTaskHandle = client.subscribeToSendQueueStatus(listener: SDKListener { [weak self] roomID, error in
|
||||
sendQueueStatusListenerTaskHandle = client.subscribeToSendQueueStatus(listener: SDKListener { [weak self] roomID, error in
|
||||
MXLog.error("Send queue failed in room: \(roomID) with error: \(error)")
|
||||
self?.sendQueueStatusSubject.send(false)
|
||||
})
|
||||
|
||||
sendQueueUpdatesListenerTaskHandle = try? await client.subscribeToSendQueueUpdates(listener: SDKListener { _, update in
|
||||
switch update {
|
||||
case .newLocalEvent(let transactionID):
|
||||
analyticsService.signpost.startTransaction(.sendMessage(uuid: transactionID))
|
||||
case .sentEvent(let transactionID, _):
|
||||
analyticsService.signpost.finishTransaction(.sendMessage(uuid: transactionID))
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
sendQueueStatusSubject
|
||||
.combineLatest(homeserverReachabilityPublisher)
|
||||
.debounce(for: 1.0, scheduler: DispatchQueue.main)
|
||||
@@ -1136,7 +1154,8 @@ class ClientProxy: ClientProxyProtocol {
|
||||
case .joined:
|
||||
let roomProxy = try await JoinedRoomProxy(roomListService: roomListService,
|
||||
room: room,
|
||||
appSettings: appSettings)
|
||||
appSettings: appSettings,
|
||||
analyticsService: analyticsService)
|
||||
|
||||
return .joined(roomProxy)
|
||||
case .left:
|
||||
|
||||
@@ -15,6 +15,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
private let roomListService: RoomListServiceProtocol
|
||||
private let room: RoomProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let analyticsService: AnalyticsService
|
||||
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private var roomInfoObservationToken: TaskHandle?
|
||||
@@ -76,13 +77,16 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
|
||||
init(roomListService: RoomListServiceProtocol,
|
||||
room: RoomProtocol,
|
||||
appSettings: AppSettings) async throws {
|
||||
appSettings: AppSettings,
|
||||
analyticsService: AnalyticsService) async throws {
|
||||
self.roomListService = roomListService
|
||||
self.room = room
|
||||
self.appSettings = appSettings
|
||||
self.analyticsService = analyticsService
|
||||
|
||||
infoSubject = try await .init(RoomInfoProxy(roomInfo: room.roomInfo()))
|
||||
|
||||
let openRoomSpan = analyticsService.signpost.addSpan(.timelineLoad, toTransaction: .openRoom)
|
||||
timeline = try await TimelineProxy(timeline: room.timelineWithConfiguration(configuration: .init(focus: .live(hideThreadedEvents: appSettings.threadsEnabled),
|
||||
filter: .eventTypeFilter(filter: excludedEventsFilter),
|
||||
internalIdPrefix: nil,
|
||||
@@ -90,6 +94,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
trackReadReceipts: .messageLikeEvents,
|
||||
reportUtds: true)),
|
||||
kind: .live)
|
||||
openRoomSpan?.finish()
|
||||
|
||||
Task {
|
||||
await updateMembers()
|
||||
@@ -146,6 +151,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
|
||||
func timelineFocusedOnEvent(eventID: String, numberOfEvents: UInt16) async -> Result<TimelineProxyProtocol, RoomProxyError> {
|
||||
do {
|
||||
let openRoomSpan = analyticsService.signpost.addSpan(.timelineLoad, toTransaction: .notificationToMessage)
|
||||
let sdkTimeline = try await room.timelineWithConfiguration(configuration: .init(focus: .event(eventId: eventID,
|
||||
numContextEvents: numberOfEvents,
|
||||
hideThreadedEvents: appSettings.threadsEnabled),
|
||||
@@ -154,6 +160,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
dateDividerMode: .daily,
|
||||
trackReadReceipts: .disabled,
|
||||
reportUtds: true))
|
||||
openRoomSpan?.finish()
|
||||
|
||||
return .success(TimelineProxy(timeline: sdkTimeline, kind: .detached))
|
||||
} catch let error as FocusEventError {
|
||||
|
||||
@@ -12,6 +12,7 @@ import MatrixRustSDK
|
||||
class UserSessionStore: UserSessionStoreProtocol {
|
||||
private let keychainController: KeychainControllerProtocol
|
||||
private let appSettings: AppSettings
|
||||
private let analyticsService: AnalyticsService
|
||||
private let networkMonitor: NetworkMonitorProtocol
|
||||
private let appHooks: AppHooks
|
||||
|
||||
@@ -31,10 +32,12 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
|
||||
init(keychainController: KeychainControllerProtocol,
|
||||
appSettings: AppSettings,
|
||||
analyticsService: AnalyticsService,
|
||||
appHooks: AppHooks,
|
||||
networkMonitor: NetworkMonitorProtocol) {
|
||||
self.keychainController = keychainController
|
||||
self.appSettings = appSettings
|
||||
self.analyticsService = analyticsService
|
||||
self.appHooks = appHooks
|
||||
self.networkMonitor = networkMonitor
|
||||
}
|
||||
@@ -159,7 +162,8 @@ class UserSessionStore: UserSessionStoreProtocol {
|
||||
do {
|
||||
return try await ClientProxy(client: client,
|
||||
networkMonitor: networkMonitor,
|
||||
appSettings: appSettings)
|
||||
appSettings: appSettings,
|
||||
analyticsService: analyticsService)
|
||||
} catch {
|
||||
throw UserSessionStoreError.failedSettingUpClientProxy(error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user