Merge pull request #3886 from element-hq/feature/bma/fixSendQueueCrash
fix : protect some usages of client to avoid crashes
This commit is contained in:
commit
126181a8b2
14 changed files with 156 additions and 111 deletions
|
|
@ -28,6 +28,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||||
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
|
import io.element.android.libraries.preferences.api.store.EnableNativeSlidingSyncUseCase
|
||||||
|
|
@ -102,10 +103,7 @@ class LoggedInPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch {
|
LoggedInEvents.CheckSlidingSyncProxyAvailability -> coroutineScope.launch {
|
||||||
// Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is.
|
forceNativeSlidingSyncMigration = matrixClient.forceNativeSlidingSyncMigration().getOrDefault(false)
|
||||||
forceNativeSlidingSyncMigration = !matrixClient.isUsingNativeSlidingSync() &&
|
|
||||||
matrixClient.isNativeSlidingSyncSupported() &&
|
|
||||||
!matrixClient.isSlidingSyncProxySupported()
|
|
||||||
}
|
}
|
||||||
LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch {
|
LoggedInEvents.LogoutAndMigrateToNativeSlidingSync -> coroutineScope.launch {
|
||||||
// Enable native sliding sync if it wasn't already the case
|
// Enable native sliding sync if it wasn't already the case
|
||||||
|
|
@ -125,6 +123,18 @@ class LoggedInPresenter @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Force the user to log out if they were using the proxy sliding sync and it's no longer available, but native sliding sync is.
|
||||||
|
private suspend fun MatrixClient.forceNativeSlidingSyncMigration(): Result<Boolean> = runCatching {
|
||||||
|
val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow()
|
||||||
|
if (currentSlidingSyncVersion == SlidingSyncVersion.Proxy) {
|
||||||
|
val availableSlidingSyncVersions = availableSlidingSyncVersions().getOrThrow()
|
||||||
|
availableSlidingSyncVersions.contains(SlidingSyncVersion.Native) &&
|
||||||
|
!availableSlidingSyncVersions.contains(SlidingSyncVersion.Proxy)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {
|
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {
|
||||||
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
|
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
|
||||||
val currentPushProvider = pushService.getCurrentPushProvider()
|
val currentPushProvider = pushService.getCurrentPushProvider()
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
|
|
@ -501,9 +502,8 @@ class LoggedInPresenterTest {
|
||||||
// - The sliding sync proxy is no longer supported
|
// - The sliding sync proxy is no longer supported
|
||||||
// - The native sliding sync is supported
|
// - The native sliding sync is supported
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
isUsingNativeSlidingSyncLambda = { false },
|
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
|
||||||
isSlidingSyncProxySupportedLambda = { false },
|
availableSlidingSyncVersionsLambda = { Result.success(listOf(SlidingSyncVersion.Native)) },
|
||||||
isNativeSlidingSyncSupportedLambda = { true },
|
|
||||||
)
|
)
|
||||||
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
|
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
|
@ -521,9 +521,8 @@ class LoggedInPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest {
|
fun `present - CheckSlidingSyncProxyAvailability will not force the migration if native sliding sync is not supported too`() = runTest {
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
isUsingNativeSlidingSyncLambda = { false },
|
currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
|
||||||
isSlidingSyncProxySupportedLambda = { false },
|
availableSlidingSyncVersionsLambda = { Result.success(emptyList()) },
|
||||||
isNativeSlidingSyncSupportedLambda = { false },
|
|
||||||
)
|
)
|
||||||
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
|
val presenter = createLoggedInPresenter(matrixClient = matrixClient)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ import io.element.android.features.roomlist.impl.search.RoomListSearchEvents
|
||||||
import io.element.android.features.roomlist.impl.search.RoomListSearchState
|
import io.element.android.features.roomlist.impl.search.RoomListSearchState
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.bool.orFalse
|
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
import io.element.android.libraries.designsystem.utils.snackbar.collectSnackbarMessageAsState
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
|
|
@ -51,6 +50,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
import io.element.android.libraries.matrix.api.encryption.RecoveryState
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
||||||
|
|
@ -231,10 +231,7 @@ class RoomListPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val needsSlidingSyncMigration by produceState(false) {
|
val needsSlidingSyncMigration by produceState(false) {
|
||||||
value = runCatching {
|
value = client.needsSlidingSyncMigration().getOrDefault(false)
|
||||||
// Note: this can fail when the session is destroyed from another client.
|
|
||||||
client.isNativeSlidingSyncSupported() && !client.isUsingNativeSlidingSync()
|
|
||||||
}.getOrNull().orFalse()
|
|
||||||
}
|
}
|
||||||
val securityBannerState by rememberSecurityBannerState(securityBannerDismissed, needsSlidingSyncMigration)
|
val securityBannerState by rememberSecurityBannerState(securityBannerDismissed, needsSlidingSyncMigration)
|
||||||
return when {
|
return when {
|
||||||
|
|
@ -315,6 +312,19 @@ class RoomListPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the user needs to migrate to a native sliding sync version.
|
||||||
|
*/
|
||||||
|
private suspend fun MatrixClient.needsSlidingSyncMigration(): Result<Boolean> = runCatching {
|
||||||
|
val currentSlidingSyncVersion = currentSlidingSyncVersion().getOrThrow()
|
||||||
|
if (currentSlidingSyncVersion != SlidingSyncVersion.Native) {
|
||||||
|
val availableSlidingSyncVersions = availableSlidingSyncVersions().getOrThrow()
|
||||||
|
availableSlidingSyncVersions.contains(SlidingSyncVersion.Native)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var currentUpdateVisibleRangeJob: Job? = null
|
private var currentUpdateVisibleRangeJob: Job? = null
|
||||||
private fun CoroutineScope.updateVisibleRange(range: IntRange) {
|
private fun CoroutineScope.updateVisibleRange(range: IntRange) {
|
||||||
currentUpdateVisibleRangeJob?.cancel()
|
currentUpdateVisibleRangeJob?.cancel()
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
|
@ -145,14 +146,15 @@ interface MatrixClient : Closeable {
|
||||||
suspend fun getUrl(url: String): Result<String>
|
suspend fun getUrl(url: String): Result<String>
|
||||||
suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo>
|
suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo>
|
||||||
|
|
||||||
/** Returns `true` if the home server supports native sliding sync. */
|
/**
|
||||||
suspend fun isNativeSlidingSyncSupported(): Boolean
|
* Returns the currently used sliding sync version.
|
||||||
|
*/
|
||||||
|
suspend fun currentSlidingSyncVersion(): Result<SlidingSyncVersion>
|
||||||
|
|
||||||
/** Returns `true` if the home server supports sliding sync using a proxy. */
|
/**
|
||||||
suspend fun isSlidingSyncProxySupported(): Boolean
|
* Returns the available sliding sync versions for the current user.
|
||||||
|
*/
|
||||||
/** Returns `true` if the current session is using native sliding sync, `false` if it's using a proxy. */
|
suspend fun availableSlidingSyncVersions(): Result<List<SlidingSyncVersion>>
|
||||||
fun isUsingNativeSlidingSync(): Boolean
|
|
||||||
|
|
||||||
fun canDeactivateAccount(): Boolean
|
fun canDeactivateAccount(): Boolean
|
||||||
suspend fun deactivateAccount(password: String, eraseData: Boolean): Result<Unit>
|
suspend fun deactivateAccount(password: String, eraseData: Boolean): Result<Unit>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.api.sync
|
||||||
|
|
||||||
|
sealed interface SlidingSyncVersion {
|
||||||
|
data object None : SlidingSyncVersion
|
||||||
|
data object Proxy : SlidingSyncVersion
|
||||||
|
data object Native : SlidingSyncVersion
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ import io.element.android.libraries.androidutils.file.safeDelete
|
||||||
import io.element.android.libraries.core.bool.orFalse
|
import io.element.android.libraries.core.bool.orFalse
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.core.coroutine.childScope
|
import io.element.android.libraries.core.coroutine.childScope
|
||||||
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||||
|
|
@ -41,6 +42,7 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||||
|
|
@ -62,6 +64,7 @@ import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryS
|
||||||
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
|
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
|
||||||
import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService
|
import io.element.android.libraries.matrix.impl.roomlist.RustRoomListService
|
||||||
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
||||||
|
import io.element.android.libraries.matrix.impl.sync.map
|
||||||
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
||||||
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
|
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
|
||||||
import io.element.android.libraries.matrix.impl.util.SessionPathsProvider
|
import io.element.android.libraries.matrix.impl.util.SessionPathsProvider
|
||||||
|
|
@ -100,7 +103,6 @@ import org.matrix.rustcomponents.sdk.IgnoredUsersListener
|
||||||
import org.matrix.rustcomponents.sdk.NotificationProcessSetup
|
import org.matrix.rustcomponents.sdk.NotificationProcessSetup
|
||||||
import org.matrix.rustcomponents.sdk.PowerLevels
|
import org.matrix.rustcomponents.sdk.PowerLevels
|
||||||
import org.matrix.rustcomponents.sdk.SendQueueRoomErrorListener
|
import org.matrix.rustcomponents.sdk.SendQueueRoomErrorListener
|
||||||
import org.matrix.rustcomponents.sdk.SlidingSyncVersion
|
|
||||||
import org.matrix.rustcomponents.sdk.TaskHandle
|
import org.matrix.rustcomponents.sdk.TaskHandle
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -116,44 +118,44 @@ import org.matrix.rustcomponents.sdk.RoomVisibility as RustRoomVisibility
|
||||||
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
|
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
|
||||||
|
|
||||||
class RustMatrixClient(
|
class RustMatrixClient(
|
||||||
private val client: Client,
|
private val innerClient: Client,
|
||||||
private val baseDirectory: File,
|
private val baseDirectory: File,
|
||||||
private val sessionStore: SessionStore,
|
private val sessionStore: SessionStore,
|
||||||
private val appCoroutineScope: CoroutineScope,
|
private val appCoroutineScope: CoroutineScope,
|
||||||
private val sessionDelegate: RustClientSessionDelegate,
|
private val sessionDelegate: RustClientSessionDelegate,
|
||||||
syncService: ClientSyncService,
|
innerSyncService: ClientSyncService,
|
||||||
dispatchers: CoroutineDispatchers,
|
dispatchers: CoroutineDispatchers,
|
||||||
baseCacheDirectory: File,
|
baseCacheDirectory: File,
|
||||||
clock: SystemClock,
|
clock: SystemClock,
|
||||||
timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
|
timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
|
||||||
featureFlagService: FeatureFlagService,
|
featureFlagService: FeatureFlagService,
|
||||||
) : MatrixClient {
|
) : MatrixClient {
|
||||||
override val sessionId: UserId = UserId(client.userId())
|
override val sessionId: UserId = UserId(innerClient.userId())
|
||||||
override val deviceId: DeviceId = DeviceId(client.deviceId())
|
override val deviceId: DeviceId = DeviceId(innerClient.deviceId())
|
||||||
override val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-$sessionId")
|
override val sessionCoroutineScope = appCoroutineScope.childScope(dispatchers.main, "Session-$sessionId")
|
||||||
|
|
||||||
private val innerRoomListService = syncService.roomListService()
|
|
||||||
private val sessionDispatcher = dispatchers.io.limitedParallelism(64)
|
private val sessionDispatcher = dispatchers.io.limitedParallelism(64)
|
||||||
|
|
||||||
private val rustSyncService = RustSyncService(syncService, sessionCoroutineScope)
|
private val innerRoomListService = innerSyncService.roomListService()
|
||||||
|
|
||||||
|
private val rustSyncService = RustSyncService(innerSyncService, sessionCoroutineScope)
|
||||||
private val pushersService = RustPushersService(
|
private val pushersService = RustPushersService(
|
||||||
client = client,
|
client = innerClient,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(syncService)
|
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(innerSyncService)
|
||||||
private val notificationClient = runBlocking { client.notificationClient(notificationProcessSetup) }
|
private val innerNotificationClient = runBlocking { innerClient.notificationClient(notificationProcessSetup) }
|
||||||
private val notificationService = RustNotificationService(notificationClient, dispatchers, clock)
|
private val notificationService = RustNotificationService(innerNotificationClient, dispatchers, clock)
|
||||||
private val notificationSettingsService = RustNotificationSettingsService(client, dispatchers)
|
private val notificationSettingsService = RustNotificationSettingsService(innerClient, dispatchers)
|
||||||
.apply { start() }
|
.apply { start() }
|
||||||
private val encryptionService = RustEncryptionService(
|
private val encryptionService = RustEncryptionService(
|
||||||
client = client,
|
client = innerClient,
|
||||||
syncService = rustSyncService,
|
syncService = rustSyncService,
|
||||||
sessionCoroutineScope = sessionCoroutineScope,
|
sessionCoroutineScope = sessionCoroutineScope,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val roomDirectoryService = RustRoomDirectoryService(
|
private val roomDirectoryService = RustRoomDirectoryService(
|
||||||
client = client,
|
client = innerClient,
|
||||||
sessionDispatcher = sessionDispatcher,
|
sessionDispatcher = sessionDispatcher,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -173,13 +175,12 @@ class RustMatrixClient(
|
||||||
)
|
)
|
||||||
|
|
||||||
private val verificationService = RustSessionVerificationService(
|
private val verificationService = RustSessionVerificationService(
|
||||||
client = client,
|
client = innerClient,
|
||||||
isSyncServiceReady = rustSyncService.syncState.map { it == SyncState.Running },
|
isSyncServiceReady = rustSyncService.syncState.map { it == SyncState.Running },
|
||||||
sessionCoroutineScope = sessionCoroutineScope,
|
sessionCoroutineScope = sessionCoroutineScope,
|
||||||
)
|
)
|
||||||
|
|
||||||
private val roomMembershipObserver = RoomMembershipObserver()
|
private val roomMembershipObserver = RoomMembershipObserver()
|
||||||
|
|
||||||
private val roomFactory = RustRoomFactory(
|
private val roomFactory = RustRoomFactory(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
innerRoomListService = innerRoomListService,
|
innerRoomListService = innerRoomListService,
|
||||||
|
|
@ -199,24 +200,24 @@ class RustMatrixClient(
|
||||||
override val mediaLoader: MatrixMediaLoader = RustMediaLoader(
|
override val mediaLoader: MatrixMediaLoader = RustMediaLoader(
|
||||||
baseCacheDirectory = baseCacheDirectory,
|
baseCacheDirectory = baseCacheDirectory,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
innerClient = client,
|
innerClient = innerClient,
|
||||||
)
|
)
|
||||||
|
|
||||||
private var clientDelegateTaskHandle: TaskHandle? = client.setDelegate(sessionDelegate)
|
private var clientDelegateTaskHandle: TaskHandle? = innerClient.setDelegate(sessionDelegate)
|
||||||
|
|
||||||
private val _userProfile: MutableStateFlow<MatrixUser> = MutableStateFlow(
|
private val _userProfile: MutableStateFlow<MatrixUser> = MutableStateFlow(
|
||||||
MatrixUser(
|
MatrixUser(
|
||||||
userId = sessionId,
|
userId = sessionId,
|
||||||
// TODO cache for displayName?
|
// TODO cache for displayName?
|
||||||
displayName = null,
|
displayName = null,
|
||||||
avatarUrl = client.cachedAvatarUrl(),
|
avatarUrl = innerClient.cachedAvatarUrl(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
override val userProfile: StateFlow<MatrixUser> = _userProfile
|
override val userProfile: StateFlow<MatrixUser> = _userProfile
|
||||||
|
|
||||||
override val ignoredUsersFlow = mxCallbackFlow<ImmutableList<UserId>> {
|
override val ignoredUsersFlow = mxCallbackFlow<ImmutableList<UserId>> {
|
||||||
client.subscribeToIgnoredUsers(object : IgnoredUsersListener {
|
innerClient.subscribeToIgnoredUsers(object : IgnoredUsersListener {
|
||||||
override fun call(ignoredUserIds: List<String>) {
|
override fun call(ignoredUserIds: List<String>) {
|
||||||
channel.trySend(ignoredUserIds.map(::UserId).toPersistentList())
|
channel.trySend(ignoredUserIds.map(::UserId).toPersistentList())
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +238,7 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override fun userIdServerName(): String {
|
override fun userIdServerName(): String {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
client.userIdServerName()
|
innerClient.userIdServerName()
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
Timber.w(it, "Failed to get userIdServerName")
|
Timber.w(it, "Failed to get userIdServerName")
|
||||||
|
|
@ -248,7 +249,7 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override suspend fun getUrl(url: String): Result<String> = withContext(sessionDispatcher) {
|
override suspend fun getUrl(url: String): Result<String> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.getUrl(url)
|
innerClient.getUrl(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,23 +279,23 @@ class RustMatrixClient(
|
||||||
.filter { roomSummary -> roomSummary.info.currentUserMembership == currentUserMembership }
|
.filter { roomSummary -> roomSummary.info.currentUserMembership == currentUserMembership }
|
||||||
.first()
|
.first()
|
||||||
// Ensure that the room is ready
|
// Ensure that the room is ready
|
||||||
.also { client.awaitRoomRemoteEcho(it.roomId.value) }
|
.also { innerClient.awaitRoomRemoteEcho(it.roomId.value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findDM(userId: UserId): RoomId? {
|
override suspend fun findDM(userId: UserId): RoomId? {
|
||||||
return client.getDmRoom(userId.value)?.use { RoomId(it.id()) }
|
return innerClient.getDmRoom(userId.value)?.use { RoomId(it.id()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ignoreUser(userId: UserId): Result<Unit> = withContext(sessionDispatcher) {
|
override suspend fun ignoreUser(userId: UserId): Result<Unit> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.ignoreUser(userId.value)
|
innerClient.ignoreUser(userId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun unignoreUser(userId: UserId): Result<Unit> = withContext(sessionDispatcher) {
|
override suspend fun unignoreUser(userId: UserId): Result<Unit> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.unignoreUser(userId.value)
|
innerClient.unignoreUser(userId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -337,7 +338,7 @@ class RustMatrixClient(
|
||||||
},
|
},
|
||||||
canonicalAlias = createRoomParams.roomAliasName.getOrNull(),
|
canonicalAlias = createRoomParams.roomAliasName.getOrNull(),
|
||||||
)
|
)
|
||||||
val roomId = RoomId(client.createRoom(rustParams))
|
val roomId = RoomId(innerClient.createRoom(rustParams))
|
||||||
// Wait to receive the room back from the sync but do not returns failure if it fails.
|
// Wait to receive the room back from the sync but do not returns failure if it fails.
|
||||||
try {
|
try {
|
||||||
awaitRoom(roomId.toRoomIdOrAlias(), 30.seconds, CurrentUserMembership.JOINED)
|
awaitRoom(roomId.toRoomIdOrAlias(), 30.seconds, CurrentUserMembership.JOINED)
|
||||||
|
|
@ -362,7 +363,7 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override suspend fun getProfile(userId: UserId): Result<MatrixUser> = withContext(sessionDispatcher) {
|
override suspend fun getProfile(userId: UserId): Result<MatrixUser> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.getProfile(userId.value).let(UserProfileMapper::map)
|
innerClient.getProfile(userId.value).let(UserProfileMapper::map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -372,28 +373,28 @@ class RustMatrixClient(
|
||||||
override suspend fun searchUsers(searchTerm: String, limit: Long): Result<MatrixSearchUserResults> =
|
override suspend fun searchUsers(searchTerm: String, limit: Long): Result<MatrixSearchUserResults> =
|
||||||
withContext(sessionDispatcher) {
|
withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.searchUsers(searchTerm, limit.toULong()).let(UserSearchResultMapper::map)
|
innerClient.searchUsers(searchTerm, limit.toULong()).let(UserSearchResultMapper::map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setDisplayName(displayName: String): Result<Unit> =
|
override suspend fun setDisplayName(displayName: String): Result<Unit> =
|
||||||
withContext(sessionDispatcher) {
|
withContext(sessionDispatcher) {
|
||||||
runCatching { client.setDisplayName(displayName) }
|
runCatching { innerClient.setDisplayName(displayName) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun uploadAvatar(mimeType: String, data: ByteArray): Result<Unit> =
|
override suspend fun uploadAvatar(mimeType: String, data: ByteArray): Result<Unit> =
|
||||||
withContext(sessionDispatcher) {
|
withContext(sessionDispatcher) {
|
||||||
runCatching { client.uploadAvatar(mimeType, data) }
|
runCatching { innerClient.uploadAvatar(mimeType, data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun removeAvatar(): Result<Unit> =
|
override suspend fun removeAvatar(): Result<Unit> =
|
||||||
withContext(sessionDispatcher) {
|
withContext(sessionDispatcher) {
|
||||||
runCatching { client.removeAvatar() }
|
runCatching { innerClient.removeAvatar() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun joinRoom(roomId: RoomId): Result<RoomSummary?> = withContext(sessionDispatcher) {
|
override suspend fun joinRoom(roomId: RoomId): Result<RoomSummary?> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.joinRoomById(roomId.value).destroy()
|
innerClient.joinRoomById(roomId.value).destroy()
|
||||||
try {
|
try {
|
||||||
awaitRoom(roomId.toRoomIdOrAlias(), 10.seconds, CurrentUserMembership.JOINED)
|
awaitRoom(roomId.toRoomIdOrAlias(), 10.seconds, CurrentUserMembership.JOINED)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
@ -405,7 +406,7 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomSummary?> = withContext(sessionDispatcher) {
|
override suspend fun joinRoomByIdOrAlias(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomSummary?> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.joinRoomByIdOrAlias(
|
innerClient.joinRoomByIdOrAlias(
|
||||||
roomIdOrAlias = roomIdOrAlias.identifier,
|
roomIdOrAlias = roomIdOrAlias.identifier,
|
||||||
serverNames = serverNames,
|
serverNames = serverNames,
|
||||||
).destroy()
|
).destroy()
|
||||||
|
|
@ -422,7 +423,7 @@ class RustMatrixClient(
|
||||||
sessionDispatcher
|
sessionDispatcher
|
||||||
) {
|
) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.knock(roomIdOrAlias.identifier, message, serverNames).destroy()
|
innerClient.knock(roomIdOrAlias.identifier, message, serverNames).destroy()
|
||||||
try {
|
try {
|
||||||
awaitRoom(roomIdOrAlias, 10.seconds, CurrentUserMembership.KNOCKED)
|
awaitRoom(roomIdOrAlias, 10.seconds, CurrentUserMembership.KNOCKED)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
@ -434,19 +435,19 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit> = withContext(sessionDispatcher) {
|
override suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.trackRecentlyVisitedRoom(roomId.value)
|
innerClient.trackRecentlyVisitedRoom(roomId.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> = withContext(sessionDispatcher) {
|
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.getRecentlyVisitedRooms().map(::RoomId)
|
innerClient.getRecentlyVisitedRooms().map(::RoomId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result<Optional<ResolvedRoomAlias>> = withContext(sessionDispatcher) {
|
override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result<Optional<ResolvedRoomAlias>> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val result = client.resolveRoomAlias(roomAlias.value)?.let {
|
val result = innerClient.resolveRoomAlias(roomAlias.value)?.let {
|
||||||
ResolvedRoomAlias(
|
ResolvedRoomAlias(
|
||||||
roomId = RoomId(it.roomId),
|
roomId = RoomId(it.roomId),
|
||||||
servers = it.servers,
|
servers = it.servers,
|
||||||
|
|
@ -459,8 +460,8 @@ class RustMatrixClient(
|
||||||
override suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo> = withContext(sessionDispatcher) {
|
override suspend fun getRoomPreviewInfo(roomIdOrAlias: RoomIdOrAlias, serverNames: List<String>): Result<RoomPreviewInfo> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
when (roomIdOrAlias) {
|
when (roomIdOrAlias) {
|
||||||
is RoomIdOrAlias.Alias -> client.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value)
|
is RoomIdOrAlias.Alias -> innerClient.getRoomPreviewFromRoomAlias(roomIdOrAlias.roomAlias.value)
|
||||||
is RoomIdOrAlias.Id -> client.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames)
|
is RoomIdOrAlias.Id -> innerClient.getRoomPreviewFromRoomId(roomIdOrAlias.roomId.value, serverNames)
|
||||||
}.use { roomPreview ->
|
}.use { roomPreview ->
|
||||||
RoomPreviewInfoMapper.map(roomPreview.info())
|
RoomPreviewInfoMapper.map(roomPreview.info())
|
||||||
}
|
}
|
||||||
|
|
@ -490,11 +491,6 @@ class RustMatrixClient(
|
||||||
clientDelegateTaskHandle?.cancelAndDestroy()
|
clientDelegateTaskHandle?.cancelAndDestroy()
|
||||||
notificationSettingsService.destroy()
|
notificationSettingsService.destroy()
|
||||||
verificationService.destroy()
|
verificationService.destroy()
|
||||||
innerRoomListService.destroy()
|
|
||||||
notificationClient.destroy()
|
|
||||||
notificationProcessSetup.destroy()
|
|
||||||
encryptionService.destroy()
|
|
||||||
client.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getCacheSize(): Long {
|
override suspend fun getCacheSize(): Long {
|
||||||
|
|
@ -514,13 +510,13 @@ class RustMatrixClient(
|
||||||
withContext(sessionDispatcher) {
|
withContext(sessionDispatcher) {
|
||||||
if (userInitiated) {
|
if (userInitiated) {
|
||||||
try {
|
try {
|
||||||
result = client.logout()
|
result = innerClient.logout()
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
if (ignoreSdkError) {
|
if (ignoreSdkError) {
|
||||||
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
|
Timber.e(failure, "Fail to call logout on HS. Still delete local files.")
|
||||||
} else {
|
} else {
|
||||||
// If the logout failed we need to restore the delegate
|
// If the logout failed we need to restore the delegate
|
||||||
clientDelegateTaskHandle = client.setDelegate(sessionDelegate)
|
clientDelegateTaskHandle = innerClient.setDelegate(sessionDelegate)
|
||||||
Timber.e(failure, "Fail to call logout on HS.")
|
Timber.e(failure, "Fail to call logout on HS.")
|
||||||
throw failure
|
throw failure
|
||||||
}
|
}
|
||||||
|
|
@ -538,7 +534,7 @@ class RustMatrixClient(
|
||||||
|
|
||||||
override fun canDeactivateAccount(): Boolean {
|
override fun canDeactivateAccount(): Boolean {
|
||||||
return runCatching {
|
return runCatching {
|
||||||
client.canDeactivateAccount()
|
innerClient.canDeactivateAccount()
|
||||||
}
|
}
|
||||||
.getOrNull()
|
.getOrNull()
|
||||||
.orFalse()
|
.orFalse()
|
||||||
|
|
@ -552,7 +548,7 @@ class RustMatrixClient(
|
||||||
runCatching {
|
runCatching {
|
||||||
// First call without AuthData, should fail
|
// First call without AuthData, should fail
|
||||||
val firstAttempt = runCatching {
|
val firstAttempt = runCatching {
|
||||||
client.deactivateAccount(
|
innerClient.deactivateAccount(
|
||||||
authData = null,
|
authData = null,
|
||||||
eraseData = eraseData,
|
eraseData = eraseData,
|
||||||
)
|
)
|
||||||
|
|
@ -561,7 +557,7 @@ class RustMatrixClient(
|
||||||
Timber.w(firstAttempt.exceptionOrNull(), "Expected failure, try again")
|
Timber.w(firstAttempt.exceptionOrNull(), "Expected failure, try again")
|
||||||
// This is expected, try again with the password
|
// This is expected, try again with the password
|
||||||
runCatching {
|
runCatching {
|
||||||
client.deactivateAccount(
|
innerClient.deactivateAccount(
|
||||||
authData = AuthData.Password(
|
authData = AuthData.Password(
|
||||||
passwordDetails = AuthDataPasswordDetails(
|
passwordDetails = AuthDataPasswordDetails(
|
||||||
identifier = sessionId.value,
|
identifier = sessionId.value,
|
||||||
|
|
@ -573,7 +569,7 @@ class RustMatrixClient(
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
Timber.e(it, "Failed to deactivate account")
|
Timber.e(it, "Failed to deactivate account")
|
||||||
// If the deactivation failed we need to restore the delegate
|
// If the deactivation failed we need to restore the delegate
|
||||||
clientDelegateTaskHandle = client.setDelegate(sessionDelegate)
|
clientDelegateTaskHandle = innerClient.setDelegate(sessionDelegate)
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -588,13 +584,13 @@ class RustMatrixClient(
|
||||||
override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> = withContext(sessionDispatcher) {
|
override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> = withContext(sessionDispatcher) {
|
||||||
val rustAction = action?.toRustAction()
|
val rustAction = action?.toRustAction()
|
||||||
runCatching {
|
runCatching {
|
||||||
client.accountUrl(rustAction)
|
innerClient.accountUrl(rustAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String> = withContext(sessionDispatcher) {
|
override suspend fun uploadMedia(mimeType: String, data: ByteArray, progressCallback: ProgressCallback?): Result<String> = withContext(sessionDispatcher) {
|
||||||
runCatching {
|
runCatching {
|
||||||
client.uploadMedia(mimeType, data, progressCallback?.toProgressWatcher())
|
innerClient.uploadMedia(mimeType, data, progressCallback?.toProgressWatcher())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -617,29 +613,33 @@ class RustMatrixClient(
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setAllSendQueuesEnabled(enabled: Boolean) = withContext(sessionDispatcher) {
|
override suspend fun setAllSendQueuesEnabled(enabled: Boolean) {
|
||||||
Timber.i("setAllSendQueuesEnabled($enabled)")
|
withContext(sessionDispatcher) {
|
||||||
client.enableAllSendQueues(enabled)
|
Timber.i("setAllSendQueuesEnabled($enabled)")
|
||||||
|
tryOrNull {
|
||||||
|
innerClient.enableAllSendQueues(enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendQueueDisabledFlow(): Flow<RoomId> = mxCallbackFlow {
|
override fun sendQueueDisabledFlow(): Flow<RoomId> = mxCallbackFlow {
|
||||||
client.subscribeToSendQueueStatus(object : SendQueueRoomErrorListener {
|
innerClient.subscribeToSendQueueStatus(object : SendQueueRoomErrorListener {
|
||||||
override fun onError(roomId: String, error: ClientException) {
|
override fun onError(roomId: String, error: ClientException) {
|
||||||
trySend(RoomId(roomId))
|
trySend(RoomId(roomId))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}.buffer(Channel.UNLIMITED)
|
}.buffer(Channel.UNLIMITED)
|
||||||
|
|
||||||
override suspend fun isNativeSlidingSyncSupported(): Boolean {
|
override suspend fun availableSlidingSyncVersions(): Result<List<SlidingSyncVersion>> = withContext(sessionDispatcher) {
|
||||||
return client.availableSlidingSyncVersions().contains(SlidingSyncVersion.Native)
|
runCatching {
|
||||||
|
innerClient.availableSlidingSyncVersions().map { it.map() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun isSlidingSyncProxySupported(): Boolean {
|
override suspend fun currentSlidingSyncVersion(): Result<SlidingSyncVersion> = withContext(sessionDispatcher) {
|
||||||
return client.availableSlidingSyncVersions().any { it is SlidingSyncVersion.Proxy }
|
runCatching {
|
||||||
}
|
innerClient.session().slidingSyncVersion.map()
|
||||||
|
}
|
||||||
override fun isUsingNativeSlidingSync(): Boolean {
|
|
||||||
return client.session().slidingSyncVersion == SlidingSyncVersion.Native
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun File.getCacheSize(
|
private suspend fun File.getCacheSize(
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,12 @@ class RustMatrixClientFactory @Inject constructor(
|
||||||
.finish()
|
.finish()
|
||||||
|
|
||||||
return RustMatrixClient(
|
return RustMatrixClient(
|
||||||
client = client,
|
innerClient = client,
|
||||||
baseDirectory = baseDirectory,
|
baseDirectory = baseDirectory,
|
||||||
sessionStore = sessionStore,
|
sessionStore = sessionStore,
|
||||||
appCoroutineScope = appCoroutineScope,
|
appCoroutineScope = appCoroutineScope,
|
||||||
sessionDelegate = sessionDelegate,
|
sessionDelegate = sessionDelegate,
|
||||||
syncService = syncService,
|
innerSyncService = syncService,
|
||||||
dispatchers = coroutineDispatchers,
|
dispatchers = coroutineDispatchers,
|
||||||
baseCacheDirectory = cacheDirectory,
|
baseCacheDirectory = cacheDirectory,
|
||||||
clock = clock,
|
clock = clock,
|
||||||
|
|
|
||||||
|
|
@ -94,10 +94,6 @@ internal class RustEncryptionService(
|
||||||
}
|
}
|
||||||
.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, false)
|
.stateIn(sessionCoroutineScope, SharingStarted.Eagerly, false)
|
||||||
|
|
||||||
fun destroy() {
|
|
||||||
service.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun enableBackups(): Result<Unit> = withContext(dispatchers.io) {
|
override suspend fun enableBackups(): Result<Unit> = withContext(dispatchers.io) {
|
||||||
runCatching {
|
runCatching {
|
||||||
service.enableBackups()
|
service.enableBackups()
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ class RustNotificationSettingsService(
|
||||||
|
|
||||||
fun destroy() {
|
fun destroy() {
|
||||||
notificationSettings.setDelegate(null)
|
notificationSettings.setDelegate(null)
|
||||||
notificationSettings.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> =
|
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> =
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,14 @@ package io.element.android.libraries.matrix.impl.sync
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||||
import io.element.android.libraries.matrix.api.sync.SyncState
|
import io.element.android.libraries.matrix.api.sync.SyncState
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.NonCancellable
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.SyncServiceState
|
import org.matrix.rustcomponents.sdk.SyncServiceState
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
@ -49,12 +51,11 @@ class RustSyncService(
|
||||||
Timber.d("Stop sync failed: $it")
|
Timber.d("Stop sync failed: $it")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun destroy() {
|
suspend fun destroy() = withContext(NonCancellable) {
|
||||||
// If the service was still running, stop it
|
// If the service was still running, stop it
|
||||||
stopSync()
|
stopSync()
|
||||||
Timber.d("Destroying sync service")
|
Timber.d("Destroying sync service")
|
||||||
isServiceReady.set(false)
|
isServiceReady.set(false)
|
||||||
innerSyncService.destroy()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val syncState: StateFlow<SyncState> =
|
override val syncState: StateFlow<SyncState> =
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.sync
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
|
import org.matrix.rustcomponents.sdk.SlidingSyncVersion as RustSlidingSyncVersion
|
||||||
|
|
||||||
|
internal fun RustSlidingSyncVersion.map(): SlidingSyncVersion {
|
||||||
|
return when (this) {
|
||||||
|
RustSlidingSyncVersion.None -> SlidingSyncVersion.None
|
||||||
|
is RustSlidingSyncVersion.Proxy -> SlidingSyncVersion.Proxy
|
||||||
|
RustSlidingSyncVersion.Native -> SlidingSyncVersion.Native
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -229,7 +229,6 @@ class RustSessionVerificationService(
|
||||||
recoveryStateListenerTaskHandle.cancelAndDestroy()
|
recoveryStateListenerTaskHandle.cancelAndDestroy()
|
||||||
if (this::verificationController.isInitialized) {
|
if (this::verificationController.isInitialized) {
|
||||||
verificationController.setDelegate(null)
|
verificationController.setDelegate(null)
|
||||||
verificationController.destroy()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,14 +35,14 @@ class RustMatrixClientTest {
|
||||||
private fun TestScope.createRustMatrixClient(
|
private fun TestScope.createRustMatrixClient(
|
||||||
sessionStore: SessionStore = InMemorySessionStore(),
|
sessionStore: SessionStore = InMemorySessionStore(),
|
||||||
) = RustMatrixClient(
|
) = RustMatrixClient(
|
||||||
client = FakeRustClient(),
|
innerClient = FakeRustClient(),
|
||||||
baseDirectory = File(""),
|
baseDirectory = File(""),
|
||||||
sessionStore = sessionStore,
|
sessionStore = sessionStore,
|
||||||
appCoroutineScope = this,
|
appCoroutineScope = this,
|
||||||
sessionDelegate = aRustClientSessionDelegate(
|
sessionDelegate = aRustClientSessionDelegate(
|
||||||
sessionStore = sessionStore,
|
sessionStore = sessionStore,
|
||||||
),
|
),
|
||||||
syncService = FakeRustSyncService(),
|
innerSyncService = FakeRustSyncService(),
|
||||||
dispatchers = testCoroutineDispatchers(),
|
dispatchers = testCoroutineDispatchers(),
|
||||||
baseCacheDirectory = File(""),
|
baseCacheDirectory = File(""),
|
||||||
clock = FakeSystemClock(),
|
clock = FakeSystemClock(),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
|
import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||||
|
|
@ -84,9 +85,8 @@ class FakeMatrixClient(
|
||||||
private val getUrlLambda: (String) -> Result<String> = { lambdaError() },
|
private val getUrlLambda: (String) -> Result<String> = { lambdaError() },
|
||||||
private val canDeactivateAccountResult: () -> Boolean = { lambdaError() },
|
private val canDeactivateAccountResult: () -> Boolean = { lambdaError() },
|
||||||
private val deactivateAccountResult: (String, Boolean) -> Result<Unit> = { _, _ -> lambdaError() },
|
private val deactivateAccountResult: (String, Boolean) -> Result<Unit> = { _, _ -> lambdaError() },
|
||||||
var isNativeSlidingSyncSupportedLambda: suspend () -> Boolean = { true },
|
private val currentSlidingSyncVersionLambda: () -> Result<SlidingSyncVersion> = { lambdaError() },
|
||||||
var isSlidingSyncProxySupportedLambda: suspend () -> Boolean = { true },
|
private val availableSlidingSyncVersionsLambda: () -> Result<List<SlidingSyncVersion>> = { lambdaError() }
|
||||||
var isUsingNativeSlidingSyncLambda: () -> Boolean = { true },
|
|
||||||
) : MatrixClient {
|
) : MatrixClient {
|
||||||
var setDisplayNameCalled: Boolean = false
|
var setDisplayNameCalled: Boolean = false
|
||||||
private set
|
private set
|
||||||
|
|
@ -340,15 +340,11 @@ class FakeMatrixClient(
|
||||||
return getUrlLambda(url)
|
return getUrlLambda(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun isNativeSlidingSyncSupported(): Boolean {
|
override suspend fun currentSlidingSyncVersion(): Result<SlidingSyncVersion> {
|
||||||
return isNativeSlidingSyncSupportedLambda()
|
return currentSlidingSyncVersionLambda()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun isSlidingSyncProxySupported(): Boolean {
|
override suspend fun availableSlidingSyncVersions(): Result<List<SlidingSyncVersion>> {
|
||||||
return isSlidingSyncProxySupportedLambda()
|
return availableSlidingSyncVersionsLambda()
|
||||||
}
|
|
||||||
|
|
||||||
override fun isUsingNativeSlidingSync(): Boolean {
|
|
||||||
return isUsingNativeSlidingSyncLambda()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue