From 4f4d8b1a31d7e7ec13cf26342ee7146a440d752d Mon Sep 17 00:00:00 2001 From: yamilmedina Date: Tue, 26 Nov 2024 15:59:43 +0100 Subject: [PATCH 1/5] feat: add metadata for assetd --- .../kotlin/com/wire/backup/data/BackupData.kt | 22 +++++++++ .../com/wire/backup/ingest/MPBackupMapper.kt | 48 +++++++++++++++++++ .../com/wire/backup/BackupEndToEndTest.kt | 9 +++- protobuf-codegen/src/main/proto/backup.proto | 22 +++++++++ 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt b/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt index 2fe20c4414a..f7f17faca7d 100644 --- a/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt +++ b/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt @@ -112,11 +112,31 @@ sealed class BackupMessageContent { val assetToken: String?, val assetDomain: String?, val encryption: EncryptionAlgorithm?, + val metaData: AssetMetadata?, ) : BackupMessageContent() { enum class EncryptionAlgorithm { AES_GCM, AES_CBC } + sealed class AssetMetadata { + data class Image( + val width: Int, + val height: Int, + val tag: String? + ) : AssetMetadata() + + data class Video( + val width: Int?, + val height: Int?, + val duration: Long?, + ) : AssetMetadata() + + data class Audio( + val normalization: ByteArray?, + val duration: Long?, + ) : AssetMetadata() + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -129,6 +149,7 @@ sealed class BackupMessageContent { if (assetToken != other.assetToken) return false if (assetDomain != other.assetDomain) return false if (encryption != other.encryption) return false + if (metaData != other.metaData) return false return true } @@ -140,6 +161,7 @@ sealed class BackupMessageContent { result = 31 * result + (assetToken?.hashCode() ?: 0) result = 31 * result + (assetDomain?.hashCode() ?: 0) result = 31 * result + (encryption?.hashCode() ?: 0) + result = 31 * result + (metaData?.hashCode() ?: 0) return result } } diff --git a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt index 97bce967771..01e2eebefe3 100644 --- a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt +++ b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt @@ -30,12 +30,15 @@ import com.wire.backup.data.toModel import com.wire.backup.data.toProtoModel import com.wire.kalium.protobuf.backup.ExportUser import com.wire.kalium.protobuf.backup.ExportedAsset +import com.wire.kalium.protobuf.backup.ExportedAudioMetaData import com.wire.kalium.protobuf.backup.ExportedConversation import com.wire.kalium.protobuf.backup.ExportedEncryptionAlgorithm +import com.wire.kalium.protobuf.backup.ExportedImageMetaData import com.wire.kalium.protobuf.backup.ExportedLocation import com.wire.kalium.protobuf.backup.ExportedMessage import com.wire.kalium.protobuf.backup.ExportedMessage.Content import com.wire.kalium.protobuf.backup.ExportedText +import com.wire.kalium.protobuf.backup.ExportedVideoMetaData import pbandk.ByteArr import com.wire.kalium.protobuf.backup.BackupData as ProtoBackupData @@ -47,6 +50,7 @@ internal class MPBackupMapper { handle = it.handle ) + @Suppress("LongMethod") fun mapMessageToProtobuf(it: BackupMessage) = ExportedMessage( id = it.id, timeIso = it.creationDate.toLongMilliseconds(), @@ -69,6 +73,35 @@ internal class MPBackupMapper { EncryptionAlgorithm.AES_GCM -> ExportedEncryptionAlgorithm.BACKUP_AES_GCM EncryptionAlgorithm.AES_CBC -> ExportedEncryptionAlgorithm.BACKUP_AES_CBC null -> null + }, + content.metaData?.let { + when (it) { + is BackupMessageContent.Asset.AssetMetadata.Audio -> + ExportedAsset.MetaData.Audio( + ExportedAudioMetaData( + it.duration, + it.normalization?.let { ByteArr(it) } + ) + ) + + is BackupMessageContent.Asset.AssetMetadata.Image -> + ExportedAsset.MetaData.Image( + ExportedImageMetaData( + it.width, + it.height, + it.tag + ) + ) + + is BackupMessageContent.Asset.AssetMetadata.Video -> + ExportedAsset.MetaData.Video( + ExportedVideoMetaData( + it.width, + it.height, + it.duration + ) + ) + } } ) ) @@ -133,6 +166,21 @@ internal class MPBackupMapper { ExportedEncryptionAlgorithm.BACKUP_AES_GCM -> EncryptionAlgorithm.AES_GCM is ExportedEncryptionAlgorithm.UNRECOGNIZED -> null } + }, + protoContent.value.metaData?.let { + when (it) { + is ExportedAsset.MetaData.Audio -> BackupMessageContent.Asset.AssetMetadata.Audio( + it.value.normalizedLoudness?.array, it.value.durationInMillis + ) + + is ExportedAsset.MetaData.Image -> BackupMessageContent.Asset.AssetMetadata.Image( + it.value.width, it.value.height, it.value.tag + ) + + is ExportedAsset.MetaData.Video -> BackupMessageContent.Asset.AssetMetadata.Video( + it.value.width, it.value.height, it.value.durationInMillis + ) + } } ) diff --git a/backup/src/commonTest/kotlin/com/wire/backup/BackupEndToEndTest.kt b/backup/src/commonTest/kotlin/com/wire/backup/BackupEndToEndTest.kt index 1c1617972ee..77b3bc6942c 100644 --- a/backup/src/commonTest/kotlin/com/wire/backup/BackupEndToEndTest.kt +++ b/backup/src/commonTest/kotlin/com/wire/backup/BackupEndToEndTest.kt @@ -41,14 +41,19 @@ class BackupEndToEndTest { fun givenBackedUpAssetMessage_whenRestoring_thenShouldReadTheSameContent() = runTest { val content = BackupMessageContent.Asset( mimeType = "image/jpeg", - size = 42, + size = 64, name = "pudim.jpg", otrKey = byteArrayOf(31), sha256 = byteArrayOf(33), assetId = "assetId", assetToken = "token", assetDomain = "domain", - encryption = BackupMessageContent.Asset.EncryptionAlgorithm.AES_GCM + encryption = BackupMessageContent.Asset.EncryptionAlgorithm.AES_GCM, + metaData = BackupMessageContent.Asset.AssetMetadata.Video( + duration = 42, + width = 800, + height = 600, + ) ) shouldBackupAndRestoreSameContent(content) } diff --git a/protobuf-codegen/src/main/proto/backup.proto b/protobuf-codegen/src/main/proto/backup.proto index 571fc492103..38ade2c3e92 100644 --- a/protobuf-codegen/src/main/proto/backup.proto +++ b/protobuf-codegen/src/main/proto/backup.proto @@ -85,6 +85,28 @@ message ExportedAsset { optional string asset_token = 7; optional string asset_domain = 8; optional ExportedEncryptionAlgorithm encryption = 9; + oneof meta_data { + ExportedImageMetaData image = 10; + ExportedVideoMetaData video = 11; + ExportedAudioMetaData audio = 12; + } +} + + message ExportedImageMetaData { + required int32 width = 1; + required int32 height = 2; + optional string tag = 3; +} + +message ExportedVideoMetaData { + optional int32 width = 1; + optional int32 height = 2; + optional uint64 duration_in_millis = 3; +} + +message ExportedAudioMetaData { + optional uint64 duration_in_millis = 1; + optional bytes normalized_loudness = 3; // each byte represent one loudness value as a byte (char) value. } message ExportedLocation { From c109b6d9cb44bd9eff16cae9b8be090e4d087195 Mon Sep 17 00:00:00 2001 From: yamilmedina Date: Tue, 26 Nov 2024 16:01:09 +0100 Subject: [PATCH 2/5] feat: add metadata for assetd --- protobuf-codegen/src/main/proto/backup.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protobuf-codegen/src/main/proto/backup.proto b/protobuf-codegen/src/main/proto/backup.proto index 38ade2c3e92..a899dafaac9 100644 --- a/protobuf-codegen/src/main/proto/backup.proto +++ b/protobuf-codegen/src/main/proto/backup.proto @@ -106,7 +106,7 @@ message ExportedVideoMetaData { message ExportedAudioMetaData { optional uint64 duration_in_millis = 1; - optional bytes normalized_loudness = 3; // each byte represent one loudness value as a byte (char) value. + optional bytes normalized_loudness = 2; // each byte represent one loudness value as a byte (char) value. } message ExportedLocation { From b34228f7367c4ffff6d1f6608760faf70bfc76c9 Mon Sep 17 00:00:00 2001 From: yamilmedina Date: Tue, 26 Nov 2024 17:45:28 +0100 Subject: [PATCH 3/5] fix: detekt --- .../kotlin/com/wire/backup/ingest/MPBackupMapper.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt index 01e2eebefe3..75c1e4fd107 100644 --- a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt +++ b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt @@ -170,15 +170,20 @@ internal class MPBackupMapper { protoContent.value.metaData?.let { when (it) { is ExportedAsset.MetaData.Audio -> BackupMessageContent.Asset.AssetMetadata.Audio( - it.value.normalizedLoudness?.array, it.value.durationInMillis + it.value.normalizedLoudness?.array, + it.value.durationInMillis ) is ExportedAsset.MetaData.Image -> BackupMessageContent.Asset.AssetMetadata.Image( - it.value.width, it.value.height, it.value.tag + it.value.width, + it.value.height, + it.value.tag ) is ExportedAsset.MetaData.Video -> BackupMessageContent.Asset.AssetMetadata.Video( - it.value.width, it.value.height, it.value.durationInMillis + it.value.width, + it.value.height, + it.value.durationInMillis ) } } From 5b12ffd2b62d438e598291c3499d7f01d8783608 Mon Sep 17 00:00:00 2001 From: yamilmedina Date: Wed, 27 Nov 2024 14:40:15 +0100 Subject: [PATCH 4/5] feat: metadata logs --- backup/build.gradle.kts | 1 + .../com/wire/backup/ingest/MPBackupMapper.kt | 127 +++++++++--------- 2 files changed, 67 insertions(+), 61 deletions(-) diff --git a/backup/build.gradle.kts b/backup/build.gradle.kts index b3a04f69097..69fe6886ac0 100644 --- a/backup/build.gradle.kts +++ b/backup/build.gradle.kts @@ -59,6 +59,7 @@ kotlin { // Libsodium implementation(libs.libsodiumBindingsMP) + api(libs.kermit) } } val commonTest by getting { diff --git a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt index 75c1e4fd107..a772fd3747e 100644 --- a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt +++ b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt @@ -17,6 +17,7 @@ */ package com.wire.backup.ingest +import co.touchlab.kermit.Logger import com.wire.backup.data.BackupConversation import com.wire.backup.data.BackupData import com.wire.backup.data.BackupDateTime @@ -51,75 +52,79 @@ internal class MPBackupMapper { ) @Suppress("LongMethod") - fun mapMessageToProtobuf(it: BackupMessage) = ExportedMessage( - id = it.id, - timeIso = it.creationDate.toLongMilliseconds(), - senderUserId = it.senderUserId.toProtoModel(), - senderClientId = it.senderClientId, - conversationId = it.conversationId.toProtoModel(), - content = when (val content = it.content) { - is BackupMessageContent.Asset -> - Content.Asset( - ExportedAsset( - content.mimeType, - content.size.toLong(), - content.name, - ByteArr(content.otrKey), - ByteArr(content.sha256), - content.assetId, - content.assetToken, - content.assetDomain, - when (content.encryption) { - EncryptionAlgorithm.AES_GCM -> ExportedEncryptionAlgorithm.BACKUP_AES_GCM - EncryptionAlgorithm.AES_CBC -> ExportedEncryptionAlgorithm.BACKUP_AES_CBC - null -> null - }, - content.metaData?.let { - when (it) { - is BackupMessageContent.Asset.AssetMetadata.Audio -> - ExportedAsset.MetaData.Audio( - ExportedAudioMetaData( - it.duration, - it.normalization?.let { ByteArr(it) } + fun mapMessageToProtobuf(it: BackupMessage): ExportedMessage { + return ExportedMessage( + id = it.id, + timeIso = it.creationDate.toLongMilliseconds(), + senderUserId = it.senderUserId.toProtoModel(), + senderClientId = it.senderClientId, + conversationId = it.conversationId.toProtoModel(), + content = when (val content = it.content) { + is BackupMessageContent.Asset -> { + Logger.d("MPBackupMapper") { "Mapping asset message to protobuf: ${content.metaData}" } + Content.Asset( + ExportedAsset( + content.mimeType, + content.size.toLong(), + content.name, + ByteArr(content.otrKey), + ByteArr(content.sha256), + content.assetId, + content.assetToken, + content.assetDomain, + when (content.encryption) { + EncryptionAlgorithm.AES_GCM -> ExportedEncryptionAlgorithm.BACKUP_AES_GCM + EncryptionAlgorithm.AES_CBC -> ExportedEncryptionAlgorithm.BACKUP_AES_CBC + null -> null + }, + content.metaData?.let { + when (it) { + is BackupMessageContent.Asset.AssetMetadata.Audio -> + ExportedAsset.MetaData.Audio( + ExportedAudioMetaData( + it.duration, + it.normalization?.let { ByteArr(it) } + ) ) - ) - - is BackupMessageContent.Asset.AssetMetadata.Image -> - ExportedAsset.MetaData.Image( - ExportedImageMetaData( - it.width, - it.height, - it.tag + + is BackupMessageContent.Asset.AssetMetadata.Image -> + ExportedAsset.MetaData.Image( + ExportedImageMetaData( + it.width, + it.height, + it.tag + ) ) - ) - - is BackupMessageContent.Asset.AssetMetadata.Video -> - ExportedAsset.MetaData.Video( - ExportedVideoMetaData( - it.width, - it.height, - it.duration + + is BackupMessageContent.Asset.AssetMetadata.Video -> + ExportedAsset.MetaData.Video( + ExportedVideoMetaData( + it.width, + it.height, + it.duration + ) ) - ) + } } - } + ) ) - ) + } - is BackupMessageContent.Text -> - Content.Text(ExportedText(content.text)) + is BackupMessageContent.Text -> + Content.Text(ExportedText(content.text)) - is BackupMessageContent.Location -> Content.Location( - ExportedLocation( - content.longitude, - content.latitude, - content.name, - content.zoom + is BackupMessageContent.Location -> Content.Location( + ExportedLocation( + content.longitude, + content.latitude, + content.name, + content.zoom + ) ) - ) - }, - webPk = it.webPrimaryKey?.toLong() - ) + }, + webPk = it.webPrimaryKey?.toLong() + ) + } fun mapConversationToProtobuf(it: BackupConversation) = ExportedConversation(it.id.toProtoModel(), it.name) From 82fb240e3b06c6501790ad78d28074a5af29cb18 Mon Sep 17 00:00:00 2001 From: yamilmedina Date: Wed, 27 Nov 2024 15:48:17 +0100 Subject: [PATCH 5/5] feat: generic metadata for images --- .../commonMain/kotlin/com/wire/backup/data/BackupData.kt | 4 ++++ .../kotlin/com/wire/backup/ingest/MPBackupMapper.kt | 9 +++++++++ protobuf-codegen/src/main/proto/backup.proto | 5 +++++ 3 files changed, 18 insertions(+) diff --git a/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt b/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt index f7f17faca7d..f0d59107750 100644 --- a/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt +++ b/backup/src/commonMain/kotlin/com/wire/backup/data/BackupData.kt @@ -135,6 +135,10 @@ sealed class BackupMessageContent { val normalization: ByteArray?, val duration: Long?, ) : AssetMetadata() + + data class Generic( + val name: String?, + ) : AssetMetadata() } override fun equals(other: Any?): Boolean { diff --git a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt index a772fd3747e..94881eafc0a 100644 --- a/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt +++ b/backup/src/commonMain/kotlin/com/wire/backup/ingest/MPBackupMapper.kt @@ -34,6 +34,7 @@ import com.wire.kalium.protobuf.backup.ExportedAsset import com.wire.kalium.protobuf.backup.ExportedAudioMetaData import com.wire.kalium.protobuf.backup.ExportedConversation import com.wire.kalium.protobuf.backup.ExportedEncryptionAlgorithm +import com.wire.kalium.protobuf.backup.ExportedGenericMetaData import com.wire.kalium.protobuf.backup.ExportedImageMetaData import com.wire.kalium.protobuf.backup.ExportedLocation import com.wire.kalium.protobuf.backup.ExportedMessage @@ -104,6 +105,9 @@ internal class MPBackupMapper { it.duration ) ) + + is BackupMessageContent.Asset.AssetMetadata.Generic -> + ExportedAsset.MetaData.Generic(ExportedGenericMetaData(it.name)) } } ) @@ -150,6 +154,7 @@ internal class MPBackupMapper { ) } + @Suppress("LongMethod") private fun fromMessageProtoToBackupModel(message: ExportedMessage): BackupMessage { val content = when (val protoContent = message.content) { is Content.Text -> { @@ -190,6 +195,10 @@ internal class MPBackupMapper { it.value.height, it.value.durationInMillis ) + + is ExportedAsset.MetaData.Generic -> BackupMessageContent.Asset.AssetMetadata.Generic( + it.value.name + ) } } ) diff --git a/protobuf-codegen/src/main/proto/backup.proto b/protobuf-codegen/src/main/proto/backup.proto index a899dafaac9..334aa1627b0 100644 --- a/protobuf-codegen/src/main/proto/backup.proto +++ b/protobuf-codegen/src/main/proto/backup.proto @@ -89,6 +89,7 @@ message ExportedAsset { ExportedImageMetaData image = 10; ExportedVideoMetaData video = 11; ExportedAudioMetaData audio = 12; + ExportedGenericMetaData generic = 13; } } @@ -109,6 +110,10 @@ message ExportedAudioMetaData { optional bytes normalized_loudness = 2; // each byte represent one loudness value as a byte (char) value. } +message ExportedGenericMetaData { + optional string name = 1; +} + message ExportedLocation { required float longitude = 1; required float latitude = 2;