Merge develop into feature/fga/dagger_setup

This commit is contained in:
ganfra 2022-12-19 16:14:14 +01:00
commit 4c88d8e3c2
214 changed files with 2662 additions and 1833 deletions

View file

@ -13,7 +13,7 @@ import io.element.android.x.matrix.util.logError
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.AuthenticationService
import org.matrix.rustcomponents.sdk.Client
@ -101,4 +101,4 @@ class Matrix @Inject constructor(
baseDirectory = baseDirectory,
)
}
}
}

View file

@ -10,13 +10,19 @@ import io.element.android.x.matrix.room.RoomSummaryDataSource
import io.element.android.x.matrix.room.RustRoomSummaryDataSource
import io.element.android.x.matrix.session.SessionStore
import io.element.android.x.matrix.sync.SlidingSyncObserverProxy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.*
import timber.log.Timber
import java.io.Closeable
import java.io.File
import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.ClientDelegate
import org.matrix.rustcomponents.sdk.MediaSource
import org.matrix.rustcomponents.sdk.RequiredState
import org.matrix.rustcomponents.sdk.SlidingSyncMode
import org.matrix.rustcomponents.sdk.SlidingSyncViewBuilder
import org.matrix.rustcomponents.sdk.StoppableSpawn
import timber.log.Timber
class MatrixClient internal constructor(
private val client: Client,
@ -60,7 +66,7 @@ class MatrixClient internal constructor(
.slidingSync()
.homeserver("https://slidingsync.lab.element.dev")
.withCommonExtensions()
//.coldCache("ElementX")
// .coldCache("ElementX")
.addView(slidingSyncView)
.build()
@ -148,6 +154,7 @@ class MatrixClient internal constructor(
}
}
@OptIn(ExperimentalUnsignedTypes::class)
suspend fun loadMediaContentForSource(source: MediaSource): Result<ByteArray> =
withContext(dispatchers.io) {
runCatching {
@ -155,6 +162,7 @@ class MatrixClient internal constructor(
}
}
@OptIn(ExperimentalUnsignedTypes::class)
suspend fun loadMediaThumbnailForSource(
source: MediaSource,
width: Long,

View file

@ -1,15 +0,0 @@
package io.element.android.x.matrix
import android.util.Log
import org.matrix.rustcomponents.sdk.Client
import org.matrix.rustcomponents.sdk.Room
class RoomWrapper(
private val client: Client
) {
fun getRoom(roomId: String): Room? {
val rooms = client.rooms()
Log.d(LOG_TAG, "We have ${rooms.size} rooms")
return rooms.firstOrNull { it.id() == roomId }
}
}

View file

@ -3,4 +3,4 @@ package io.element.android.x.matrix.core
import java.io.Serializable
@JvmInline
value class EventId(val value: String) : Serializable
value class EventId(val value: String) : Serializable

View file

@ -80,15 +80,15 @@ object MatrixPatterns {
// list of patterns to find some matrix item.
val MATRIX_PATTERNS = listOf(
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_ALIAS,
PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_MATRIX_TO_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ID,
PATTERN_CONTAIN_APP_LINK_PERMALINK_ROOM_ALIAS,
PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_ALIAS,
PATTERN_CONTAIN_MATRIX_ROOM_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER,
PATTERN_CONTAIN_MATRIX_GROUP_IDENTIFIER
)
/**
@ -129,9 +129,9 @@ object MatrixPatterns {
*/
fun isEventId(str: String?): Boolean {
return str != null &&
(str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
(str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V3 ||
str matches PATTERN_CONTAIN_MATRIX_EVENT_IDENTIFIER_V4)
}
/**

View file

@ -3,4 +3,4 @@ package io.element.android.x.matrix.core
import java.io.Serializable
@JvmInline
value class RoomId(val value: String): Serializable
value class RoomId(val value: String) : Serializable

View file

@ -3,4 +3,4 @@ package io.element.android.x.matrix.core
import java.io.Serializable
@JvmInline
value class UserId(val value: String): Serializable
value class UserId(val value: String) : Serializable

View file

@ -36,4 +36,4 @@ internal class MediaFetcher(
)
}
}
}
}

View file

@ -7,4 +7,4 @@ internal class MediaKeyer : Keyer<MediaResolver.Meta> {
override fun key(data: MediaResolver.Meta, options: Options): String? {
return "${data.source.url()}_${data.kind}"
}
}
}

View file

@ -24,7 +24,6 @@ interface MediaResolver {
suspend fun resolve(meta: Meta): ByteArray?
}
internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver {
override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? {
@ -43,6 +42,4 @@ internal class RustMediaResolver(private val client: MatrixClient) : MediaResolv
)
}.getOrNull()
}
}
}

View file

@ -3,8 +3,8 @@ package io.element.android.x.matrix.permalink
import android.net.Uri
import android.net.UrlQuerySanitizer
import io.element.android.x.matrix.core.MatrixPatterns
import timber.log.Timber
import java.net.URLDecoder
import timber.log.Timber
/**
* This class turns a uri to a [PermalinkData].
@ -43,12 +43,12 @@ object PermalinkParser {
// we are limiting to 2 params
val params = safeFragment
.split(MatrixPatterns.SEP_REGEX)
.filter { it.isNotEmpty() }
.take(2)
.split(MatrixPatterns.SEP_REGEX)
.filter { it.isNotEmpty() }
.take(2)
val decodedParams = params
.map { URLDecoder.decode(it, "UTF-8") }
.map { URLDecoder.decode(it, "UTF-8") }
val identifier = params.getOrNull(0)
val decodedIdentifier = decodedParams.getOrNull(0)
@ -61,10 +61,10 @@ object PermalinkParser {
}
MatrixPatterns.isRoomAlias(decodedIdentifier) -> {
PermalinkData.RoomLink(
roomIdOrAlias = decodedIdentifier,
isRoomAlias = true,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
roomIdOrAlias = decodedIdentifier,
isRoomAlias = true,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
)
}
else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
@ -83,16 +83,16 @@ object PermalinkParser {
val token = signValidUri.getQueryParameter("token") ?: throw IllegalArgumentException()
val privateKey = signValidUri.getQueryParameter("private_key") ?: throw IllegalArgumentException()
PermalinkData.RoomEmailInviteLink(
roomId = identifier,
email = email!!,
signUrl = signUrl!!,
roomName = paramList.firstOrNull { it.first == "room_name" }?.second,
inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second,
roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second,
roomType = paramList.firstOrNull { it.first == "room_type" }?.second,
identityServer = identityServerHost,
token = token,
privateKey = privateKey
roomId = identifier,
email = email!!,
signUrl = signUrl!!,
roomName = paramList.firstOrNull { it.first == "room_name" }?.second,
inviterName = paramList.firstOrNull { it.first == "inviter_name" }?.second,
roomAvatarUrl = paramList.firstOrNull { it.first == "room_avatar_url" }?.second,
roomType = paramList.firstOrNull { it.first == "room_type" }?.second,
identityServer = identityServerHost,
token = token,
privateKey = privateKey
)
} catch (failure: Throwable) {
Timber.i("## Permalink: Failed to parse permalink $signUrl")
@ -100,29 +100,29 @@ object PermalinkParser {
}
} else {
PermalinkData.RoomLink(
roomIdOrAlias = identifier,
isRoomAlias = false,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
roomIdOrAlias = identifier,
isRoomAlias = false,
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
viaParameters = viaQueryParameters
)
}
}
private fun safeExtractParams(fragment: String) =
fragment.substringAfter("?").split('&').mapNotNull {
val splitNameValue = it.split("=")
if (splitNameValue.size == 2) {
Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8"))
} else null
}
fragment.substringAfter("?").split('&').mapNotNull {
val splitNameValue = it.split("=")
if (splitNameValue.size == 2) {
Pair(splitNameValue[0], URLDecoder.decode(splitNameValue[1], "UTF-8"))
} else null
}
private fun String.getViaParameters(): List<String> {
return UrlQuerySanitizer(this)
.parameterList
.filter {
it.mParameter == "via"
}.map {
URLDecoder.decode(it.mValue, "UTF-8")
}
.parameterList
.filter {
it.mParameter == "via"
}.map {
URLDecoder.decode(it.mValue, "UTF-8")
}
}
}

View file

@ -9,7 +9,11 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.*
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
import org.matrix.rustcomponents.sdk.UpdateSummary
import org.matrix.rustcomponents.sdk.genTransactionId
import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown
class MatrixRoom(
private val slidingSyncUpdateFlow: Flow<UpdateSummary>,
@ -84,7 +88,7 @@ class MatrixRoom(
suspend fun editMessage(originalEventId: String, message: String): Result<Unit> = withContext(coroutineDispatchers.io) {
val transactionId = genTransactionId()
val content = messageEventContentFromMarkdown(message)
// val content = messageEventContentFromMarkdown(message)
runCatching {
room.edit(/* TODO use content */ message, originalEventId, transactionId)
}
@ -92,16 +96,16 @@ class MatrixRoom(
suspend fun replyMessage(eventId: String, message: String): Result<Unit> = withContext(coroutineDispatchers.io) {
val transactionId = genTransactionId()
val content = messageEventContentFromMarkdown(message)
// val content = messageEventContentFromMarkdown(message)
runCatching {
room.sendReply(/* TODO use content */ message, eventId, transactionId)
}
}
suspend fun redactEvent(eventId: String, reason: String? = null, ) = withContext(coroutineDispatchers.io) {
suspend fun redactEvent(eventId: String, reason: String? = null) = withContext(coroutineDispatchers.io) {
val transactionId = genTransactionId()
runCatching {
room.redact(eventId, reason, transactionId)
}
}
}
}

View file

@ -9,7 +9,6 @@ import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.TimelineDiff
import org.matrix.rustcomponents.sdk.TimelineListener
fun Room.timelineDiff(scope: CoroutineScope): Flow<TimelineDiff> = callbackFlow {
val listener = object : TimelineListener {
override fun onUpdate(update: TimelineDiff) {
@ -22,6 +21,4 @@ fun Room.timelineDiff(scope: CoroutineScope): Flow<TimelineDiff> = callbackFlow
awaitClose {
removeTimeline()
}
}

View file

@ -2,7 +2,6 @@ package io.element.android.x.matrix.room
import io.element.android.x.matrix.core.RoomId
sealed interface RoomSummary {
data class Empty(val identifier: String) : RoomSummary
data class Filled(val details: RoomSummaryDetails) : RoomSummary
@ -13,7 +12,6 @@ sealed interface RoomSummary {
is Filled -> details.roomId.value
}
}
}
data class RoomSummaryDetails(

View file

@ -3,12 +3,28 @@ package io.element.android.x.matrix.room
import io.element.android.x.core.coroutine.CoroutineDispatchers
import io.element.android.x.matrix.sync.roomListDiff
import io.element.android.x.matrix.sync.state
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.matrix.rustcomponents.sdk.*
import timber.log.Timber
import java.io.Closeable
import java.util.*
import java.util.Collections
import java.util.UUID
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.RoomListEntry
import org.matrix.rustcomponents.sdk.SlidingSync
import org.matrix.rustcomponents.sdk.SlidingSyncState
import org.matrix.rustcomponents.sdk.SlidingSyncView
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff
import org.matrix.rustcomponents.sdk.UpdateSummary
import timber.log.Timber
interface RoomSummaryDataSource {
fun roomSummaries(): Flow<List<RoomSummary>>
@ -56,7 +72,6 @@ internal class RustRoomSummaryDataSource(
Timber.v("New sliding sync state: $slidingSyncState")
state.value = slidingSyncState
}.launchIn(coroutineScope)
}
fun stopSync() {
@ -67,6 +82,7 @@ internal class RustRoomSummaryDataSource(
coroutineScope.cancel()
}
@OptIn(FlowPreview::class)
override fun roomSummaries(): Flow<List<RoomSummary>> {
return roomSummaries.sample(50)
}
@ -95,7 +111,6 @@ internal class RustRoomSummaryDataSource(
}
private fun MutableList<RoomSummary>.applyDiff(diff: SlidingSyncViewRoomsListDiff) {
fun MutableList<RoomSummary>.fillUntil(untilIndex: Int) {
repeat((size - 1 until untilIndex).count()) {
add(buildEmptyRoomSummary())
@ -163,4 +178,4 @@ internal class RustRoomSummaryDataSource(
else -> false
}
}
}
}

View file

@ -7,7 +7,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncRoom
class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) {
fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails{
fun create(slidingSyncRoom: SlidingSyncRoom, room: Room?): RoomSummaryDetails {
val latestRoomMessage = slidingSyncRoom.latestRoomMessage()?.let {
roomMessageFactory.create(it)
}
@ -17,14 +17,13 @@ class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFacto
else -> "${latestRoomMessage.sender.value}: ${latestRoomMessage.body}"
}
return RoomSummaryDetails(
roomId = RoomId(slidingSyncRoom.roomId()),
name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(),
isDirect = slidingSyncRoom.isDm() ?: false,
avatarURLString = room?.avatarUrl(),
unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(),
lastMessage = computedLastMessage,
lastMessageTimestamp = latestRoomMessage?.originServerTs
roomId = RoomId(slidingSyncRoom.roomId()),
name = slidingSyncRoom.name() ?: slidingSyncRoom.roomId(),
isDirect = slidingSyncRoom.isDm() ?: false,
avatarURLString = room?.avatarUrl(),
unreadNotificationCount = slidingSyncRoom.unreadNotifications().notificationCount().toInt(),
lastMessage = computedLastMessage,
lastMessageTimestamp = latestRoomMessage?.originServerTs
)
}
}
}

View file

@ -14,5 +14,4 @@ class RoomMessageFactory {
originServerTs = eventTimelineItem.originServerTs()?.toLong() ?: 0L
)
}
}
}

View file

@ -10,7 +10,8 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.map
import kotlinx.serialization.Serializable
import kotlinx.serialization.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.matrix.rustcomponents.sdk.Session
@ -73,4 +74,4 @@ internal class SessionStore(
suspend fun reset() {
store.edit { it.clear() }
}
}
}

View file

@ -11,6 +11,7 @@ import org.matrix.rustcomponents.sdk.UpdateSummary
// Sounds like a reasonable buffer size before it suspends emitting new items.
private const val BUFFER_SIZE = 64
class SlidingSyncObserverProxy(
private val coroutineScope: CoroutineScope,
private val coroutineDispatchers: CoroutineDispatchers
@ -26,5 +27,4 @@ class SlidingSyncObserverProxy(
updateSummaryMutableFlow.emit(summary)
}
}
}
}

View file

@ -1,10 +1,15 @@
package io.element.android.x.matrix.sync
import io.element.android.x.matrix.util.mxCallbackFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import mxCallbackFlow
import org.matrix.rustcomponents.sdk.*
import org.matrix.rustcomponents.sdk.SlidingSyncState
import org.matrix.rustcomponents.sdk.SlidingSyncView
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomListObserver
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsCountObserver
import org.matrix.rustcomponents.sdk.SlidingSyncViewRoomsListDiff
import org.matrix.rustcomponents.sdk.SlidingSyncViewStateObserver
fun SlidingSyncView.roomListDiff(scope: CoroutineScope): Flow<SlidingSyncViewRoomsListDiff> =
mxCallbackFlow {

View file

@ -2,15 +2,21 @@ package io.element.android.x.matrix.timeline
import io.element.android.x.core.coroutine.CoroutineDispatchers
import io.element.android.x.matrix.room.MatrixRoom
import java.util.Collections
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.*
import org.matrix.rustcomponents.sdk.PaginationOutcome
import org.matrix.rustcomponents.sdk.Room
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
import org.matrix.rustcomponents.sdk.TimelineChange
import org.matrix.rustcomponents.sdk.TimelineDiff
import org.matrix.rustcomponents.sdk.TimelineListener
import timber.log.Timber
import java.util.*
class MatrixTimeline(
private val matrixRoom: MatrixRoom,
@ -31,7 +37,7 @@ class MatrixTimeline(
private val timelineItems: MutableStateFlow<List<MatrixTimelineItem>> =
MutableStateFlow(emptyList())
@OptIn(FlowPreview::class)
fun timelineItems(): Flow<List<MatrixTimelineItem>> {
return timelineItems.sample(50)
}
@ -41,7 +47,6 @@ class MatrixTimeline(
return paginationOutcome.value.moreMessages
}
private fun MutableList<MatrixTimelineItem>.applyDiff(diff: TimelineDiff) {
when (diff.change()) {
TimelineChange.PUSH -> {
@ -140,5 +145,4 @@ class MatrixTimeline(
}
}
}
}
}

View file

@ -9,7 +9,6 @@ data class TracingConfiguration(
targets.map { "${it.key.filter}=${it.value.filter}" }.joinToString(separator = ",")
}"
sealed class Target(open val filter: String) {
object Hyper : Target("hyper")
object Sled : Target("sled")
@ -31,7 +30,6 @@ data class TracingConfiguration(
object Debug : LogLevel("debug")
object Error : LogLevel("error")
}
}
fun setupTracing(tracingConfiguration: TracingConfiguration) {
@ -47,4 +45,4 @@ object TracingConfigurations {
TracingConfiguration.Target.Sled to TracingConfiguration.LogLevel.Warn
)
)
}
}

View file

@ -1,6 +1,5 @@
@file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.x.matrix.util
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
@ -12,4 +11,4 @@ internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> StoppableS
awaitClose {
token.cancel()
}
}
}

View file

@ -12,4 +12,4 @@ fun logError(throwable: Throwable) {
Timber.e("Error", throwable)
}
}
}
}