Secure Storage: improve API for waitForBackupUploadSteadyState()
This commit is contained in:
parent
4898d8012c
commit
29e1e9b316
5 changed files with 37 additions and 18 deletions
|
|
@ -29,6 +29,7 @@ import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
import io.element.android.libraries.matrix.api.encryption.EncryptionService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -46,13 +47,15 @@ class LogoutPresenter @Inject constructor(
|
||||||
mutableStateOf(Async.Uninitialized)
|
mutableStateOf(Async.Uninitialized)
|
||||||
}
|
}
|
||||||
|
|
||||||
val backupUploadState by encryptionService.backupUploadStateStateFlow.collectAsState()
|
val backupUploadState: BackupUploadState by remember {
|
||||||
|
encryptionService.waitForBackupUploadSteadyState()
|
||||||
|
}
|
||||||
|
.collectAsState(initial = BackupUploadState.Unknown)
|
||||||
|
|
||||||
var showLogoutDialog by remember { mutableStateOf(false) }
|
var showLogoutDialog by remember { mutableStateOf(false) }
|
||||||
var isLastSession by remember { mutableStateOf(false) }
|
var isLastSession by remember { mutableStateOf(false) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
isLastSession = encryptionService.isLastDevice().getOrNull() ?: false
|
isLastSession = encryptionService.isLastDevice().getOrNull() ?: false
|
||||||
encryptionService.waitForBackupUploadSteadyState()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleEvents(event: LogoutEvents) {
|
fun handleEvents(event: LogoutEvents) {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -73,6 +75,15 @@ class LogoutPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun `present - initial state - backing up`() = runTest {
|
fun `present - initial state - backing up`() = runTest {
|
||||||
val encryptionService = FakeEncryptionService()
|
val encryptionService = FakeEncryptionService()
|
||||||
|
encryptionService.givenWaitForBackupUploadSteadyStateFlow(
|
||||||
|
flow {
|
||||||
|
emit(BackupUploadState.Waiting)
|
||||||
|
delay(1)
|
||||||
|
emit(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
|
||||||
|
delay(1)
|
||||||
|
emit(BackupUploadState.Done)
|
||||||
|
}
|
||||||
|
)
|
||||||
val presenter = createLogoutPresenter(
|
val presenter = createLogoutPresenter(
|
||||||
encryptionService = encryptionService
|
encryptionService = encryptionService
|
||||||
)
|
)
|
||||||
|
|
@ -81,13 +92,11 @@ class LogoutPresenterTest {
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
assertThat(initialState.isLastSession).isFalse()
|
assertThat(initialState.isLastSession).isFalse()
|
||||||
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Unknown)
|
assertThat(initialState.backupUploadState).isEqualTo(BackupUploadState.Waiting)
|
||||||
assertThat(initialState.showConfirmationDialog).isFalse()
|
assertThat(initialState.showConfirmationDialog).isFalse()
|
||||||
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
|
assertThat(initialState.logoutAction).isEqualTo(Async.Uninitialized)
|
||||||
encryptionService.emitBackupUploadState(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
|
|
||||||
val state = awaitItem()
|
val state = awaitItem()
|
||||||
assertThat(state.backupUploadState).isEqualTo(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
|
assertThat(state.backupUploadState).isEqualTo(BackupUploadState.Uploading(backedUpCount = 1, totalCount = 2))
|
||||||
encryptionService.emitBackupUploadState(BackupUploadState.Done)
|
|
||||||
val doneState = awaitItem()
|
val doneState = awaitItem()
|
||||||
assertThat(doneState.backupUploadState).isEqualTo(BackupUploadState.Done)
|
assertThat(doneState.backupUploadState).isEqualTo(BackupUploadState.Done)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.encryption
|
package io.element.android.libraries.matrix.api.encryption
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
interface EncryptionService {
|
interface EncryptionService {
|
||||||
val backupStateStateFlow: StateFlow<BackupState>
|
val backupStateStateFlow: StateFlow<BackupState>
|
||||||
val recoveryStateStateFlow: StateFlow<RecoveryState>
|
val recoveryStateStateFlow: StateFlow<RecoveryState>
|
||||||
val backupUploadStateStateFlow: StateFlow<BackupUploadState>
|
|
||||||
val enableRecoveryProgressStateFlow: StateFlow<EnableRecoveryProgress>
|
val enableRecoveryProgressStateFlow: StateFlow<EnableRecoveryProgress>
|
||||||
|
|
||||||
suspend fun enableBackups(): Result<Unit>
|
suspend fun enableBackups(): Result<Unit>
|
||||||
|
|
@ -46,7 +46,7 @@ interface EncryptionService {
|
||||||
suspend fun fixRecoveryIssues(recoveryKey: String): Result<Unit>
|
suspend fun fixRecoveryIssues(recoveryKey: String): Result<Unit>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observe [backupUploadStateStateFlow] to get progress.
|
* Wait for backup upload steady state.
|
||||||
*/
|
*/
|
||||||
suspend fun waitForBackupUploadSteadyState(): Result<Unit>
|
fun waitForBackupUploadSteadyState(): Flow<BackupUploadState>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ import io.element.android.libraries.matrix.api.encryption.BackupUploadState
|
||||||
import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress
|
import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress
|
||||||
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 kotlinx.coroutines.channels.awaitClose
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.BackupStateListener
|
import org.matrix.rustcomponents.sdk.BackupStateListener
|
||||||
import org.matrix.rustcomponents.sdk.BackupSteadyStateListener
|
import org.matrix.rustcomponents.sdk.BackupSteadyStateListener
|
||||||
|
|
@ -50,7 +53,6 @@ internal class RustEncryptionService(
|
||||||
override val backupStateStateFlow: MutableStateFlow<BackupState> = MutableStateFlow(service.backupState().let(backupStateMapper::map))
|
override val backupStateStateFlow: MutableStateFlow<BackupState> = MutableStateFlow(service.backupState().let(backupStateMapper::map))
|
||||||
override val recoveryStateStateFlow: MutableStateFlow<RecoveryState> = MutableStateFlow(service.recoveryState().let(recoveryStateMapper::map))
|
override val recoveryStateStateFlow: MutableStateFlow<RecoveryState> = MutableStateFlow(service.recoveryState().let(recoveryStateMapper::map))
|
||||||
override val enableRecoveryProgressStateFlow: MutableStateFlow<EnableRecoveryProgress> = MutableStateFlow(EnableRecoveryProgress.Unknown)
|
override val enableRecoveryProgressStateFlow: MutableStateFlow<EnableRecoveryProgress> = MutableStateFlow(EnableRecoveryProgress.Unknown)
|
||||||
override val backupUploadStateStateFlow: MutableStateFlow<BackupUploadState> = MutableStateFlow(BackupUploadState.Unknown)
|
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
service.backupStateListener(object : BackupStateListener {
|
service.backupStateListener(object : BackupStateListener {
|
||||||
|
|
@ -94,16 +96,19 @@ internal class RustEncryptionService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun waitForBackupUploadSteadyState(
|
override fun waitForBackupUploadSteadyState(): Flow<BackupUploadState> {
|
||||||
): Result<Unit> = withContext(dispatchers.io) {
|
return callbackFlow {
|
||||||
runCatching {
|
|
||||||
service.waitForBackupUploadSteadyState(
|
service.waitForBackupUploadSteadyState(
|
||||||
progressListener = object : BackupSteadyStateListener {
|
progressListener = object : BackupSteadyStateListener {
|
||||||
override fun onUpdate(status: RustBackupUploadState) {
|
override fun onUpdate(status: RustBackupUploadState) {
|
||||||
backupUploadStateStateFlow.value = backupUploadStateMapper.map(status)
|
trySend(backupUploadStateMapper.map(status))
|
||||||
|
if (status == RustBackupUploadState.Done) {
|
||||||
|
close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
awaitClose {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,16 @@ import io.element.android.libraries.matrix.api.encryption.EnableRecoveryProgress
|
||||||
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.tests.testutils.simulateLongTask
|
import io.element.android.tests.testutils.simulateLongTask
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
|
|
||||||
class FakeEncryptionService : EncryptionService {
|
class FakeEncryptionService : EncryptionService {
|
||||||
private var disableRecoveryFailure: Exception? = null
|
private var disableRecoveryFailure: Exception? = null
|
||||||
override val backupStateStateFlow: MutableStateFlow<BackupState> = MutableStateFlow(BackupState.UNKNOWN)
|
override val backupStateStateFlow: MutableStateFlow<BackupState> = MutableStateFlow(BackupState.UNKNOWN)
|
||||||
override val recoveryStateStateFlow: MutableStateFlow<RecoveryState> = MutableStateFlow(RecoveryState.UNKNOWN)
|
override val recoveryStateStateFlow: MutableStateFlow<RecoveryState> = MutableStateFlow(RecoveryState.UNKNOWN)
|
||||||
override val enableRecoveryProgressStateFlow: MutableStateFlow<EnableRecoveryProgress> = MutableStateFlow(EnableRecoveryProgress.Unknown)
|
override val enableRecoveryProgressStateFlow: MutableStateFlow<EnableRecoveryProgress> = MutableStateFlow(EnableRecoveryProgress.Unknown)
|
||||||
override val backupUploadStateStateFlow: MutableStateFlow<BackupUploadState> = MutableStateFlow(BackupUploadState.Unknown)
|
private var waitForBackupUploadSteadyStateFlow: Flow<BackupUploadState> = flowOf()
|
||||||
|
|
||||||
private var fixRecoveryIssuesFailure: Exception? = null
|
private var fixRecoveryIssuesFailure: Exception? = null
|
||||||
|
|
||||||
|
|
@ -73,12 +75,12 @@ class FakeEncryptionService : EncryptionService {
|
||||||
return Result.success(Unit)
|
return Result.success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun waitForBackupUploadSteadyState(): Result<Unit> {
|
fun givenWaitForBackupUploadSteadyStateFlow(flow: Flow<BackupUploadState>) {
|
||||||
return Result.success(Unit)
|
waitForBackupUploadSteadyStateFlow = flow
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun emitBackupUploadState(state: BackupUploadState) {
|
override fun waitForBackupUploadSteadyState(): Flow<BackupUploadState> {
|
||||||
backupUploadStateStateFlow.emit(state)
|
return waitForBackupUploadSteadyStateFlow
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun emitBackupState(state: BackupState) {
|
suspend fun emitBackupState(state: BackupState) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue