Skip to content

Commit

Permalink
Merge pull request #3501 from element-hq/bma/testRustMatrixClient
Browse files Browse the repository at this point in the history
Test RustMatrixClient and other classes in the matrix module
  • Loading branch information
bmarty authored Sep 20, 2024
2 parents 9571261 + 88a30eb commit dfe9323
Show file tree
Hide file tree
Showing 70 changed files with 1,598 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ sealed interface NotificationContent {
data object RoomHistoryVisibility : StateEvent
data object RoomJoinRules : StateEvent
data class RoomMemberContent(
val userId: String,
val userId: UserId,
val membershipState: RoomMembershipState
) : StateEvent

Expand All @@ -108,6 +108,10 @@ sealed interface NotificationContent {
data object SpaceChild : StateEvent
data object SpaceParent : StateEvent
}

data class Invite(
val senderId: UserId,
) : NotificationContent
}

enum class CallNotifyType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ package io.element.android.libraries.matrix.api.notification

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

interface NotificationService {
suspend fun getNotification(userId: SessionId, roomId: RoomId, eventId: EventId): Result<NotificationData?>
suspend fun getNotification(roomId: RoomId, eventId: EventId): Result<NotificationData?>
}
2 changes: 2 additions & 0 deletions libraries/matrix/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ dependencies {
testImplementation(libs.test.junit)
testImplementation(libs.test.truth)
testImplementation(libs.test.robolectric)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.preferences.test)
testImplementation(projects.libraries.sessionStorage.implMemory)
testImplementation(projects.libraries.sessionStorage.test)
testImplementation(projects.services.analytics.test)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/

package io.element.android.libraries.matrix.impl

import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import org.matrix.rustcomponents.sdk.ClientBuilder
import javax.inject.Inject

interface ClientBuilderProvider {
fun provide(): ClientBuilder
}

