Subscribe to RoomListItems in the visible range (#3169)
* Subscribe to `RoomListItems` in the visible range This ensures the room list items always have updated info.
This commit is contained in:
parent
0be7058416
commit
5944f112fb
16 changed files with 204 additions and 17 deletions
|
|
@ -55,6 +55,7 @@ import io.element.android.libraries.matrix.impl.notificationsettings.RustNotific
|
|||
import io.element.android.libraries.matrix.impl.oidc.toRustAction
|
||||
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
||||
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
|
||||
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
|
||||
import io.element.android.libraries.matrix.impl.room.RustRoomFactory
|
||||
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewMapper
|
||||
import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryService
|
||||
|
|
@ -213,6 +214,8 @@ class RustMatrixClient(
|
|||
}
|
||||
}
|
||||
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber = RoomSyncSubscriber(innerRoomListService, dispatchers)
|
||||
|
||||
override val roomListService: RoomListService = RustRoomListService(
|
||||
innerRoomListService = innerRoomListService,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
|
|
@ -221,6 +224,7 @@ class RustMatrixClient(
|
|||
innerRoomListService = innerRoomListService,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
),
|
||||
roomSyncSubscriber = roomSyncSubscriber,
|
||||
)
|
||||
|
||||
private val verificationService = RustSessionVerificationService(
|
||||
|
|
@ -238,6 +242,7 @@ class RustMatrixClient(
|
|||
dispatchers = dispatchers,
|
||||
systemClock = clock,
|
||||
roomContentForwarder = RoomContentForwarder(innerRoomListService),
|
||||
roomSyncSubscriber = roomSyncSubscriber,
|
||||
isKeyBackupEnabled = { client.encryption().use { it.backupState() == BackupState.ENABLED } },
|
||||
getSessionData = { sessionStore.getSession(sessionId.value)!! },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,18 +19,19 @@ package io.element.android.libraries.matrix.impl.room
|
|||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.RequiredState
|
||||
import org.matrix.rustcomponents.sdk.RoomListService
|
||||
import org.matrix.rustcomponents.sdk.RoomListServiceInterface
|
||||
import org.matrix.rustcomponents.sdk.RoomSubscription
|
||||
import timber.log.Timber
|
||||
|
||||
private const val DEFAULT_TIMELINE_LIMIT = 20u
|
||||
|
||||
class RoomSyncSubscriber(
|
||||
private val roomListService: RoomListService,
|
||||
private val roomListService: RoomListServiceInterface,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) {
|
||||
private val subscriptionCounts = HashMap<RoomId, Int>()
|
||||
|
|
@ -38,8 +39,10 @@ class RoomSyncSubscriber(
|
|||
|
||||
private val settings = RoomSubscription(
|
||||
requiredState = listOf(
|
||||
RequiredState(key = EventType.STATE_ROOM_CANONICAL_ALIAS, value = ""),
|
||||
RequiredState(key = EventType.STATE_ROOM_NAME, value = ""),
|
||||
RequiredState(key = EventType.STATE_ROOM_TOPIC, value = ""),
|
||||
RequiredState(key = EventType.STATE_ROOM_AVATAR, value = ""),
|
||||
RequiredState(key = EventType.STATE_ROOM_CANONICAL_ALIAS, value = ""),
|
||||
RequiredState(key = EventType.STATE_ROOM_JOIN_RULES, value = ""),
|
||||
RequiredState(key = EventType.STATE_ROOM_POWER_LEVELS, value = ""),
|
||||
),
|
||||
|
|
@ -65,6 +68,27 @@ class RoomSyncSubscriber(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun batchSubscribe(roomIds: List<RoomId>) = mutex.withLock {
|
||||
withContext(dispatchers.io) {
|
||||
for (roomId in roomIds) {
|
||||
try {
|
||||
val currentSubscription = subscriptionCounts.getOrElse(roomId) { 0 }
|
||||
if (currentSubscription == 0) {
|
||||
Timber.d("Subscribing to room $roomId}")
|
||||
roomListService.room(roomId.value).use { roomListItem ->
|
||||
roomListItem.subscribe(settings)
|
||||
}
|
||||
}
|
||||
subscriptionCounts[roomId] = currentSubscription + 1
|
||||
} catch (cancellationException: CancellationException) {
|
||||
throw cancellationException
|
||||
} catch (exception: Exception) {
|
||||
Timber.e("Failed to subscribe to room $roomId")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun unsubscribe(roomId: RoomId) = mutex.withLock {
|
||||
withContext(dispatchers.io) {
|
||||
try {
|
||||
|
|
@ -84,4 +108,9 @@ class RoomSyncSubscriber(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isSubscribedTo(roomId: RoomId): Boolean {
|
||||
val subscriptionCount = subscriptionCounts[roomId] ?: return false
|
||||
return subscriptionCount > 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class RustRoomFactory(
|
|||
private val roomContentForwarder: RoomContentForwarder,
|
||||
private val roomListService: RoomListService,
|
||||
private val innerRoomListService: InnerRoomListService,
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber,
|
||||
private val isKeyBackupEnabled: suspend () -> Boolean,
|
||||
private val getSessionData: suspend () -> SessionData,
|
||||
) {
|
||||
|
|
@ -59,8 +60,6 @@ class RustRoomFactory(
|
|||
|
||||
private val matrixRoomInfoMapper = MatrixRoomInfoMapper()
|
||||
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber = RoomSyncSubscriber(innerRoomListService, dispatchers)
|
||||
|
||||
private val eventFilters = TimelineConfig.excludedEvents
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.let { listStateEventType ->
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import org.matrix.rustcomponents.sdk.use
|
|||
class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) {
|
||||
suspend fun create(roomListItem: RoomListItem): RoomSummary {
|
||||
val roomInfo = roomListItem.roomInfo()
|
||||
val latestRoomMessage = roomListItem.latestEvent()?.use {
|
||||
roomMessageFactory.create(it)
|
||||
val latestRoomMessage = roomListItem.latestEvent().use { event ->
|
||||
roomMessageFactory.create(event)
|
||||
}
|
||||
return RoomSummary(
|
||||
roomId = RoomId(roomInfo.id),
|
||||
|
|
|
|||
|
|
@ -113,9 +113,7 @@ class RoomSummaryListProcessor(
|
|||
val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem ->
|
||||
buildAndCacheRoomSummaryForRoomListItem(roomListItem)
|
||||
}
|
||||
if (builtRoomSummary != null) {
|
||||
roomSummariesByIdentifier[identifier] = builtRoomSummary
|
||||
} else {
|
||||
if (builtRoomSummary == null) {
|
||||
roomSummariesByIdentifier.remove(identifier)
|
||||
}
|
||||
return builtRoomSummary
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@
|
|||
|
||||
package io.element.android.libraries.matrix.impl.roomlist
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.loadAllIncrementally
|
||||
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
|
|
@ -41,6 +43,7 @@ internal class RustRoomListService(
|
|||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val sessionDispatcher: CoroutineDispatcher,
|
||||
private val roomListFactory: RoomListFactory,
|
||||
private val roomSyncSubscriber: RoomSyncSubscriber,
|
||||
) : RoomListService {
|
||||
override fun createRoomList(
|
||||
pageSize: Int,
|
||||
|
|
@ -58,6 +61,14 @@ internal class RustRoomListService(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun subscribeToVisibleRooms(roomIds: List<RoomId>) {
|
||||
val toSubscribe = roomIds.filterNot { roomSyncSubscriber.isSubscribedTo(it) }
|
||||
if (toSubscribe.isNotEmpty()) {
|
||||
Timber.d("Subscribe to ${toSubscribe.size} rooms: $toSubscribe")
|
||||
roomSyncSubscriber.batchSubscribe(toSubscribe)
|
||||
}
|
||||
}
|
||||
|
||||
override val allRooms: DynamicRoomList = roomListFactory.createRoomList(
|
||||
pageSize = DEFAULT_PAGE_SIZE,
|
||||
coroutineContext = sessionDispatcher,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import org.matrix.rustcomponents.sdk.RoomListServiceStateListener
|
|||
import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicatorListener
|
||||
import org.matrix.rustcomponents.sdk.RoomMember
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode
|
||||
import org.matrix.rustcomponents.sdk.RoomSubscription
|
||||
import org.matrix.rustcomponents.sdk.TaskHandle
|
||||
|
||||
// NOTE: this class is using a fake implementation of a Rust SDK interface which returns actual Rust objects with pointers.
|
||||
|
|
@ -267,4 +268,6 @@ class FakeRoomListItem(
|
|||
override suspend fun latestEvent(): EventTimelineItem? {
|
||||
return latestEvent
|
||||
}
|
||||
|
||||
override fun subscribe(settings: RoomSubscription?) = Unit
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue