// // Copyright 2025 Element Creations Ltd. // Copyright 2022-2025 New Vector Ltd. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. // Please see LICENSE files in the repository root for full details. // import Combine import Foundation class UserSession: UserSessionProtocol { private var cancellables = Set() private var authErrorCancellable: AnyCancellable? let clientProxy: ClientProxyProtocol let mediaProvider: MediaProviderProtocol let voiceMessageMediaManager: VoiceMessageMediaManagerProtocol let liveLocationManager: LiveLocationManagerProtocol let callbacks = PassthroughSubject() let sessionSecurityStateSubject = CurrentValueSubject(.init(verificationState: .unknown, recoveryState: .unknown)) var sessionSecurityStatePublisher: CurrentValuePublisher { sessionSecurityStateSubject.asCurrentValuePublisher() } init(clientProxy: ClientProxyProtocol, mediaProvider: MediaProviderProtocol, voiceMessageMediaManager: VoiceMessageMediaManagerProtocol, liveLocationManager: LiveLocationManagerProtocol) { self.clientProxy = clientProxy self.mediaProvider = mediaProvider self.voiceMessageMediaManager = voiceMessageMediaManager self.liveLocationManager = liveLocationManager authErrorCancellable = clientProxy.actionsPublisher .receive(on: DispatchQueue.main) .sink { [weak self] callback in guard let self else { return } switch callback { case .receivedAuthError(let isSoftLogout): callbacks.send(.didReceiveAuthError(isSoftLogout: isSoftLogout)) authErrorCancellable = nil default: break } } Publishers.CombineLatest(clientProxy.verificationStatePublisher, clientProxy.secureBackupController.recoveryState) .map { MXLog.info("Session security state changed, verificationState: \($0), recoveryState: \($1)") return SessionSecurityState(verificationState: $0, recoveryState: $1) } .receive(on: DispatchQueue.main) .sink { [weak self] value in self?.sessionSecurityStateSubject.send(value) } .store(in: &cancellables) } }