@ContributesBinding(AppScope::class)
class RustClientBuilderProvider @Inject constructor() : ClientBuilderProvider {
override fun provide(): ClientBuilder {
return ClientBuilder()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ 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.TimelineEventTypeFilterFactory
import io.element.android.libraries.matrix.impl.room.preview.RoomPreviewMapper
import io.element.android.libraries.matrix.impl.roomdirectory.RustRoomDirectoryService
import io.element.android.libraries.matrix.impl.roomlist.RoomListFactory
Expand Down Expand Up @@ -115,14 +116,15 @@ import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
@OptIn(ExperimentalCoroutinesApi::class)
class RustMatrixClient(
private val client: Client,
private val syncService: ClientSyncService,
private val baseDirectory: File,
private val sessionStore: SessionStore,
private val appCoroutineScope: CoroutineScope,
private val dispatchers: CoroutineDispatchers,
private val baseDirectory: File,
baseCacheDirectory: File,
private val clock: SystemClock,
private val sessionDelegate: RustClientSessionDelegate,
syncService: ClientSyncService,
dispatchers: CoroutineDispatchers,
baseCacheDirectory: File,
clock: SystemClock,
timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
) : MatrixClient {
override val sessionId: UserId = UserId(client.userId())
override val deviceId: DeviceId = DeviceId(client.deviceId())
Expand All @@ -138,7 +140,7 @@ class RustMatrixClient(
)
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(syncService)
private val notificationClient = runBlocking { client.notificationClient(notificationProcessSetup) }
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
private val notificationService = RustNotificationService(notificationClient, dispatchers, clock)
private val notificationSettingsService = RustNotificationSettingsService(client, dispatchers)
.apply { start() }
private val encryptionService = RustEncryptionService(
Expand Down Expand Up @@ -185,6 +187,7 @@ class RustMatrixClient(
systemClock = clock,
roomContentForwarder = RoomContentForwarder(innerRoomListService),
roomSyncSubscriber = roomSyncSubscriber,
timelineEventTypeFilterFactory = timelineEventTypeFilterFactory,
)

override val mediaLoader: MatrixMediaLoader = RustMediaLoader(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.impl.certificates.UserCertificatesPro
import io.element.android.libraries.matrix.impl.paths.SessionPaths
import io.element.android.libraries.matrix.impl.paths.getSessionPaths
import io.element.android.libraries.matrix.impl.proxy.ProxyProvider
import io.element.android.libraries.matrix.impl.room.TimelineEventTypeFilterFactory
import io.element.android.libraries.matrix.impl.util.anonymizedTokens
import io.element.android.libraries.network.useragent.UserAgentProvider
import io.element.android.libraries.sessionstorage.api.SessionData
Expand Down Expand Up @@ -45,6 +46,8 @@ class RustMatrixClientFactory @Inject constructor(
private val clock: SystemClock,
private val utdTracker: UtdTracker,
private val featureFlagService: FeatureFlagService,
private val timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
private val clientBuilderProvider: ClientBuilderProvider,
) {
suspend fun create(sessionData: SessionData): RustMatrixClient = withContext(coroutineDispatchers.io) {
val sessionDelegate = RustClientSessionDelegate(sessionStore, appCoroutineScope, coroutineDispatchers)
Expand All @@ -68,14 +71,15 @@ class RustMatrixClientFactory @Inject constructor(

RustMatrixClient(
client = client,
syncService = syncService,
baseDirectory = baseDirectory,
sessionStore = sessionStore,
appCoroutineScope = appCoroutineScope,
sessionDelegate = sessionDelegate,
syncService = syncService,
dispatchers = coroutineDispatchers,
baseDirectory = baseDirectory,
baseCacheDirectory = cacheDirectory,
clock = clock,
sessionDelegate = sessionDelegate,
timelineEventTypeFilterFactory = timelineEventTypeFilterFactory,
).also {
Timber.tag(it.toString()).d("Creating Client with access token '$anonymizedAccessToken' and refresh token '$anonymizedRefreshToken'")
}
Expand All @@ -86,7 +90,7 @@ class RustMatrixClientFactory @Inject constructor(
passphrase: String?,
slidingSyncType: ClientBuilderSlidingSync,
): ClientBuilder {
return ClientBuilder()
return clientBuilderProvider.provide()
.sessionPaths(
dataPath = sessionPaths.fileDirectory.absolutePath,
cachePath = sessionPaths.cacheDirectory.absolutePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ 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
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.services.toolbox.api.systemclock.SystemClock
import org.matrix.rustcomponents.sdk.NotificationEvent
import org.matrix.rustcomponents.sdk.NotificationItem
import org.matrix.rustcomponents.sdk.use

class NotificationMapper(
sessionId: SessionId,
private val clock: SystemClock,
) {
private val notificationContentMapper = NotificationContentMapper(sessionId)
private val notificationContentMapper = NotificationContentMapper()

fun map(
eventId: EventId,
Expand Down Expand Up @@ -56,15 +54,14 @@ class NotificationMapper(
}
}

class NotificationContentMapper(private val sessionId: SessionId) {
class NotificationContentMapper {
private val timelineEventToNotificationContentMapper = TimelineEventToNotificationContentMapper()

fun map(notificationEvent: NotificationEvent): NotificationContent =
when (notificationEvent) {
is NotificationEvent.Timeline -> timelineEventToNotificationContentMapper.map(notificationEvent.event)
is NotificationEvent.Invite -> NotificationContent.StateEvent.RoomMemberContent(
userId = sessionId.value,
membershipState = RoomMembershipState.INVITE,
is NotificationEvent.Invite -> NotificationContent.Invite(
senderId = UserId(notificationEvent.sender),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ 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
Expand All @@ -19,15 +18,13 @@ import org.matrix.rustcomponents.sdk.NotificationClient
import org.matrix.rustcomponents.sdk.use

class RustNotificationService(
sessionId: SessionId,
private val notificationClient: NotificationClient,
private val dispatchers: CoroutineDispatchers,
clock: SystemClock,
) : NotificationService {
private val notificationMapper: NotificationMapper = NotificationMapper(sessionId, clock)
private val notificationMapper: NotificationMapper = NotificationMapper(clock)

override suspend fun getNotification(
userId: SessionId,
roomId: RoomId,
eventId: EventId,
): Result<NotificationData?> = withContext(dispatchers.io) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ import org.matrix.rustcomponents.sdk.StateEventContent
import org.matrix.rustcomponents.sdk.TimelineEvent
import org.matrix.rustcomponents.sdk.TimelineEventType
import org.matrix.rustcomponents.sdk.use
import javax.inject.Inject

class TimelineEventToNotificationContentMapper @Inject constructor() {
class TimelineEventToNotificationContentMapper {
fun map(timelineEvent: TimelineEvent): NotificationContent {
return timelineEvent.use {
timelineEvent.eventType().use { eventType ->
Expand Down Expand Up @@ -52,7 +51,10 @@ private fun StateEventContent.toContent(): NotificationContent.StateEvent {
StateEventContent.RoomHistoryVisibility -> NotificationContent.StateEvent.RoomHistoryVisibility
StateEventContent.RoomJoinRules -> NotificationContent.StateEvent.RoomJoinRules
is StateEventContent.RoomMemberContent -> {
NotificationContent.StateEvent.RoomMemberContent(userId, RoomMemberMapper.mapMembership(membershipState))
NotificationContent.StateEvent.RoomMemberContent(
userId = UserId(userId),
membershipState = RoomMemberMapper.mapMembership(membershipState),
)
}
StateEventContent.RoomName -> NotificationContent.StateEvent.RoomName
StateEventContent.RoomPinnedEvents -> NotificationContent.StateEvent.RoomPinnedEvents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ 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.RoomListServiceInterface
import org.matrix.rustcomponents.sdk.RoomListService
import org.matrix.rustcomponents.sdk.RoomSubscription
import timber.log.Timber

private const val DEFAULT_TIMELINE_LIMIT = 20u

class RoomSyncSubscriber(
private val roomListService: RoomListServiceInterface,
private val roomListService: RoomListService,
private val dispatchers: CoroutineDispatchers,
) {
private val subscribedRoomIds = mutableSetOf<RoomId>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.FilterTimelineEventType
import org.matrix.rustcomponents.sdk.Membership
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.RoomListException
import org.matrix.rustcomponents.sdk.RoomListItem
import org.matrix.rustcomponents.sdk.TimelineEventTypeFilter
import timber.log.Timber
import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService

Expand All @@ -49,6 +47,7 @@ class RustRoomFactory(
private val roomListService: RoomListService,
private val innerRoomListService: InnerRoomListService,
private val roomSyncSubscriber: RoomSyncSubscriber,
private val timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
) {
@OptIn(ExperimentalCoroutinesApi::class)
private val dispatcher = dispatchers.io.limitedParallelism(1)
Expand All @@ -74,11 +73,7 @@ class RustRoomFactory(
private val eventFilters = TimelineConfig.excludedEvents
.takeIf { it.isNotEmpty() }
?.let { listStateEventType ->
TimelineEventTypeFilter.exclude(
listStateEventType.map { stateEventType ->
FilterTimelineEventType.State(stateEventType.map())
}
)
timelineEventTypeFilterFactory.create(listStateEventType)
}

suspend fun destroy() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/

package io.element.android.libraries.matrix.impl.room

import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.room.StateEventType
import org.matrix.rustcomponents.sdk.FilterTimelineEventType
import org.matrix.rustcomponents.sdk.TimelineEventTypeFilter
import javax.inject.Inject

interface TimelineEventTypeFilterFactory {
fun create(listStateEventType: List<StateEventType>): TimelineEventTypeFilter
}

@ContributesBinding(AppScope::class)
class RustTimelineEventTypeFilterFactory @Inject constructor() : TimelineEventTypeFilterFactory {
override fun create(listStateEventType: List<StateEventType>): TimelineEventTypeFilter {
return TimelineEventTypeFilter.exclude(
listStateEventType.map { stateEventType ->
FilterTimelineEventType.State(stateEventType.map())
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import io.element.android.libraries.matrix.api.room.message.RoomMessage
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
import org.matrix.rustcomponents.sdk.EventTimelineItem as RustEventTimelineItem

class RoomMessageFactory {
class RoomMessageFactory(
private val eventTimelineItemMapper: EventTimelineItemMapper = EventTimelineItemMapper(),
) {
fun create(eventTimelineItem: RustEventTimelineItem?): RoomMessage? {
eventTimelineItem ?: return null
val mappedTimelineItem = EventTimelineItemMapper().map(eventTimelineItem)
val mappedTimelineItem = eventTimelineItemMapper.map(eventTimelineItem)
return RoomMessage(
eventId = mappedTimelineItem.eventId ?: return null,
event = mappedTimelineItem,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package io.element.android.libraries.matrix.impl.roomdirectory

import io.element.android.libraries.matrix.api.roomdirectory.RoomDescription
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
Expand All @@ -17,10 +18,12 @@ import timber.log.Timber
import kotlin.coroutines.CoroutineContext

class RoomDirectorySearchProcessor(
private val roomDescriptions: MutableSharedFlow<List<RoomDescription>>,
private val coroutineContext: CoroutineContext,
private val roomDescriptionMapper: RoomDescriptionMapper,
) {
private val roomDescriptions: MutableSharedFlow<List<RoomDescription>> = MutableSharedFlow(replay = 1)
val roomDescriptionsFlow: Flow<List<RoomDescription>> = roomDescriptions

private val roomDescriptionMapper: RoomDescriptionMapper = RoomDescriptionMapper()
private val mutex = Mutex()

suspend fun postUpdates(updates: List<RoomDirectorySearchEntryUpdate>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@

package io.element.android.libraries.matrix.impl.roomdirectory

import io.element.android.libraries.matrix.api.roomdirectory.RoomDescription
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
Expand All @@ -27,8 +25,7 @@ class RustRoomDirectoryList(
private val coroutineContext: CoroutineContext,
) : RoomDirectoryList {
private val hasMoreToLoad = MutableStateFlow(true)
private val items = MutableSharedFlow<List<RoomDescription>>(replay = 1)
private val processor = RoomDirectorySearchProcessor(items, coroutineContext, RoomDescriptionMapper())
private val processor = RoomDirectorySearchProcessor(coroutineContext)

init {
launchIn(coroutineScope)
Expand Down Expand Up @@ -77,7 +74,7 @@ class RustRoomDirectoryList(
}

override val state: Flow<RoomDirectoryList.State> =
combine(hasMoreToLoad, items) { hasMoreToLoad, items ->
combine(hasMoreToLoad, processor.roomDescriptionsFlow) { hasMoreToLoad, items ->
RoomDirectoryList.State(
hasMoreToLoad = hasMoreToLoad,
items = items
Expand Down
Loading

0 comments on commit dfe9323

Please sign in to comment.