diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e5495eaf3c..2250d9bf39 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -129,7 +129,7 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = { module = "app.cash.molecule:molecule-runtime", version.ref = "molecule" } timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.11" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.12" sqldelight-driver-android = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" } sqldelight-driver-jvm = { module = "com.squareup.sqldelight:sqlite-driver", version.ref = "sqldelight" } sqldelight-coroutines = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationService.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationService.kt index 972873ab38..f52e24d79b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationService.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/notification/NotificationService.kt @@ -21,5 +21,5 @@ import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId interface NotificationService { - suspend fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId): Result + fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId): Result } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 73e37121d5..cce7ac90c7 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -44,7 +44,9 @@ import io.element.android.libraries.matrix.impl.verification.RustSessionVerifica import io.element.android.libraries.sessionstorage.api.SessionStore import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn @@ -54,7 +56,9 @@ import kotlinx.coroutines.withTimeout import org.matrix.rustcomponents.sdk.Client import org.matrix.rustcomponents.sdk.ClientDelegate import org.matrix.rustcomponents.sdk.RequiredState +import org.matrix.rustcomponents.sdk.SlidingSyncList import org.matrix.rustcomponents.sdk.SlidingSyncListBuilder +import org.matrix.rustcomponents.sdk.SlidingSyncListOnceBuilt import org.matrix.rustcomponents.sdk.SlidingSyncMode import org.matrix.rustcomponents.sdk.SlidingSyncRequestListFilters import org.matrix.rustcomponents.sdk.TaskHandle @@ -82,7 +86,7 @@ class RustMatrixClient constructor( client = client, dispatchers = dispatchers, ) - private val notificationService = RustNotificationService(baseDirectory, dispatchers) + private val notificationService = RustNotificationService(client) private var slidingSyncUpdateJob: Job? = null private val clientDelegate = object : ClientDelegate { @@ -105,7 +109,8 @@ class RustMatrixClient constructor( notTags = emptyList() ) - private val visibleRoomsSlidingSyncList = SlidingSyncListBuilder() + private val visibleRoomsSlidingSyncList = MutableSharedFlow(replay = 1) + private val visibleRoomsSlidingSyncListBuilder = SlidingSyncListBuilder("CurrentlyVisibleRooms") .timelineLimit(limit = 1u) .requiredState( requiredState = listOf( @@ -115,16 +120,19 @@ class RustMatrixClient constructor( ) ) .filters(visibleRoomsSlidingSyncFilters) - .name(name = "CurrentlyVisibleRooms") .syncMode(mode = SlidingSyncMode.SELECTIVE) .addRange(0u, 20u) - .use { - it.build() - } + .onceBuilt(object : SlidingSyncListOnceBuilt { + override fun updateList(list: SlidingSyncList): SlidingSyncList { + visibleRoomsSlidingSyncList.tryEmit(list) + return list + } + }) private val invitesSlidingSyncFilters = visibleRoomsSlidingSyncFilters.copy(isInvite = true) - private val invitesSlidingSyncList = SlidingSyncListBuilder() + private val invitesSlidingSyncList = MutableSharedFlow(replay = 1) + private val invitesSlidingSyncListBuilder = SlidingSyncListBuilder("CurrentInvites") .timelineLimit(limit = 1u) .requiredState( requiredState = listOf( @@ -134,20 +142,22 @@ class RustMatrixClient constructor( ) ) .filters(invitesSlidingSyncFilters) - .name(name = "CurrentInvites") .syncMode(mode = SlidingSyncMode.SELECTIVE) .addRange(0u, 20u) - .use { - it.build() - } + .onceBuilt(object : SlidingSyncListOnceBuilt { + override fun updateList(list: SlidingSyncList): SlidingSyncList { + invitesSlidingSyncList.tryEmit(list) + return list + } + }) private val slidingSync = client .slidingSync() .homeserver("https://slidingsync.lab.matrix.org") .withCommonExtensions() .storageKey("ElementX") - .addList(visibleRoomsSlidingSyncList) - .addList(invitesSlidingSyncList) + .addList(visibleRoomsSlidingSyncListBuilder) + .addList(invitesSlidingSyncListBuilder) .use { it.build() } @@ -159,7 +169,6 @@ class RustMatrixClient constructor( slidingSync, visibleRoomsSlidingSyncList, dispatchers, - ::onRestartSync ) override val roomSummaryDataSource: RoomSummaryDataSource @@ -171,7 +180,6 @@ class RustMatrixClient constructor( slidingSync, invitesSlidingSyncList, dispatchers, - ::onRestartSync ) override val invitesDataSource: RoomSummaryDataSource @@ -194,11 +202,6 @@ class RustMatrixClient constructor( .launchIn(coroutineScope) } - private fun onRestartSync() { - stopSync() - startSync() - } - override fun getRoom(roomId: RoomId): MatrixRoom? { val slidingSyncRoom = slidingSync.getRoom(roomId.value) ?: return null val fullRoom = slidingSyncRoom.fullRoom() ?: return null @@ -297,6 +300,7 @@ class RustMatrixClient constructor( } } + @ExperimentalCoroutinesApi override fun close() { slidingSyncUpdateJob?.cancel() stopSync() @@ -304,7 +308,10 @@ class RustMatrixClient constructor( rustRoomSummaryDataSource.close() rustInvitesDataSource.close() client.setDelegate(null) - visibleRoomsSlidingSyncList.destroy() + visibleRoomsSlidingSyncListBuilder.destroy() + invitesSlidingSyncListBuilder.destroy() + visibleRoomsSlidingSyncList.resetReplayCache() + invitesSlidingSyncList.resetReplayCache() slidingSync.destroy() verificationService.destroy() client.destroy() diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt index 1368c17243..bd94de21fc 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notification/RustNotificationService.kt @@ -17,33 +17,30 @@ package io.element.android.libraries.matrix.impl.notification import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.notification.NotificationData import io.element.android.libraries.matrix.api.notification.NotificationService import kotlinx.coroutines.withContext +import org.matrix.rustcomponents.sdk.Client +import org.matrix.rustcomponents.sdk.use import java.io.File class RustNotificationService( - private val baseDirectory: File, - private val dispatchers: CoroutineDispatchers, + private val client: Client, ) : NotificationService { private val notificationMapper: NotificationMapper = NotificationMapper() - override suspend fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId): Result { - return withContext(dispatchers.io) { - runCatching { - org.matrix.rustcomponents.sdk.NotificationService( - basePath = File(baseDirectory, "sessions").absolutePath, - userId = userId.value - ).use { - // TODO Not implemented yet, see https://github.com/matrix-org/matrix-rust-sdk/issues/1628 - it.getNotificationItem(roomId.value, eventId.value)?.let { notificationItem -> - notificationMapper.map(notificationItem) - } - } - } + override fun getNotification( + userId: SessionId, + roomId: RoomId, + eventId: EventId + ): Result { + return runCatching { + client.getNotificationItem(roomId.value, eventId.value).use(notificationMapper::map) } } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 9caba227ce..062f24ab62 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -33,7 +33,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart -import kotlinx.coroutines.flow.onSubscription import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.SlidingSyncRoom diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt index 9c2382fb4a..c908651e75 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomSummaryDataSource.kt @@ -27,9 +27,12 @@ import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.RoomListEntry import org.matrix.rustcomponents.sdk.SlidingSync @@ -44,9 +47,8 @@ import java.util.UUID internal class RustRoomSummaryDataSource( private val slidingSyncUpdateFlow: Flow, private val slidingSync: SlidingSync, - private val slidingSyncList: SlidingSyncList, + private val slidingSyncListFlow: Flow, private val coroutineDispatchers: CoroutineDispatchers, - private val onRestartSync: () -> Unit, private val roomSummaryDetailsFactory: RoomSummaryDetailsFactory = RoomSummaryDetailsFactory(), ) : RoomSummaryDataSource, Closeable { @@ -57,34 +59,35 @@ internal class RustRoomSummaryDataSource( fun init() { coroutineScope.launch { + val slidingSyncList = slidingSyncListFlow.first() + val summaries = slidingSyncList.currentRoomList().map(::buildSummaryForRoomListEntry) updateRoomSummaries { - addAll( - slidingSyncList.currentRoomList().map(::buildSummaryForRoomListEntry) - ) + addAll(summaries) } + + slidingSyncList.roomListDiff(this) + .onEach { diffs -> + updateRoomSummaries { + applyDiff(diffs) + } + } + .launchIn(this) + + slidingSyncList.state(this) + .onEach { slidingSyncState -> + Timber.v("New sliding sync state: $slidingSyncState") + state.value = slidingSyncState + }.launchIn(this) } slidingSyncUpdateFlow .onEach { didReceiveSyncUpdate(it) }.launchIn(coroutineScope) - - slidingSyncList.roomListDiff(coroutineScope) - .onEach { diffs -> - updateRoomSummaries { - applyDiff(diffs) - } - } - .launchIn(coroutineScope) - - slidingSyncList.state(coroutineScope) - .onEach { slidingSyncState -> - Timber.v("New sliding sync state: $slidingSyncState") - state.value = slidingSyncState - }.launchIn(coroutineScope) } override fun close() { + runBlocking { slidingSyncListFlow.firstOrNull() }?.close() coroutineScope.cancel() } @@ -95,8 +98,9 @@ internal class RustRoomSummaryDataSource( override fun setSlidingSyncRange(range: IntRange) { Timber.v("setVisibleRange=$range") - slidingSyncList.setRange(range.first.toUInt(), range.last.toUInt()) - onRestartSync() + coroutineScope.launch { + slidingSyncListFlow.first().setRange(range.first.toUInt(), range.last.toUInt()) + } } private suspend fun didReceiveSyncUpdate(summary: UpdateSummary) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notification/FakeNotificationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notification/FakeNotificationService.kt index 7cb92d35c5..b92c9b7a92 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notification/FakeNotificationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/notification/FakeNotificationService.kt @@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.notification.NotificationData import io.element.android.libraries.matrix.api.notification.NotificationService class FakeNotificationService : NotificationService { - override suspend fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId): Result { + override fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId): Result { return Result.success(null) } }