From f57bfedc455e382b6475026ff7bcb3ac0612d406 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:08:30 +0000 Subject: [PATCH 1/2] Update dependency org.matrix.rustcomponents:sdk-android to v0.2.60 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 224dc9cec93..1177419d2e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -173,7 +173,7 @@ jsoup = "org.jsoup:jsoup:1.18.1" appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" } molecule-runtime = "app.cash.molecule:molecule-runtime:2.0.0" timber = "com.jakewharton.timber:timber:5.0.1" -matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.59" +matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.60" matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" } matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" } sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" } From dc797441df48ade3295867795538e4efee0b1ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Thu, 7 Nov 2024 14:38:43 +0100 Subject: [PATCH 2/2] Fix SDK API breaks: - Map new `QueueWedgeError` cases. - Add `MediaUploadOnSendQueue` feature flag enabled on debug and nightly builds: this will by used by `Timeline.send*` media functions fot its new `useSendQueue` parameter. --- .../libraries/featureflag/api/FeatureFlags.kt | 8 ++++ .../item/event/LocalEventSendState.kt | 4 ++ .../libraries/matrix/impl/RustMatrixClient.kt | 3 ++ .../matrix/impl/RustMatrixClientFactory.kt | 1 + .../matrix/impl/room/RustMatrixRoom.kt | 3 ++ .../matrix/impl/room/RustRoomFactory.kt | 3 ++ .../matrix/impl/timeline/RustTimeline.kt | 45 ++++++++++++------- .../item/event/EventTimelineItemMapper.kt | 6 +++ .../matrix/impl/RustMatrixClientTest.kt | 2 + 9 files changed, 60 insertions(+), 15 deletions(-) diff --git a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt index de7fe02b5d7..490c12ebe0d 100644 --- a/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt +++ b/libraries/featureflag/api/src/main/kotlin/io/element/android/libraries/featureflag/api/FeatureFlags.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.featureflag.api import io.element.android.appconfig.OnBoardingConfig import io.element.android.libraries.core.meta.BuildMeta +import io.element.android.libraries.core.meta.BuildType /** * To enable or disable a FeatureFlags, change the `defaultValue` value. @@ -132,4 +133,11 @@ enum class FeatureFlags( defaultValue = { false }, isFinished = false, ), + MediaUploadOnSendQueue( + key = "feature.media_upload_through_send_queue", + title = "Media upload through send queue", + description = "Experimental support for treating media uploads as regular events, with an improved retry and cancellation implementation.", + defaultValue = { buildMeta -> buildMeta.buildType != BuildType.RELEASE }, + isFinished = false, + ), } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt index e6a0eae7edb..c95fe467419 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/LocalEventSendState.kt @@ -34,6 +34,10 @@ sealed interface LocalEventSendState { */ val users: List ) : VerifiedUser + + data class InvalidMimeType(val mimeType: String) : Failed + + data object MissingMediaContent : Failed } data class Sent( 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 a10448959c1..3165cef1bfb 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 @@ -12,6 +12,7 @@ import io.element.android.libraries.androidutils.file.safeDelete import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope +import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.core.ProgressCallback @@ -125,6 +126,7 @@ class RustMatrixClient( baseCacheDirectory: File, clock: SystemClock, timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory, + featureFlagService: FeatureFlagService, ) : MatrixClient { override val sessionId: UserId = UserId(client.userId()) override val deviceId: DeviceId = DeviceId(client.deviceId()) @@ -188,6 +190,7 @@ class RustMatrixClient( roomContentForwarder = RoomContentForwarder(innerRoomListService), roomSyncSubscriber = roomSyncSubscriber, timelineEventTypeFilterFactory = timelineEventTypeFilterFactory, + featureFlagService = featureFlagService, ) override val mediaLoader: MatrixMediaLoader = RustMediaLoader( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index c33ccdb5434..c22cb84c4da 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -82,6 +82,7 @@ class RustMatrixClientFactory @Inject constructor( baseCacheDirectory = cacheDirectory, clock = clock, timelineEventTypeFilterFactory = timelineEventTypeFilterFactory, + featureFlagService = featureFlagService, ).also { Timber.tag(it.toString()).d("Creating Client with access token '$anonymizedAccessToken' and refresh token '$anonymizedRefreshToken'") } 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 a80d0921455..8b72282cd53 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 @@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.impl.room import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.core.extensions.mapFailure +import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ProgressCallback @@ -103,6 +104,7 @@ class RustMatrixRoom( private val roomContentForwarder: RoomContentForwarder, private val roomSyncSubscriber: RoomSyncSubscriber, private val matrixRoomInfoMapper: MatrixRoomInfoMapper, + private val featureFlagService: FeatureFlagService, ) : MatrixRoom { override val roomId = RoomId(innerRoom.id()) @@ -700,6 +702,7 @@ class RustMatrixRoom( dispatcher = roomDispatcher, roomContentForwarder = roomContentForwarder, onNewSyncedEvent = onNewSyncedEvent, + featureFlagsService = featureFlagService, ) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt index e06424e723e..1b9fe4115e6 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustRoomFactory.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.matrix.impl.room import androidx.collection.lruCache import io.element.android.appconfig.TimelineConfig import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId @@ -49,6 +50,7 @@ class RustRoomFactory( private val innerRoomListService: InnerRoomListService, private val roomSyncSubscriber: RoomSyncSubscriber, private val timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory, + private val featureFlagService: FeatureFlagService, ) { @OptIn(ExperimentalCoroutinesApi::class) private val dispatcher = dispatchers.io.limitedParallelism(1) @@ -117,6 +119,7 @@ class RustRoomFactory( roomContentForwarder = roomContentForwarder, roomSyncSubscriber = roomSyncSubscriber, matrixRoomInfoMapper = matrixRoomInfoMapper, + featureFlagService = featureFlagService, ) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt index 019f59bfaf6..98f7ccfba10 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/RustTimeline.kt @@ -7,6 +7,8 @@ package io.element.android.libraries.matrix.impl.timeline +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.ProgressCallback import io.element.android.libraries.matrix.api.core.RoomId @@ -85,6 +87,7 @@ class RustTimeline( private val coroutineScope: CoroutineScope, private val dispatcher: CoroutineDispatcher, private val roomContentForwarder: RoomContentForwarder, + private val featureFlagsService: FeatureFlagService, onNewSyncedEvent: () -> Unit, ) : Timeline { private val initLatch = CompletableDeferred() @@ -330,6 +333,7 @@ class RustTimeline( formattedCaption: String?, progressCallback: ProgressCallback?, ): Result { + val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) return sendAttachment(listOfNotNull(file, thumbnailFile)) { inner.sendImage( url = file.path, @@ -339,7 +343,7 @@ class RustTimeline( formattedCaption = formattedCaption?.let { FormattedBody(body = it, format = MessageFormat.Html) }, - storeInCache = true, + useSendQueue = useSendQueue, progressWatcher = progressCallback?.toProgressWatcher() ) } @@ -353,6 +357,7 @@ class RustTimeline( formattedCaption: String?, progressCallback: ProgressCallback?, ): Result { + val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) return sendAttachment(listOfNotNull(file, thumbnailFile)) { inner.sendVideo( url = file.path, @@ -362,13 +367,14 @@ class RustTimeline( formattedCaption = formattedCaption?.let { FormattedBody(body = it, format = MessageFormat.Html) }, - storeInCache = true, + useSendQueue = useSendQueue, progressWatcher = progressCallback?.toProgressWatcher() ) } } override suspend fun sendAudio(file: File, audioInfo: AudioInfo, progressCallback: ProgressCallback?): Result { + val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) return sendAttachment(listOf(file)) { inner.sendAudio( url = file.path, @@ -376,15 +382,21 @@ class RustTimeline( // Maybe allow a caption in the future? caption = null, formattedCaption = null, - storeInCache = true, + useSendQueue = useSendQueue, progressWatcher = progressCallback?.toProgressWatcher() ) } } override suspend fun sendFile(file: File, fileInfo: FileInfo, progressCallback: ProgressCallback?): Result { + val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) return sendAttachment(listOf(file)) { - inner.sendFile(file.path, fileInfo.map(), false, progressCallback?.toProgressWatcher()) + inner.sendFile( + url = file.path, + fileInfo = fileInfo.map(), + useSendQueue = useSendQueue, + progressWatcher = progressCallback?.toProgressWatcher(), + ) } } @@ -491,17 +503,20 @@ class RustTimeline( audioInfo: AudioInfo, waveform: List, progressCallback: ProgressCallback?, - ): Result = sendAttachment(listOf(file)) { - inner.sendVoiceMessage( - url = file.path, - audioInfo = audioInfo.map(), - waveform = waveform.toMSC3246range(), - // Maybe allow a caption in the future? - caption = null, - formattedCaption = null, - storeInCache = true, - progressWatcher = progressCallback?.toProgressWatcher(), - ) + ): Result { + val useSendQueue = featureFlagsService.isFeatureEnabled(FeatureFlags.MediaUploadOnSendQueue) + return sendAttachment(listOf(file)) { + inner.sendVoiceMessage( + url = file.path, + audioInfo = audioInfo.map(), + waveform = waveform.toMSC3246range(), + // Maybe allow a caption in the future? + caption = null, + formattedCaption = null, + useSendQueue = useSendQueue, + progressWatcher = progressCallback?.toProgressWatcher(), + ) + } } private fun sendAttachment(files: List, handle: () -> SendAttachmentJoinHandle): Result { diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index cec54d3d20d..f93d3fe982c 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -100,6 +100,12 @@ fun RustEventSendState?.map(): LocalEventSendState? { LocalEventSendState.Failed.Unknown(queueWedgeError.msg) } } + is QueueWedgeError.InvalidMimeType -> { + LocalEventSendState.Failed.InvalidMimeType(queueWedgeError.mimeType) + } + is QueueWedgeError.MissingMediaContent -> { + LocalEventSendState.Failed.MissingMediaContent + } } } is RustEventSendState.Sent -> LocalEventSendState.Sent(EventId(eventId)) diff --git a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt index 36c96d2dfed..22fcad92bf1 100644 --- a/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt +++ b/libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientTest.kt @@ -8,6 +8,7 @@ package io.element.android.libraries.matrix.impl import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustClient import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustSyncService import io.element.android.libraries.matrix.impl.room.FakeTimelineEventTypeFilterFactory @@ -46,5 +47,6 @@ class RustMatrixClientTest { baseCacheDirectory = File(""), clock = FakeSystemClock(), timelineEventTypeFilterFactory = FakeTimelineEventTypeFilterFactory(), + featureFlagService = FakeFeatureFlagService(), ) }