From e4a73222500d4f82a274ac0aa30b0bbe9c713989 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Thu, 4 Jun 2026 11:03:32 +0300 Subject: [PATCH] Expose the async nature of the ClientProxy `startSync` method --- .../Sources/Application/AppCoordinator.swift | 28 +++++++----- .../Mocks/Generated/GeneratedMocks.swift | 6 +-- .../Sources/Services/Client/ClientProxy.swift | 43 +++++++++---------- .../Services/Client/ClientProxyProtocol.swift | 2 +- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index e7c29c8c4..f56469a82 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -41,8 +41,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg configureElementCallService() configureNotificationManager() observeUserSessionChanges() - startSync() - Task { await appHooks.configure(with: userSession) } + Task { + await startSync() + await appHooks.configure(with: userSession) + } } } } @@ -185,8 +187,10 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg // When reporting a VoIP call through the CXProvider's `reportNewIncomingVoIPPushPayload` // the UIApplication states don't change and syncing is neither started nor ran on // a background task. Handle both manually here. - self?.startSync() - self?.scheduleDelayedSyncStop() + Task { + await self?.startSync() + self?.scheduleDelayedSyncStop() + } default: break } @@ -1072,12 +1076,12 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } } - private func startSync() { + private func startSync() async { guard let userSession else { return } analyticsService.signpost.startTransaction(.upToDateRoomList) - userSession.clientProxy.startSync() + await userSession.clientProxy.startSync() guard clientProxyObserver == nil else { return @@ -1180,7 +1184,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg private func applicationWillEnterForeground() { MXLog.info("Application will enter foreground") endActiveBackgroundTask() - startSync() + Task { + await startSync() + } } @objc @@ -1207,7 +1213,9 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg return } - self?.handleBackgroundAppRefresh(task) + Task { + await self?.handleBackgroundAppRefresh(task) + } } MXLog.info("Register background app refresh with result: \(result)") @@ -1228,7 +1236,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg } private var backgroundRefreshSyncObserver: AnyCancellable? - private func handleBackgroundAppRefresh(_ task: BGAppRefreshTask) { + private func handleBackgroundAppRefresh(_ task: BGAppRefreshTask) async { MXLog.info("Started background app refresh") // This is important for the app to keep refreshing in the background @@ -1255,7 +1263,7 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg return } - startSync() + await startSync() // Be a good citizen, run for a max of 10 SS responses or 10 seconds // An SS request will time out after 30 seconds if no new data is available diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index c4d60eaee..50dc1a50e 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -2462,11 +2462,11 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable { var startSyncCalled: Bool { return startSyncCallsCount > 0 } - var startSyncClosure: (() -> Void)? + var startSyncClosure: (() async -> Void)? - func startSync() { + func startSync() async { startSyncCallsCountLock.withLock { startSyncUnderlyingCallsCount += 1 } - startSyncClosure?() + await startSyncClosure?() } //MARK: - stopSync diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index fe2afd0d6..03742a158 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -389,7 +389,7 @@ class ClientProxy: ClientProxyProtocol { } } - func startSync() { + func startSync() async { guard !hasEncounteredAuthError else { MXLog.warning("Ignoring request, this client has an unknown token.") return @@ -400,23 +400,21 @@ class ClientProxy: ClientProxyProtocol { return } - MXLog.info("Starting sync") - - Task { - if appSettings.clientPausingAndResumingEnabled { - do { - try await client.resume() - } catch { - MXLog.error("Failed resuming client with error: \(error)") - } + if appSettings.clientPausingAndResumingEnabled { + do { + MXLog.info("Resuming client") + try await client.resume() + } catch { + MXLog.error("Failed resuming client with error: \(error)") } - - await syncService.start() - - // If we are using OAuth we want to cache the account management URL in volatile memory on the SDK side. - // To avoid the cache being invalidated while the app is backgrounded, we cache at every sync start. - await cacheAccountURL() } + + MXLog.info("Starting sync") + await syncService.start() + + // If we are using OAuth we want to cache the account management URL in volatile memory on the SDK side. + // To avoid the cache being invalidated while the app is backgrounded, we cache at every sync start. + await cacheAccountURL() } /// A stored task for restarting the sync after a failure. This is stored so that we can cancel @@ -432,7 +430,7 @@ class ClientProxy: ClientProxyProtocol { // Until the SDK can tell us the failure, we add a small // delay to avoid generating multi-gigabyte log files. try await Task.sleep(for: .milliseconds(250)) - self?.startSync() + await self?.startSync() } catch { MXLog.error("Restart cancelled.") } @@ -445,8 +443,6 @@ class ClientProxy: ClientProxyProtocol { } func stopSync(completion: (() -> Void)?) { - MXLog.info("Stopping sync") - if restartTask != nil { MXLog.warning("Removing the sync service restart task.") restartTask = nil @@ -461,17 +457,18 @@ class ClientProxy: ClientProxyProtocol { completion?() } + MXLog.info("Stopping sync") await syncService.stop() + MXLog.info("Sync stopped") if appSettings.clientPausingAndResumingEnabled { do { + MXLog.info("Pausing client") try await client.pause() } catch { MXLog.error("Failed pausing client with error: \(error)") } } - - MXLog.info("Sync stopped") } } @@ -1032,7 +1029,9 @@ class ClientProxy: ClientProxyProtocol { .receive(on: DispatchQueue.main) .sink { [weak self] reachability in if reachability == .reachable { - self?.startSync() + Task { + await self?.startSync() + } } } .store(in: &cancellables) diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index 06fd40f79..8e16c8df4 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -169,7 +169,7 @@ protocol ClientProxyProtocol: AnyObject { func hasDevicesToVerifyAgainst() async -> Result - func startSync() + func startSync() async func stopSync()