Notification events resolving and rendering in batches (#4722)
- Use `NotiticationService.getNotifications()` function so we resolve the events in bulk. - Added `NotifierResolverQueue` to group the notifications to resolve based on a debounce strategy. - Batch rendering of these events as notifications.
This commit is contained in:
parent
f0c9f8294a
commit
f455085e08
30 changed files with 882 additions and 523 deletions
|
|
@ -152,7 +152,7 @@ class RustMatrixClient(
|
|||
)
|
||||
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(innerSyncService)
|
||||
private val innerNotificationClient = runBlocking { innerClient.notificationClient(notificationProcessSetup) }
|
||||
private val notificationService = RustNotificationService(innerNotificationClient, dispatchers, clock)
|
||||
private val notificationService = RustNotificationService(sessionId, innerNotificationClient, dispatchers, clock)
|
||||
private val notificationSettingsService = RustNotificationSettingsService(innerClient, sessionCoroutineScope, dispatchers)
|
||||
private val encryptionService = RustEncryptionService(
|
||||
client = innerClient,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.impl.notification
|
|||
import io.element.android.libraries.core.bool.orFalse
|
||||
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.NotificationContent
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationData
|
||||
|
|
@ -25,6 +26,7 @@ class NotificationMapper(
|
|||
private val notificationContentMapper = NotificationContentMapper()
|
||||
|
||||
fun map(
|
||||
sessionId: SessionId,
|
||||
eventId: EventId,
|
||||
roomId: RoomId,
|
||||
notificationItem: NotificationItem
|
||||
|
|
@ -35,6 +37,7 @@ class NotificationMapper(
|
|||
activeMembersCount = item.roomInfo.joinedMembersCount.toInt(),
|
||||
)
|
||||
NotificationData(
|
||||
sessionId = sessionId,
|
||||
eventId = eventId,
|
||||
// FIXME once the `NotificationItem` in the SDK returns the thread id
|
||||
threadId = null,
|
||||
|
|
|
|||
|
|
@ -10,28 +10,45 @@ package io.element.android.libraries.matrix.impl.notification
|
|||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
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.notification.NotificationData
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.NotificationClient
|
||||
import org.matrix.rustcomponents.sdk.use
|
||||
import org.matrix.rustcomponents.sdk.NotificationItemsRequest
|
||||
import timber.log.Timber
|
||||
|
||||
class RustNotificationService(
|
||||
private val sessionId: SessionId,
|
||||
private val notificationClient: NotificationClient,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
clock: SystemClock,
|
||||
) : NotificationService {
|
||||
private val notificationMapper: NotificationMapper = NotificationMapper(clock)
|
||||
|
||||
override suspend fun getNotification(
|
||||
roomId: RoomId,
|
||||
eventId: EventId,
|
||||
): Result<NotificationData?> = withContext(dispatchers.io) {
|
||||
override suspend fun getNotifications(
|
||||
ids: Map<RoomId, List<EventId>>
|
||||
): Result<Map<EventId, NotificationData>> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
val item = notificationClient.getNotification(roomId.value, eventId.value)
|
||||
item?.use {
|
||||
notificationMapper.map(eventId, roomId, it)
|
||||
val requests = ids.map { (roomId, eventIds) ->
|
||||
NotificationItemsRequest(
|
||||
roomId = roomId.value,
|
||||
eventIds = eventIds.map { it.value }
|
||||
)
|
||||
}
|
||||
val items = notificationClient.getNotifications(requests)
|
||||
buildMap {
|
||||
val eventIds = requests.flatMap { it.eventIds }
|
||||
for (eventId in eventIds) {
|
||||
val item = items[eventId]
|
||||
if (item != null) {
|
||||
val roomId = RoomId(requests.find { it.eventIds.contains(eventId) }?.roomId!!)
|
||||
put(EventId(eventId), notificationMapper.map(sessionId, EventId(eventId), roomId, item))
|
||||
} else {
|
||||
Timber.e("Could not retrieve event for notification with $eventId")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,15 @@
|
|||
|
||||
package io.element.android.libraries.matrix.impl.fixtures.fakes
|
||||
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import org.matrix.rustcomponents.sdk.NoPointer
|
||||
import org.matrix.rustcomponents.sdk.NotificationClient
|
||||
import org.matrix.rustcomponents.sdk.NotificationItem
|
||||
import org.matrix.rustcomponents.sdk.NotificationItemsRequest
|
||||
|
||||
class FakeRustNotificationClient(
|
||||
var notificationItemResult: NotificationItem? = null
|
||||
var notificationItemResult: Map<String, NotificationItem> = emptyMap(),
|
||||
) : NotificationClient(NoPointer) {
|
||||
override suspend fun getNotification(roomId: String, eventId: String): NotificationItem? = simulateLongTask {
|
||||
notificationItemResult
|
||||
override suspend fun getNotifications(requests: List<NotificationItemsRequest>): Map<String, NotificationItem> {
|
||||
return notificationItemResult
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustNotificat
|
|||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_MESSAGE
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
||||
|
|
@ -28,12 +29,12 @@ class RustNotificationServiceTest {
|
|||
@Test
|
||||
fun test() = runTest {
|
||||
val notificationClient = FakeRustNotificationClient(
|
||||
notificationItemResult = aRustNotificationItem(),
|
||||
notificationItemResult = mapOf(AN_EVENT_ID.value to aRustNotificationItem()),
|
||||
)
|
||||
val sut = createRustNotificationService(
|
||||
notificationClient = notificationClient,
|
||||
)
|
||||
val result = sut.getNotification(A_ROOM_ID, AN_EVENT_ID).getOrThrow()!!
|
||||
val result = sut.getNotifications(mapOf(A_ROOM_ID to listOf(AN_EVENT_ID))).getOrThrow()[AN_EVENT_ID]!!
|
||||
assertThat(result.isEncrypted).isTrue()
|
||||
assertThat(result.content).isEqualTo(
|
||||
NotificationContent.MessageLike.RoomMessage(
|
||||
|
|
@ -51,6 +52,7 @@ class RustNotificationServiceTest {
|
|||
clock: SystemClock = FakeSystemClock(),
|
||||
) =
|
||||
RustNotificationService(
|
||||
sessionId = A_SESSION_ID,
|
||||
notificationClient = notificationClient,
|
||||
dispatchers = testCoroutineDispatchers(),
|
||||
clock = clock,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue