diff --git a/app/src/main/kotlin/app/dapk/st/SharedPreferencesDelegate.kt b/app/src/main/kotlin/app/dapk/st/SharedPreferencesDelegate.kt index 1ec1edb..8db7750 100644 --- a/app/src/main/kotlin/app/dapk/st/SharedPreferencesDelegate.kt +++ b/app/src/main/kotlin/app/dapk/st/SharedPreferencesDelegate.kt @@ -33,7 +33,7 @@ internal class SharedPreferencesDelegate( override suspend fun clear() { coroutineDispatchers.withIoContext { - preferences.edit().clear().apply() + preferences.edit().clear().commit() } } } \ No newline at end of file diff --git a/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt b/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt index a2de52e..aff9bee 100644 --- a/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt +++ b/app/src/main/kotlin/app/dapk/st/SmallTalkApplication.kt @@ -1,26 +1,27 @@ package app.dapk.st import android.app.Application +import android.content.Intent import android.util.Log import app.dapk.st.core.CoreAndroidModule import app.dapk.st.core.ModuleProvider import app.dapk.st.core.ProvidableModule import app.dapk.st.core.attachAppLogger +import app.dapk.st.core.extensions.ResettableUnsafeLazy import app.dapk.st.core.extensions.Scope -import app.dapk.st.core.extensions.unsafeLazy import app.dapk.st.directory.DirectoryModule -import app.dapk.st.messenger.MessengerModule +import app.dapk.st.domain.StoreModule import app.dapk.st.graph.AppModule -import app.dapk.st.graph.FeatureModules import app.dapk.st.home.HomeModule import app.dapk.st.login.LoginModule +import app.dapk.st.messenger.MessengerModule import app.dapk.st.notifications.NotificationsModule +import app.dapk.st.notifications.PushAndroidService import app.dapk.st.profile.ProfileModule import app.dapk.st.settings.SettingsModule import app.dapk.st.work.TaskRunnerModule import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch +import kotlinx.coroutines.cancel import kotlin.reflect.KClass class SmallTalkApplication : Application(), ModuleProvider { @@ -28,8 +29,10 @@ class SmallTalkApplication : Application(), ModuleProvider { private val appLogger: (String, String) -> Unit = { tag, message -> _appLogger?.invoke(tag, message) } private var _appLogger: ((String, String) -> Unit)? = null - private val appModule: AppModule by unsafeLazy { AppModule(this, appLogger) } - private val featureModules: FeatureModules by unsafeLazy { appModule.featureModules } + private val lazyAppModule = ResettableUnsafeLazy { AppModule(this, appLogger) } + private val lazyFeatureModules = ResettableUnsafeLazy { appModule.featureModules } + private val appModule by lazyAppModule + private val featureModules by lazyFeatureModules private val applicationScope = Scope(Dispatchers.IO) override fun onCreate() { @@ -40,13 +43,15 @@ class SmallTalkApplication : Application(), ModuleProvider { val logger: (String, String) -> Unit = { tag, message -> Log.e(tag, message) - GlobalScope.launch { - eventLogStore.insert(tag, message) - } + applicationScope.launch { eventLogStore.insert(tag, message) } } attachAppLogger(logger) _appLogger = logger + onApplicationLaunch(notificationsModule, storeModule) + } + + private fun onApplicationLaunch(notificationsModule: NotificationsModule, storeModule: StoreModule) { applicationScope.launch { notificationsModule.firebasePushTokenUseCase().registerCurrentToken() storeModule.localEchoStore.preload() @@ -73,4 +78,17 @@ class SmallTalkApplication : Application(), ModuleProvider { else -> throw IllegalArgumentException("Unknown: $klass") } as T } + + override fun reset() { + featureModules.notificationsModule.firebasePushTokenUseCase().unregister() + appModule.coroutineDispatchers.io.cancel() + applicationScope.cancel() + stopService(Intent(this, PushAndroidService::class.java)) + lazyAppModule.reset() + lazyFeatureModules.reset() + + val notificationsModule = featureModules.notificationsModule + val storeModule = appModule.storeModule.value + onApplicationLaunch(notificationsModule, storeModule) + } } diff --git a/app/src/main/kotlin/app/dapk/st/graph/AndroidBase64.kt b/app/src/main/kotlin/app/dapk/st/graph/AndroidBase64.kt new file mode 100644 index 0000000..dad547f --- /dev/null +++ b/app/src/main/kotlin/app/dapk/st/graph/AndroidBase64.kt @@ -0,0 +1,13 @@ +package app.dapk.st.graph + +import app.dapk.st.core.Base64 + +class AndroidBase64 : Base64 { + override fun encode(input: ByteArray): String { + return android.util.Base64.encodeToString(input, android.util.Base64.DEFAULT) + } + + override fun decode(input: String): ByteArray { + return android.util.Base64.decode(input, android.util.Base64.DEFAULT) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt index 7f7bc4d..e6efdb6 100644 --- a/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt +++ b/app/src/main/kotlin/app/dapk/st/graph/AppModule.kt @@ -69,7 +69,7 @@ internal class AppModule(context: Application, logger: MatrixLogger) { private val driver = AndroidSqliteDriver(DapkDb.Schema, context, "dapk.db") private val database = DapkDb(driver) private val clock = Clock.systemUTC() - private val coroutineDispatchers = CoroutineDispatchers(Dispatchers.IO) + val coroutineDispatchers = CoroutineDispatchers(Dispatchers.IO) val storeModule = unsafeLazy { StoreModule( @@ -83,9 +83,12 @@ internal class AppModule(context: Application, logger: MatrixLogger) { sql = "SELECT name FROM sqlite_master WHERE type = 'table' ${if (includeCryptoAccount) "" else "AND name != 'dbCryptoAccount'"}", parameters = 0 ) - while (cursor.next()) { - cursor.getString(0)?.let { - driver.execute(null, "DELETE FROM $it", 0) + cursor.use { + while (cursor.next()) { + cursor.getString(0)?.let { + log(AppLogTag.ERROR_NON_FATAL, "Deleting $it") + driver.execute(null, "DELETE FROM $it", 0) + } } } }, @@ -283,6 +286,14 @@ internal class MatrixModules( store.roomStore(), store.syncStore(), store.filterStore(), + deviceNotifier = { services -> + val encryption = services.deviceService() + val crypto = services.cryptoService() + DeviceNotifier { userIds, syncToken -> + encryption.updateStaleDevices(userIds) + crypto.updateOlmSession(userIds, syncToken) + } + }, messageDecrypter = { serviceProvider -> val cryptoService = serviceProvider.cryptoService() MessageDecrypter { @@ -296,9 +307,9 @@ internal class MatrixModules( } }, verificationHandler = { services -> - logger.matrixLog(MatrixLogTag.VERIFICATION, "got a verification request $it") val cryptoService = services.cryptoService() VerificationHandler { apiEvent -> + logger.matrixLog(MatrixLogTag.VERIFICATION, "got a verification request $it") cryptoService.onVerificationEvent( when (apiEvent) { is ApiToDeviceEvent.VerificationRequest -> Verification.Event.Requested( @@ -341,14 +352,6 @@ internal class MatrixModules( ) } }, - deviceNotifier = { services -> - val encryption = services.deviceService() - val crypto = services.cryptoService() - DeviceNotifier { userIds, syncToken -> - encryption.updateStaleDevices(userIds) - crypto.updateOlmSession(userIds, syncToken) - } - }, oneTimeKeyProducer = { services -> val cryptoService = services.cryptoService() MaybeCreateMoreKeys { @@ -367,8 +370,6 @@ internal class MatrixModules( ) installPushService(credentialsStore) - - } } } @@ -414,13 +415,3 @@ class TaskRunnerAdapter(private val matrixTaskRunner: suspend (MatrixTask) -> Ma } } } - -class AndroidBase64 : Base64 { - override fun encode(input: ByteArray): String { - return android.util.Base64.encodeToString(input, android.util.Base64.DEFAULT) - } - - override fun decode(input: String): ByteArray { - return android.util.Base64.decode(input, android.util.Base64.DEFAULT) - } -} \ No newline at end of file diff --git a/core/src/main/kotlin/app/dapk/st/core/ModuleProvider.kt b/core/src/main/kotlin/app/dapk/st/core/ModuleProvider.kt index 67f75a7..7dad034 100644 --- a/core/src/main/kotlin/app/dapk/st/core/ModuleProvider.kt +++ b/core/src/main/kotlin/app/dapk/st/core/ModuleProvider.kt @@ -4,7 +4,8 @@ import kotlin.reflect.KClass interface ModuleProvider { - fun provide(klass: KClass): T + fun provide(klass: KClass): T + fun reset() } interface ProvidableModule \ No newline at end of file diff --git a/core/src/main/kotlin/app/dapk/st/core/extensions/GlobalExtensions.kt b/core/src/main/kotlin/app/dapk/st/core/extensions/GlobalExtensions.kt index 5675590..1c947a7 100644 --- a/core/src/main/kotlin/app/dapk/st/core/extensions/GlobalExtensions.kt +++ b/core/src/main/kotlin/app/dapk/st/core/extensions/GlobalExtensions.kt @@ -21,3 +21,25 @@ inline fun Iterable.firstOrNull(predicate: (T) -> Boolean } fun unsafeLazy(initializer: () -> T): Lazy = lazy(mode = LazyThreadSafetyMode.NONE, initializer = initializer) + +class ResettableUnsafeLazy(private val initializer: () -> T) : Lazy { + + private var _value: T? = null + + override val value: T + get() { + return if (_value == null) { + initializer().also { _value = it } + } else { + _value!! + } + } + + override fun isInitialized(): Boolean { + return _value != null + } + + fun reset() { + _value = null + } +} \ No newline at end of file diff --git a/domains/android/core/src/main/kotlin/app/dapk/st/core/ContextExtensions.kt b/domains/android/core/src/main/kotlin/app/dapk/st/core/ContextExtensions.kt index 0d426b0..fdfd8cd 100644 --- a/domains/android/core/src/main/kotlin/app/dapk/st/core/ContextExtensions.kt +++ b/domains/android/core/src/main/kotlin/app/dapk/st/core/ContextExtensions.kt @@ -3,4 +3,6 @@ package app.dapk.st.core import android.content.Context inline fun Context.module() = - (this.applicationContext as ModuleProvider).provide(T::class) \ No newline at end of file + (this.applicationContext as ModuleProvider).provide(T::class) + +fun Context.resetModules() = (this.applicationContext as ModuleProvider).reset() \ No newline at end of file diff --git a/domains/android/push/src/main/kotlin/app/dapk/st/push/RegisterFirebasePushTokenUseCase.kt b/domains/android/push/src/main/kotlin/app/dapk/st/push/RegisterFirebasePushTokenUseCase.kt index 4ef213b..ded8029 100644 --- a/domains/android/push/src/main/kotlin/app/dapk/st/push/RegisterFirebasePushTokenUseCase.kt +++ b/domains/android/push/src/main/kotlin/app/dapk/st/push/RegisterFirebasePushTokenUseCase.kt @@ -12,6 +12,10 @@ class RegisterFirebasePushTokenUseCase( override val errorTracker: ErrorTracker, ) : CrashScope { + fun unregister() { + FirebaseMessaging.getInstance().deleteToken() + } + suspend fun registerCurrentToken() { kotlin.runCatching { FirebaseMessaging.getInstance().token().also { diff --git a/domains/store/src/main/kotlin/app/dapk/st/domain/SyncTokenPreferences.kt b/domains/store/src/main/kotlin/app/dapk/st/domain/SyncTokenPreferences.kt index 2be221e..a884c60 100644 --- a/domains/store/src/main/kotlin/app/dapk/st/domain/SyncTokenPreferences.kt +++ b/domains/store/src/main/kotlin/app/dapk/st/domain/SyncTokenPreferences.kt @@ -1,5 +1,7 @@ package app.dapk.st.domain +import app.dapk.st.core.AppLogTag +import app.dapk.st.core.log import app.dapk.st.matrix.common.SyncToken import app.dapk.st.matrix.sync.SyncStore import app.dapk.st.matrix.sync.SyncStore.SyncKey @@ -9,11 +11,13 @@ internal class SyncTokenPreferences( ) : SyncStore { override suspend fun store(key: SyncKey, syncToken: SyncToken) { + log(AppLogTag.ERROR_NON_FATAL, "Store token :$syncToken") preferences.store(key.value, syncToken.value) } override suspend fun read(key: SyncKey): SyncToken? { return preferences.readString(key.value)?.let { + log(AppLogTag.ERROR_NON_FATAL, "Read token :$it") SyncToken(it) } } diff --git a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsActivity.kt b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsActivity.kt index f89d251..471d387 100644 --- a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsActivity.kt +++ b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsActivity.kt @@ -7,6 +7,7 @@ import androidx.compose.material.Surface import androidx.compose.ui.Modifier import app.dapk.st.core.DapkActivity import app.dapk.st.core.module +import app.dapk.st.core.resetModules import app.dapk.st.core.viewModel import app.dapk.st.design.components.SmallTalkTheme @@ -20,6 +21,7 @@ class SettingsActivity : DapkActivity() { SmallTalkTheme { Surface(Modifier.fillMaxSize()) { SettingsScreen(settingsViewModel, onSignOut = { + resetModules() navigator.navigate.toHome() finish() }, navigator) diff --git a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsModule.kt b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsModule.kt index 00a0d67..680b72a 100644 --- a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsModule.kt +++ b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsModule.kt @@ -19,7 +19,6 @@ class SettingsModule( ) : ProvidableModule { internal fun settingsViewModel() = SettingsViewModel( - storeModule.credentialsStore(), storeModule.cacheCleaner(), contentResolver, cryptoService, diff --git a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsViewModel.kt b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsViewModel.kt index 1847878..f8dc927 100644 --- a/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsViewModel.kt +++ b/features/settings/src/main/kotlin/app/dapk/st/settings/SettingsViewModel.kt @@ -3,10 +3,11 @@ package app.dapk.st.settings import android.content.ContentResolver import android.net.Uri import androidx.lifecycle.viewModelScope +import app.dapk.st.core.AppLogTag import app.dapk.st.core.Lce +import app.dapk.st.core.log import app.dapk.st.design.components.SpiderPage import app.dapk.st.domain.StoreCleaner -import app.dapk.st.matrix.common.CredentialsStore import app.dapk.st.matrix.crypto.CryptoService import app.dapk.st.matrix.sync.SyncService import app.dapk.st.settings.SettingItem.Id.* @@ -19,7 +20,6 @@ import kotlinx.coroutines.launch private const val PRIVACY_POLICY_URL = "https://ouchadam.github.io/small-talk/privacy/" internal class SettingsViewModel( - private val credentialsStore: CredentialsStore, private val cacheCleaner: StoreCleaner, private val contentResolver: ContentResolver, private val cryptoService: CryptoService, @@ -49,9 +49,9 @@ internal class SettingsViewModel( when (item.id) { SignOut -> { viewModelScope.launch { - credentialsStore.clear() + log(AppLogTag.ERROR_NON_FATAL, "Sign out triggered") + cacheCleaner.cleanCache(removeCredentials = true) _events.emit(SignedOut) - println("emitted") } } AccessToken -> { diff --git a/features/settings/src/test/kotlin/app/dapk/st/settings/SettingsViewModelTest.kt b/features/settings/src/test/kotlin/app/dapk/st/settings/SettingsViewModelTest.kt index 7d9c152..b8ca7e1 100644 --- a/features/settings/src/test/kotlin/app/dapk/st/settings/SettingsViewModelTest.kt +++ b/features/settings/src/test/kotlin/app/dapk/st/settings/SettingsViewModelTest.kt @@ -38,7 +38,6 @@ internal class SettingsViewModelTest { private val fakeSettingsItemFactory = FakeSettingsItemFactory() private val viewModel = SettingsViewModel( - fakeCredentialsStore, fakeStoreCleaner, fakeContentResolver.instance, fakeCryptoService, @@ -77,8 +76,8 @@ internal class SettingsViewModelTest { } @Test - fun `when sign out clicked, then clears credentials`() = runViewModelTest { - fakeCredentialsStore.expectUnit { it.clear() } + fun `when sign out clicked, then clears store`() = runViewModelTest { + fakeStoreCleaner.expectUnit { it.cleanCache(removeCredentials = true) } val aSignOutItem = aSettingTextItem(id = SettingItem.Id.SignOut) viewModel.test().onClick(aSignOutItem) diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/Store.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/Store.kt index de59886..6964ff4 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/Store.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/Store.kt @@ -23,7 +23,6 @@ interface RoomStore { interface FilterStore { suspend fun store(key: String, filterId: String) - suspend fun read(key: String): String? } diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/DefaultSyncService.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/DefaultSyncService.kt index 8a12cef..699d5d1 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/DefaultSyncService.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/DefaultSyncService.kt @@ -2,6 +2,7 @@ package app.dapk.st.matrix.sync.internal import app.dapk.st.core.CoroutineDispatchers import app.dapk.st.core.extensions.ErrorTracker +import app.dapk.st.core.withIoContext import app.dapk.st.matrix.common.* import app.dapk.st.matrix.http.MatrixHttpClient import app.dapk.st.matrix.sync.* @@ -12,11 +13,15 @@ import app.dapk.st.matrix.sync.internal.room.RoomEventsDecrypter import app.dapk.st.matrix.sync.internal.room.SyncEventDecrypter import app.dapk.st.matrix.sync.internal.room.SyncSideEffects import app.dapk.st.matrix.sync.internal.sync.* -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.flow.* import kotlinx.serialization.json.Json import java.util.concurrent.atomic.AtomicInteger +private val syncSubscriptionCount = AtomicInteger() + internal class DefaultSyncService( httpClient: MatrixHttpClient, syncStore: SyncStore, @@ -34,11 +39,10 @@ internal class DefaultSyncService( roomMembersService: RoomMembersService, logger: MatrixLogger, errorTracker: ErrorTracker, - coroutineDispatchers: CoroutineDispatchers, + private val coroutineDispatchers: CoroutineDispatchers, syncConfig: SyncConfig, ) : SyncService { - private val syncSubscriptionCount = AtomicInteger() private val syncEventsFlow = MutableStateFlow>(emptyList()) private val roomDataSource by lazy { RoomDataSource(roomStore, logger) } @@ -107,7 +111,7 @@ internal class DefaultSyncService( override fun events() = syncEventsFlow override suspend fun observeEvent(eventId: EventId) = roomStore.observeEvent(eventId) override suspend fun forceManualRefresh(roomIds: List) { - withContext(Dispatchers.IO) { + coroutineDispatchers.withIoContext { roomIds.map { async { roomRefresher.refreshRoomContent(it)?.also { diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncReducer.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncReducer.kt index aa422ce..27bbb43 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncReducer.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncReducer.kt @@ -34,18 +34,22 @@ internal class SyncReducer( val newRooms = response.rooms?.join?.keys?.filterNot { roomDataSource.contains(it) } ?: emptyList() val apiUpdatedRooms = response.rooms?.join?.keepRoomsWithChanges() - val apiRoomsToProcess = apiUpdatedRooms?.map { (roomId, apiRoom) -> + val apiRoomsToProcess = apiUpdatedRooms?.mapNotNull { (roomId, apiRoom) -> logger.matrixLog(SYNC, "reducing: $roomId") coroutineDispatchers.withIoContextAsync { - roomProcessor.processRoom( - roomToProcess = RoomToProcess( - roomId = roomId, - apiSyncRoom = apiRoom, - directMessage = directMessages[roomId], - userCredentials = userCredentials, - ), - isInitialSync = isInitialSync - ) + runCatching { + roomProcessor.processRoom( + roomToProcess = RoomToProcess( + roomId = roomId, + apiSyncRoom = apiRoom, + directMessage = directMessages[roomId], + userCredentials = userCredentials, + ), + isInitialSync = isInitialSync + ) + } + .onFailure { logger.matrixLog(SYNC, "failed to reduce: $roomId, skipping") } + .getOrNull() } } ?: emptyList() diff --git a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncUseCase.kt b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncUseCase.kt index 5e840f4..c715ad0 100644 --- a/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncUseCase.kt +++ b/matrix/services/sync/src/main/kotlin/app/dapk/st/matrix/sync/internal/sync/SyncUseCase.kt @@ -8,9 +8,12 @@ import app.dapk.st.matrix.sync.internal.SideEffectFlowIterator import app.dapk.st.matrix.sync.internal.overview.ReducedSyncFilterUseCase import app.dapk.st.matrix.sync.internal.request.syncRequest import app.dapk.st.matrix.sync.internal.room.SyncSideEffects +import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.cancellable import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.isActive +import kotlinx.coroutines.isActive internal class SyncUseCase( private val persistence: OverviewStore, @@ -27,40 +30,43 @@ internal class SyncUseCase( fun sync(): Flow { return flow { - logger.matrixLog("flow instance: ${hashCode()}") val credentials = credentialsStore.credentials()!! val filterId = filterUseCase.reducedFilter(credentials.userId) with(flowIterator) { loop(initial = null) { previousState -> - logger.matrixLog("looper : ${hashCode()}") val syncToken = syncStore.read(key = SyncStore.SyncKey.Overview) val response = doSyncRequest(filterId, syncToken) - logger.logP("sync processing") { - syncStore.store(key = SyncStore.SyncKey.Overview, syncToken = response.nextBatch) - val sideEffects = logger.logP("side effects processing") { - syncSideEffects.blockingSideEffects(credentials.userId, response, syncToken) - } + if (credentialsStore.isSignedIn()) { + logger.logP("sync processing") { + syncStore.store(key = SyncStore.SyncKey.Overview, syncToken = response.nextBatch) + val sideEffects = logger.logP("side effects processing") { + syncSideEffects.blockingSideEffects(credentials.userId, response, syncToken) + } - val isInitialSync = syncToken == null - val nextState = logger.logP("reducing") { syncReducer.reduce(isInitialSync, sideEffects, response, credentials) } - val overview = nextState.roomState.map { it.roomOverview } + val isInitialSync = syncToken == null + val nextState = logger.logP("reducing") { syncReducer.reduce(isInitialSync, sideEffects, response, credentials) } + val overview = nextState.roomState.map { it.roomOverview } - if (nextState.roomsLeft.isNotEmpty()) { - persistence.removeRooms(nextState.roomsLeft) - } - if (nextState.invites.isNotEmpty()) { - persistence.persistInvites(nextState.invites) - } - if (nextState.newRoomsJoined.isNotEmpty()) { - persistence.removeInvites(nextState.newRoomsJoined) - } + if (nextState.roomsLeft.isNotEmpty()) { + persistence.removeRooms(nextState.roomsLeft) + } + if (nextState.invites.isNotEmpty()) { + persistence.persistInvites(nextState.invites) + } + if (nextState.newRoomsJoined.isNotEmpty()) { + persistence.removeInvites(nextState.newRoomsJoined) + } - when { - previousState == overview -> previousState.also { logger.matrixLog(SYNC, "no changes, not persisting new state") } - overview.isNotEmpty() -> overview.also { persistence.persist(overview) } - else -> previousState.also { logger.matrixLog(SYNC, "nothing to do") } + when { + previousState == overview -> previousState.also { logger.matrixLog(SYNC, "no changes, not persisting new state") } + overview.isNotEmpty() -> overview.also { persistence.persist(overview) } + else -> previousState.also { logger.matrixLog(SYNC, "nothing to do") } + } } + } else { + logger.matrixLog(SYNC, "sync processing skipped due to being signed out") + null } } } diff --git a/test-harness/src/test/kotlin/test/TestMatrix.kt b/test-harness/src/test/kotlin/test/TestMatrix.kt index d38e91f..a195e45 100644 --- a/test-harness/src/test/kotlin/test/TestMatrix.kt +++ b/test-harness/src/test/kotlin/test/TestMatrix.kt @@ -157,6 +157,14 @@ class TestMatrix( storeModule.roomStore(), storeModule.syncStore(), storeModule.filterStore(), + deviceNotifier = { services -> + val encryptionService = services.deviceService() + val cryptoService = services.cryptoService() + DeviceNotifier { userIds, syncToken -> + encryptionService.updateStaleDevices(userIds) + cryptoService.updateOlmSession(userIds, syncToken) + } + }, messageDecrypter = { serviceProvider -> MessageDecrypter { serviceProvider.cryptoService().decrypt(it) @@ -222,14 +230,6 @@ class TestMatrix( ) } }, - deviceNotifier = { services -> - val encryptionService = services.deviceService() - val cryptoService = services.cryptoService() - DeviceNotifier { userIds, syncToken -> - encryptionService.updateStaleDevices(userIds) - cryptoService.updateOlmSession(userIds, syncToken) - } - }, oneTimeKeyProducer = { services -> val cryptoService = services.cryptoService() MaybeCreateMoreKeys {