Update the SDK.

Handles changes that removed support for the sliding sync proxy.
This commit is contained in:
Doug
2025-02-18 10:34:32 +00:00
committed by Doug
parent f77faee981
commit 8c07ee35c4
33 changed files with 229 additions and 309 deletions
@@ -120,6 +120,7 @@
"action_yes" = "Yes";
"action_yes_try_again" = "Yes, try again";
"banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade";
"banner_migrate_to_native_sliding_sync_app_force_logout_title" = "Element X no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.";
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available";
@@ -120,6 +120,7 @@
"action_yes" = "Yes";
"action_yes_try_again" = "Yes, try again";
"banner_migrate_to_native_sliding_sync_action" = "Log Out & Upgrade";
"banner_migrate_to_native_sliding_sync_app_force_logout_title" = "Element X no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_description" = "Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.";
"banner_migrate_to_native_sliding_sync_force_logout_title" = "Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.";
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available";
@@ -44,7 +44,6 @@ final class AppSettings {
case elementCallBaseURLOverride
// Feature flags
case slidingSyncDiscovery
case publicSearchEnabled
case fuzzyRoomListSearchEnabled
case enableOnlySignedDeviceIsolationMode
@@ -283,10 +282,6 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.fuzzyRoomListSearchEnabled, defaultValue: false, storageType: .userDefaults(store))
var fuzzyRoomListSearchEnabled
enum SlidingSyncDiscovery: Codable { case proxy, native, forceNative }
@UserPreference(key: UserDefaultsKeys.slidingSyncDiscovery, defaultValue: .native, storageType: .userDefaults(store))
var slidingSyncDiscovery: SlidingSyncDiscovery
@UserPreference(key: UserDefaultsKeys.knockingEnabled, defaultValue: false, storageType: .userDefaults(store))
var knockingEnabled
@@ -230,7 +230,7 @@ class SettingsFlowCoordinator: FlowCoordinatorProtocol {
}
private func presentDeveloperOptions() {
let coordinator = DeveloperOptionsScreenCoordinator(isUsingNativeSlidingSync: parameters.userSession.clientProxy.slidingSyncVersion == .native)
let coordinator = DeveloperOptionsScreenCoordinator()
coordinator.actions
.sink { [weak self] action in
+2
View File
@@ -274,6 +274,8 @@ internal enum L10n {
internal static var actionYesTryAgain: String { return L10n.tr("Localizable", "action_yes_try_again") }
/// Log Out & Upgrade
internal static var bannerMigrateToNativeSlidingSyncAction: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_action") }
/// Element X no longer supports the old protocol. Please log out and log back in to continue using the app.
internal static var bannerMigrateToNativeSlidingSyncAppForceLogoutTitle: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_app_force_logout_title") }
/// Your server now supports a new, faster protocol. Log out and log back in to upgrade now. Doing this now will help you avoid a forced logout when the old protocol is removed later.
internal static var bannerMigrateToNativeSlidingSyncDescription: String { return L10n.tr("Localizable", "banner_migrate_to_native_sliding_sync_description") }
/// Your homeserver no longer supports the old protocol. Please log out and log back in to continue using the app.
+1 -3
View File
@@ -69,10 +69,8 @@ extension ClientProxyMock {
ignoreUserReturnValue = .success(())
unignoreUserReturnValue = .success(())
needsSlidingSyncMigration = false
slidingSyncVersion = .native
availableSlidingSyncVersionsClosure = {
[]
}
trackRecentlyVisitedRoomReturnValue = .success(())
recentlyVisitedRoomsReturnValue = .success([])
@@ -2235,28 +2235,16 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
set(value) { underlyingHomeserver = value }
}
var underlyingHomeserver: String!
var needsSlidingSyncMigration: Bool {
get { return underlyingNeedsSlidingSyncMigration }
set(value) { underlyingNeedsSlidingSyncMigration = value }
}
var underlyingNeedsSlidingSyncMigration: Bool!
var slidingSyncVersion: SlidingSyncVersion {
get { return underlyingSlidingSyncVersion }
set(value) { underlyingSlidingSyncVersion = value }
}
var underlyingSlidingSyncVersion: SlidingSyncVersion!
var availableSlidingSyncVersionsCallsCount = 0
var availableSlidingSyncVersionsCalled: Bool {
return availableSlidingSyncVersionsCallsCount > 0
}
var availableSlidingSyncVersions: [SlidingSyncVersion] {
get async {
availableSlidingSyncVersionsCallsCount += 1
if let availableSlidingSyncVersionsClosure = availableSlidingSyncVersionsClosure {
return await availableSlidingSyncVersionsClosure()
} else {
return underlyingAvailableSlidingSyncVersions
}
}
}
var underlyingAvailableSlidingSyncVersions: [SlidingSyncVersion]!
var availableSlidingSyncVersionsClosure: (() async -> [SlidingSyncVersion])?
var canDeactivateAccount: Bool {
get { return underlyingCanDeactivateAccount }
set(value) { underlyingCanDeactivateAccount = value }
@@ -27,9 +27,7 @@ extension ClientBuilder {
builder = switch slidingSync {
case .restored: builder
case .discoverProxy: builder.slidingSyncVersionBuilder(versionBuilder: .discoverProxy)
case .discoverNative: builder.slidingSyncVersionBuilder(versionBuilder: .discoverNative)
case .forceNative: builder.slidingSyncVersionBuilder(versionBuilder: .native)
case .discover: builder.slidingSyncVersionBuilder(versionBuilder: .discoverNative)
}
if setupEncryption {
@@ -58,12 +56,8 @@ extension ClientBuilder {
}
enum ClientBuilderSlidingSync {
/// The proxy will be supplied when restoring the Session.
/// Sliding sync will be configured when restoring the Session.
case restored
/// A proxy must be discovered whilst building the session.
case discoverProxy
/// Native sliding sync must be discovered whilst building the session.
case discoverNative
/// Forces native sliding sync without discovering it.
case forceNative
/// Sliding sync must be discovered whilst building the session.
case discover
}
@@ -36,8 +36,6 @@ enum HomeScreenViewAction {
case confirmRecoveryKey
case resetEncryption
case skipRecoveryKeyConfirmation
case confirmSlidingSyncUpgrade
case skipSlidingSyncUpgrade
case updateVisibleItemRange(Range<Int>)
case globalSearch
case markRoomAsUnread(roomIdentifier: String)
@@ -86,17 +84,12 @@ enum HomeScreenSecurityBannerMode: Equatable {
}
}
enum HomeScreenMigrationBannerMode {
case none, show, dismissed
}
struct HomeScreenViewState: BindableState {
let userID: String
var userDisplayName: String?
var userAvatarURL: URL?
var securityBannerMode = HomeScreenSecurityBannerMode.none
var slidingSyncMigrationBannerMode = HomeScreenMigrationBannerMode.none
var requiresExtraAccountSetup = false
@@ -145,11 +145,6 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
actionsSubject.send(.presentEncryptionResetScreen)
case .skipRecoveryKeyConfirmation:
state.securityBannerMode = .dismissed
case .confirmSlidingSyncUpgrade:
appSettings.slidingSyncDiscovery = .native
actionsSubject.send(.logout)
case .skipSlidingSyncUpgrade:
state.slidingSyncMigrationBannerMode = .dismissed
case .updateVisibleItemRange(let range):
roomSummaryProvider?.updateVisibleRange(range)
case .startChat:
@@ -307,30 +302,18 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
/// Check whether we can inform the user about potential migrations
/// or have him logout as his proxy is no longer available
private func checkSlidingSyncMigration() async {
// Not logged in with a proxy, don't need to do anything
guard userSession.clientProxy.slidingSyncVersion.isProxy else {
guard userSession.clientProxy.needsSlidingSyncMigration else {
return
}
let versions = await userSession.clientProxy.availableSlidingSyncVersions
// Native not available, nothing we can do
guard versions.contains(.native) else {
return
}
if versions.contains(where: \.isProxy) { // Both available, prompt for migration
state.slidingSyncMigrationBannerMode = .show
} else { // The proxy has been removed and logout is needed
// Delay setting the alert otherwise it automatically gets dismissed. Same as the crashed last run one
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.state.bindings.alertInfo = AlertInfo(id: UUID(),
title: L10n.bannerMigrateToNativeSlidingSyncForceLogoutTitle,
primaryButton: .init(title: L10n.bannerMigrateToNativeSlidingSyncAction) { [weak self] in
self?.appSettings.slidingSyncDiscovery = .native
self?.actionsSubject.send(.logoutWithoutConfirmation)
})
}
// The proxy is no longer supported so a logout is needed.
// Delay setting the alert otherwise it automatically gets dismissed. Same as the crashed last run one
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.state.bindings.alertInfo = AlertInfo(id: UUID(),
title: L10n.bannerMigrateToNativeSlidingSyncAppForceLogoutTitle,
primaryButton: .init(title: L10n.bannerMigrateToNativeSlidingSyncAction) { [weak self] in
self?.actionsSubject.send(.logoutWithoutConfirmation)
})
}
}
@@ -460,14 +443,3 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
message: L10n.errorUnknown)
}
}
extension SlidingSyncVersion {
var isProxy: Bool {
switch self {
case .proxy:
return true
default:
return false
}
}
}
@@ -119,17 +119,13 @@ struct HomeScreenContent: View {
@ViewBuilder
private var topSection: some View {
// An empty VStack causes glitches within the room list
if context.viewState.shouldShowFilters ||
context.viewState.securityBannerMode.isShown ||
context.viewState.slidingSyncMigrationBannerMode == .show {
if context.viewState.shouldShowFilters || context.viewState.securityBannerMode.isShown {
VStack(spacing: 0) {
if context.viewState.shouldShowFilters {
RoomListFiltersView(state: $context.filtersState)
}
if context.viewState.slidingSyncMigrationBannerMode == .show {
HomeScreenSlidingSyncMigrationBanner(context: context)
} else if case let .show(state) = context.viewState.securityBannerMode {
if case let .show(state) = context.viewState.securityBannerMode {
HomeScreenRecoveryKeyConfirmationBanner(state: state, context: context)
}
}
@@ -1,68 +0,0 @@
//
// Copyright 2024 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 SwiftUI
struct HomeScreenSlidingSyncMigrationBanner: View {
var context: HomeScreenViewModel.Context
var body: some View {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: 4) {
HStack(spacing: 16) {
Text(L10n.bannerMigrateToNativeSlidingSyncTitle)
.font(.compound.bodyLGSemibold)
.foregroundColor(.compound.textPrimary)
Spacer()
Button {
context.send(viewAction: .skipSlidingSyncUpgrade)
} label: {
Image(systemName: "xmark")
.foregroundColor(.compound.iconSecondary)
.frame(width: 12, height: 12)
}
}
Text(L10n.bannerMigrateToNativeSlidingSyncDescription)
.font(.compound.bodyMD)
.foregroundColor(.compound.textSecondary)
}
Button(L10n.bannerMigrateToNativeSlidingSyncAction) {
context.send(viewAction: .confirmSlidingSyncUpgrade)
}
.frame(maxWidth: .infinity)
.buttonStyle(.compound(.primary, size: .medium))
}
.padding(16)
.background(Color.compound.bgSubtleSecondary)
.cornerRadius(14)
.padding(.horizontal, 16)
}
}
struct HomeScreenSlidingSyncMigrationBanner_Previews: PreviewProvider, TestablePreview {
static let viewModel = buildViewModel()
static var previews: some View {
HomeScreenSlidingSyncMigrationBanner(context: viewModel.context)
}
static func buildViewModel() -> HomeScreenViewModel {
let clientProxy = ClientProxyMock(.init())
let userSession = UserSessionMock(.init(clientProxy: clientProxy))
return HomeScreenViewModel(userSession: userSession,
analyticsService: ServiceLocator.shared.analytics,
appSettings: ServiceLocator.shared.settings,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}
}
@@ -22,10 +22,9 @@ final class DeveloperOptionsScreenCoordinator: CoordinatorProtocol {
actionsSubject.eraseToAnyPublisher()
}
init(isUsingNativeSlidingSync: Bool) {
init() {
viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings,
elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL,
isUsingNativeSlidingSync: isUsingNativeSlidingSync)
elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL)
viewModel.actions
.sink { [weak self] action in
@@ -13,12 +13,7 @@ enum DeveloperOptionsScreenViewModelAction {
struct DeveloperOptionsScreenViewState: BindableState {
let elementCallBaseURL: URL
let isUsingNativeSlidingSync: Bool
var bindings: DeveloperOptionsScreenViewStateBindings
var slidingSyncFooter: String {
"The method used to configure sliding sync when signing in. Changing this setting has no effect until you sign out.\n\nYour current session is using \(isUsingNativeSlidingSync ? "native sliding sync." : "a sliding sync proxy.")"
}
}
// periphery: ignore - subscripts are seen as false positive
@@ -42,7 +37,6 @@ enum DeveloperOptionsScreenViewAction {
protocol DeveloperOptionsProtocol: AnyObject {
var logLevel: LogLevel { get set }
var slidingSyncDiscovery: AppSettings.SlidingSyncDiscovery { get set }
var publicSearchEnabled: Bool { get set }
var hideUnreadMessagesBadge: Bool { get set }
var fuzzyRoomListSearchEnabled: Bool { get set }
@@ -17,9 +17,9 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve
actionsSubject.eraseToAnyPublisher()
}
init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL, isUsingNativeSlidingSync: Bool) {
init(developerOptions: DeveloperOptionsProtocol, elementCallBaseURL: URL) {
let bindings = DeveloperOptionsScreenViewStateBindings(developerOptions: developerOptions)
let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, isUsingNativeSlidingSync: isUsingNativeSlidingSync, bindings: bindings)
let state = DeveloperOptionsScreenViewState(elementCallBaseURL: elementCallBaseURL, bindings: bindings)
super.init(initialViewState: state)
}
@@ -32,18 +32,6 @@ struct DeveloperOptionsScreen: View {
}
}
Section {
Picker("Discovery", selection: $context.slidingSyncDiscovery) {
Text("Proxy only").tag(AppSettings.SlidingSyncDiscovery.proxy)
Text("Automatic").tag(AppSettings.SlidingSyncDiscovery.native)
Text("Force Native ⚠️").tag(AppSettings.SlidingSyncDiscovery.forceNative)
}
} header: {
Text("Sliding Sync")
} footer: {
Text(context.viewState.slidingSyncFooter)
}
Section("Room List") {
Toggle(isOn: $context.publicSearchEnabled) {
Text("Public search")
@@ -175,8 +163,7 @@ private struct LogLevelConfigurationView: View {
struct DeveloperOptionsScreen_Previews: PreviewProvider {
static let viewModel = DeveloperOptionsScreenViewModel(developerOptions: ServiceLocator.shared.settings,
elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL,
isUsingNativeSlidingSync: true)
elementCallBaseURL: ServiceLocator.shared.settings.elementCallBaseURL)
static var previews: some View {
NavigationStack {
DeveloperOptionsScreen(context: viewModel.context)
@@ -27,55 +27,25 @@ struct AuthenticationClientBuilder: AuthenticationClientBuilderProtocol {
/// Builds a Client for login using OIDC or password authentication.
func build(homeserverAddress: String) async throws -> ClientProtocol {
if appSettings.slidingSyncDiscovery == .forceNative {
return try await makeClientBuilder(slidingSync: .forceNative).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
}
if appSettings.slidingSyncDiscovery == .native {
do {
return try await makeClientBuilder(slidingSync: .discoverNative).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
} catch {
MXLog.warning("Native sliding sync not available: \(error)")
MXLog.info("Falling back to a sliding sync proxy.")
}
}
return try await makeClientBuilder(slidingSync: .discoverProxy).serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
try await makeClientBuilder().serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress).build()
}
/// Builds a Client, authenticating with the given QR code data.
func buildWithQRCode(qrCodeData: QrCodeData,
oidcConfiguration: OIDCConfigurationProxy,
progressListener: QrLoginProgressListenerProxy) async throws -> ClientProtocol {
if appSettings.slidingSyncDiscovery == .forceNative {
return try await makeClientBuilder(slidingSync: .forceNative).buildWithQrCode(qrCodeData: qrCodeData,
oidcConfiguration: oidcConfiguration.rustValue,
progressListener: progressListener)
}
if appSettings.slidingSyncDiscovery == .native {
do {
return try await makeClientBuilder(slidingSync: .discoverNative).buildWithQrCode(qrCodeData: qrCodeData,
oidcConfiguration: oidcConfiguration.rustValue,
progressListener: progressListener)
} catch HumanQrLoginError.SlidingSyncNotAvailable {
MXLog.warning("Native sliding sync not available")
MXLog.info("Falling back to a sliding sync proxy.")
}
}
return try await makeClientBuilder(slidingSync: .discoverProxy).buildWithQrCode(qrCodeData: qrCodeData,
oidcConfiguration: oidcConfiguration.rustValue,
progressListener: progressListener)
try await makeClientBuilder().buildWithQrCode(qrCodeData: qrCodeData,
oidcConfiguration: oidcConfiguration.rustValue,
progressListener: progressListener)
}
// MARK: - Private
/// The base builder configuration used for authentication within the app.
private func makeClientBuilder(slidingSync: ClientBuilderSlidingSync) -> ClientBuilder {
private func makeClientBuilder() -> ClientBuilder {
ClientBuilder
.baseBuilder(httpProxy: appSettings.websiteURL.globalProxy,
slidingSync: slidingSync,
slidingSync: .discover,
sessionDelegate: clientSessionDelegate,
appHooks: appHooks,
enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode,
@@ -19,7 +19,7 @@ class ClientProxy: ClientProxyProtocol {
private let mediaLoader: MediaLoaderProtocol
private let clientQueue: DispatchQueue
private var roomListService: RoomListService?
// periphery: ignore - only for retain
private var roomListStateUpdateTaskHandle: TaskHandle?
@@ -135,6 +135,7 @@ class ClientProxy: ClientProxyProtocol {
private let sendQueueStatusSubject = CurrentValueSubject<Bool, Never>(false)
init(client: ClientProtocol,
needsSlidingSyncMigration: Bool,
networkMonitor: NetworkMonitorProtocol,
appSettings: AppSettings) async {
self.client = client
@@ -148,6 +149,8 @@ class ClientProxy: ClientProxyProtocol {
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings())
secureBackupController = SecureBackupController(encryption: client.encryption())
self.needsSlidingSyncMigration = needsSlidingSyncMigration
delegateHandle = client.setDelegate(delegate: ClientDelegateWrapper { [weak self] isSoftLogout in
self?.hasEncounteredAuthError = true
@@ -221,16 +224,11 @@ class ClientProxy: ClientProxyProtocol {
client.homeserver()
}
let needsSlidingSyncMigration: Bool
var slidingSyncVersion: SlidingSyncVersion {
client.slidingSyncVersion()
}
var availableSlidingSyncVersions: [SlidingSyncVersion] {
get async {
await client.availableSlidingSyncVersions()
}
}
var canDeactivateAccount: Bool {
client.canDeactivateAccount()
}
@@ -263,6 +261,11 @@ class ClientProxy: ClientProxyProtocol {
}
func startSync() {
guard !needsSlidingSyncMigration else {
MXLog.warning("Ignoring request, this client needs to be migrated to native sliding sync.")
return
}
guard !hasEncounteredAuthError else {
MXLog.warning("Ignoring request, this client has an unknown token.")
return
@@ -75,9 +75,11 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {
var deviceID: String? { get }
var homeserver: String { get }
// TODO: This is a temporary value, in the future we should throw a migration error
// when decoding a session that contains a sliding sync proxy URL instead of restoring it.
var needsSlidingSyncMigration: Bool { get }
var slidingSyncVersion: SlidingSyncVersion { get }
var availableSlidingSyncVersions: [SlidingSyncVersion] { get async }
var canDeactivateAccount: Bool { get }
@@ -112,7 +112,8 @@ class KeychainController: KeychainControllerProtocol {
let restorationToken = RestorationToken(session: session,
sessionDirectories: oldToken.sessionDirectories,
passphrase: oldToken.passphrase,
pusherNotificationClientIdentifier: oldToken.pusherNotificationClientIdentifier)
pusherNotificationClientIdentifier: oldToken.pusherNotificationClientIdentifier,
slidingSyncProxyURLString: oldToken.slidingSyncProxyURLString)
setRestorationToken(restorationToken, forUsername: session.userId)
}
@@ -14,6 +14,13 @@ struct RestorationToken: Equatable {
let passphrase: String?
let pusherNotificationClientIdentifier: String?
/// The sliding sync proxy URL that was previously encoded in the Session.
/// This is temporary to help make a nicer user migration flow. In the future
/// we will throw when decoding sessions with a sliding sync proxy URL.
let slidingSyncProxyURLString: String?
/// Whether the token is for a session that is using the now unsupported sliding sync proxy.
var needsSlidingSyncMigration: Bool { slidingSyncProxyURLString != nil }
enum CodingKeys: CodingKey {
case session
case sessionDirectory
@@ -27,7 +34,7 @@ extension RestorationToken: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let session = try container.decode(MatrixRustSDK.Session.self, forKey: .session)
let sessionWrapper = try container.decode(SessionWrapper.self, forKey: .session)
let dataDirectory = try container.decodeIfPresent(URL.self, forKey: .sessionDirectory)
let cacheDirectory = try container.decodeIfPresent(URL.self, forKey: .cacheDirectory)
@@ -38,18 +45,19 @@ extension RestorationToken: Codable {
SessionDirectories(dataDirectory: dataDirectory)
}
} else {
SessionDirectories(userID: session.userId)
SessionDirectories(userID: sessionWrapper.session.userId)
}
self = try .init(session: session,
self = try .init(session: sessionWrapper.session,
sessionDirectories: sessionDirectories,
passphrase: container.decodeIfPresent(String.self, forKey: .passphrase),
pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier))
pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier),
slidingSyncProxyURLString: sessionWrapper.slidingSyncProxyURLString)
}
func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(session, forKey: .session)
try container.encode(SessionWrapper(session: session, slidingSyncProxyURLString: slidingSyncProxyURLString), forKey: .session)
try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory)
try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory)
try container.encode(passphrase, forKey: .passphrase)
@@ -57,17 +65,40 @@ extension RestorationToken: Codable {
}
}
/// Temporary struct to smooth the forced migration by keeping a user session.
/// In the future we can remove this and throw a migration error when the URL
/// is decoded to a non-nil value.
private struct SessionWrapper {
let session: MatrixRustSDK.Session
let slidingSyncProxyURLString: String?
}
extension SessionWrapper: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: MatrixRustSDK.Session.CodingKeys.self)
session = try Session(from: decoder)
// TODO: In the future we should decode this in the Session and throw a migration error if it contains a value.
slidingSyncProxyURLString = try container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: MatrixRustSDK.Session.CodingKeys.self)
try session.encode(to: encoder)
try container.encode(slidingSyncProxyURLString, forKey: .slidingSyncProxy)
}
}
extension MatrixRustSDK.Session: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let slidingSyncProxy = try container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)
self = try .init(accessToken: container.decode(String.self, forKey: .accessToken),
refreshToken: container.decodeIfPresent(String.self, forKey: .refreshToken),
userId: container.decode(String.self, forKey: .userId),
deviceId: container.decode(String.self, forKey: .deviceId),
homeserverUrl: container.decode(String.self, forKey: .homeserverUrl),
oidcData: container.decodeIfPresent(String.self, forKey: .oidcData),
slidingSyncVersion: slidingSyncProxy.map { .proxy(url: $0) } ?? .native)
slidingSyncVersion: .native)
}
public func encode(to encoder: Encoder) throws {
@@ -78,17 +109,9 @@ extension MatrixRustSDK.Session: Codable {
try container.encode(deviceId, forKey: .deviceId)
try container.encode(homeserverUrl, forKey: .homeserverUrl)
try container.encode(oidcData, forKey: .oidcData)
try container.encode(slidingSyncVersion.proxyURL, forKey: .slidingSyncProxy)
}
enum CodingKeys: String, CodingKey {
case accessToken, refreshToken, userId, deviceId, homeserverUrl, oidcData, slidingSyncProxy
}
}
private extension SlidingSyncVersion {
var proxyURL: String? {
guard case let .proxy(url) = self else { return nil }
return url
}
}
@@ -64,12 +64,13 @@ class UserSessionStore: UserSessionStoreProtocol {
do {
let session = try client.session()
let userID = try client.userId()
let clientProxy = await setupProxyForClient(client)
let clientProxy = await setupProxyForClient(client, needsSlidingSyncMigration: false)
keychainController.setRestorationToken(RestorationToken(session: session,
sessionDirectories: sessionDirectories,
passphrase: passphrase,
pusherNotificationClientIdentifier: clientProxy.pusherNotificationClientIdentifier),
pusherNotificationClientIdentifier: clientProxy.pusherNotificationClientIdentifier,
slidingSyncProxyURLString: nil),
forUsername: userID)
MXLog.info("Set up session for user \(userID) at: \(sessionDirectories)")
@@ -145,15 +146,16 @@ class UserSessionStore: UserSessionStoreProtocol {
MXLog.info("Set up session for user \(credentials.userID) at: \(credentials.restorationToken.sessionDirectories)")
return await .success(setupProxyForClient(client))
return await .success(setupProxyForClient(client, needsSlidingSyncMigration: credentials.restorationToken.needsSlidingSyncMigration))
} catch {
MXLog.error("Failed restoring login with error: \(error)")
return .failure(.failedRestoringLogin)
}
}
private func setupProxyForClient(_ client: ClientProtocol) async -> ClientProxyProtocol {
private func setupProxyForClient(_ client: ClientProtocol, needsSlidingSyncMigration: Bool) async -> ClientProxyProtocol {
await ClientProxy(client: client,
needsSlidingSyncMigration: needsSlidingSyncMigration,
networkMonitor: networkMonitor,
appSettings: appSettings)
}