Skip to content

Commit

Permalink
saving work, still need to fix test 2
Browse files Browse the repository at this point in the history
  • Loading branch information
cameronvoell committed Feb 7, 2025
1 parent 28aebb5 commit 4137e83
Show file tree
Hide file tree
Showing 10 changed files with 686 additions and 3 deletions.
1 change: 1 addition & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'org.web3j:core:4.9.4'
androidTestImplementation 'org.web3j:contracts:4.9.4'
androidTestImplementation project(':example')
}

afterEvaluate {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package org.xmtp.android.library

import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.protobuf.kotlin.toByteStringUtf8
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Ignore
import android.content.Context
import android.util.Log
import androidx.test.core.app.ApplicationProvider
import org.junit.Test
import org.junit.runner.RunWith
import org.xmtp.android.library.codecs.Attachment
import org.xmtp.android.library.codecs.AttachmentCodec
import org.xmtp.android.library.codecs.ContentTypeAttachment
import org.xmtp.android.library.codecs.ContentTypeReaction
import org.xmtp.android.library.codecs.ContentTypeReactionV2
import org.xmtp.android.library.codecs.ContentTypeRemoteAttachment
import org.xmtp.android.library.codecs.EncodedContent
import org.xmtp.android.library.codecs.Reaction
import org.xmtp.android.library.codecs.ReactionAction
import org.xmtp.android.library.codecs.ReactionCodec
import org.xmtp.android.library.codecs.ReactionSchema
import org.xmtp.android.library.codecs.ReactionV2Codec
import org.xmtp.android.library.codecs.RemoteAttachment
import org.xmtp.android.library.codecs.RemoteAttachmentCodec
import org.xmtp.android.library.codecs.decoded
import org.xmtp.android.library.codecs.id
import org.xmtp.android.library.libxmtp.Message
import org.xmtp.android.library.messages.walletAddress
import uniffi.xmtpv3.FfiMultiRemoteAttachment
import uniffi.xmtpv3.FfiReaction
import uniffi.xmtpv3.FfiReactionAction
import uniffi.xmtpv3.FfiReactionSchema
import uniffi.xmtpv3.decryptMultiEncryptedAttachment
import uniffi.xmtpv3.encryptEncodedContentArray
import uniffi.xmtpv3.org.xmtp.android.library.codecs.ContentTypeMultiRemoteAttachment
import uniffi.xmtpv3.org.xmtp.android.library.codecs.MultiRemoteAttachmentCodec
import uniffi.xmtpv3.org.xmtp.android.library.codecs.MultiRemoteAttachmentCodec.Companion.decryptMultiRemoteAttachment
import java.io.File
import java.net.URL

@RunWith(AndroidJUnit4::class)
class MultiRemoteAttachmentTest {

@Test
fun testEncryptedContentShouldBeDecryptable() {
Client.register(codec = AttachmentCodec())
val attachment1 = Attachment(
filename = "test1.txt",
mimeType = "text/plain",
data = "hello world".toByteStringUtf8(),
)

val attachment2 = Attachment(
filename = "test2.txt",
mimeType = "text/plain",
data = "hello world".toByteStringUtf8(),
)

val codec = AttachmentCodec()
val encodedContent1Bytes = codec.encode(attachment1).toByteArray()
val encodedContent2Bytes = codec.encode(attachment2).toByteArray()

val multiEncryptedAttachment = encryptEncodedContentArray(
listOf(
codec.encode(attachment1).toByteArray(),
codec.encode(attachment2).toByteArray()
)
)


val attachmentBytesList = decryptMultiEncryptedAttachment(multiEncryptedAttachment)
val encodedContent1 = EncodedContent.parseFrom(attachmentBytesList[0])
val encodedContent2 = EncodedContent.parseFrom(attachmentBytesList[1])

Assert.assertEquals(encodedContent1.type, ContentTypeAttachment)
val decoded = encodedContent1.decoded<Attachment>()
Assert.assertEquals("test1.txt", decoded?.filename)
val decoded2 = encodedContent2.decoded<Attachment>()
Assert.assertEquals("test2.txt", decoded2?.filename)
}

val context = ApplicationProvider.getApplicationContext<Context>()

@Test
fun testCanUseMultiRemoteAttachmentCodec() {
val attachment1 = Attachment(
filename = "test123.txt",
mimeType = "text/plain",
data = "hello world".toByteStringUtf8(),
)

val attachment2 = Attachment(
filename = "test456.txt",
mimeType = "text/plain",
data = "hello world".toByteStringUtf8(),
)

Client.register(codec = AttachmentCodec())
Client.register(codec = MultiRemoteAttachmentCodec())

val codec = AttachmentCodec()

val multiEncryptedAttachment = encryptEncodedContentArray(
listOf(
codec.encode(attachment1).toByteArray(),
codec.encode(attachment2).toByteArray()
)
)

// val decryptedEncodedContentBytesList = decryptMultiEncryptedAttachment(multiEncryptedAttachment)
// var encodedContentList: MutableList<EncodedContent> = ArrayList()
// for (decryptedEncodedContentBytes in decryptedEncodedContentBytesList) {
// val encodedContent = EncodedContent.parseFrom(decryptedEncodedContentBytes)
// encodedContentList.add(encodedContent)
// }
// runBlocking {
// val attachment1: Attachment? =
// encodedContentList[0].decoded<Attachment>()
// Assert.assertEquals("test123.txt", attachment1?.filename)
// }


val uploadLocations = listOf("https://uploadlocation1.com", "https://uploadLocation2.com")
val multiRemoteAttachment: FfiMultiRemoteAttachment =
MultiRemoteAttachmentCodec.generateMultiRemoteAttachment(
multiEncryptedAttachment,
uploadLocations,
"https://"
)!!

val fixtures = fixtures()
val aliceClient = fixtures.alixClient
val aliceConversation = runBlocking {
aliceClient.conversations.newConversation(fixtures.bo.walletAddress)
}

runBlocking {
aliceConversation.send(
content = multiRemoteAttachment,
options = SendOptions(contentType = ContentTypeMultiRemoteAttachment),
)
}

val messages = runBlocking { aliceConversation.messages() }
Assert.assertEquals(messages.size, 1)
//
// if (messages.size == 1) {
// val loadedMultiRemoteAttachment: FfiMultiRemoteAttachment = messages[0].content()!!
// val downloadedEncryptedAttachment1 =
// simulateDownload(loadedMultiRemoteAttachment.attachments[0].url)
// val downloadedEncryptedAttachment2 =
// simulateDownload(loadedMultiRemoteAttachment.attachments[1].url)
//
// val encodedContentList: List<EncodedContent> = decryptMultiRemoteAttachment(
// loadedMultiRemoteAttachment.also {
// Log.d("XMTP", "MultiRemoteAttachment nonce[PLZ]: ${it.secret.contentToString()}")
// },
// listOf(downloadedEncryptedAttachment1, downloadedEncryptedAttachment2)
// )
//
//
// runBlocking {
// val attachment1: Attachment? =
// encodedContentList[0].decoded<Attachment>()
// Assert.assertEquals("test123.txt", attachment1?.filename)
// }
// }
}

fun simulateDownload(url: String): ByteArray {
val attachment1 = Attachment(
filename = "test1.txt",
mimeType = "text/plain",
data = "hello world".toByteStringUtf8(),
)

val attachment2 = Attachment(
filename = "test2.txt",
mimeType = "text/plain",
data = "hello world".toByteStringUtf8(),
)

val codec = AttachmentCodec()

val multiEncryptedAttachment = encryptEncodedContentArray(
listOf(
codec.encode(attachment1).toByteArray(),
codec.encode(attachment2).toByteArray()
)
)
when (url) {
"https://uploadlocation1.com" -> {
return multiEncryptedAttachment.encryptedAttachments[0].payload.also {
Log.d("XMTP", "MultiRemoteAttachment payload[https://uploadlocation1.com]: ${it.contentToString()}")
}
}

"https://uploadLocation2.com" -> {
return multiEncryptedAttachment.encryptedAttachments[1].payload.also {
Log.d("XMTP", "MultiRemoteAttachment payload[https://uploadlocation2.com]: ${it.contentToString()}")
}
}
}
return byteArrayOf()
}
}
6 changes: 3 additions & 3 deletions library/src/main/java/libxmtp-version.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Version: b137466b
Branch: main
Date: 2025-02-06 16:54:22 +0000
Version: 37302b99
Branch: cv/multi-attachment-content-type
Date: 2025-02-07 12:37:07 +0000
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ val ContentTypeAttachment = ContentTypeIdBuilder.builderFromAuthorityId(

data class Attachment(val filename: String, val mimeType: String, val data: ByteString)

data class LocalAttachment(val filename: String, val mimeType: String, val absoluteFilePath: String)

data class AttachmentCodec(override var contentType: ContentTypeId = ContentTypeAttachment) : ContentCodec<Attachment> {
override fun encode(content: Attachment): EncodedContent {
return EncodedContent.newBuilder().also {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package uniffi.xmtpv3.org.xmtp.android.library.codecs

import android.util.Log
import org.xmtp.android.library.codecs.ContentCodec
import org.xmtp.android.library.codecs.ContentTypeId
import org.xmtp.android.library.codecs.ContentTypeIdBuilder
import org.xmtp.android.library.codecs.EncodedContent
import org.xmtp.android.library.codecs.LocalAttachment
import uniffi.xmtpv3.FfiEncryptedEncodedContent
import uniffi.xmtpv3.FfiMultiEncryptedAttachment
import uniffi.xmtpv3.FfiMultiRemoteAttachment
import uniffi.xmtpv3.FfiReaction
import uniffi.xmtpv3.FfiReactionAction
import uniffi.xmtpv3.FfiRemoteAttachmentInfo
import uniffi.xmtpv3.decodeMultiRemoteAttachment
import uniffi.xmtpv3.decodeReaction
import uniffi.xmtpv3.decryptMultiEncryptedAttachment
import uniffi.xmtpv3.encodeMultiRemoteAttachment
import uniffi.xmtpv3.encodeReaction

val ContentTypeMultiRemoteAttachment = ContentTypeIdBuilder.builderFromAuthorityId(
"xmtp.org",
"multiRemoteStaticAttachment",
versionMajor = 1,
versionMinor = 0,
)

data class MultiRemoteAttachmentCodec(override var contentType: ContentTypeId = ContentTypeMultiRemoteAttachment) :
ContentCodec<FfiMultiRemoteAttachment> {

override fun encode(content: FfiMultiRemoteAttachment): EncodedContent {
return EncodedContent.parseFrom(encodeMultiRemoteAttachment(content))
}

override fun decode(content: EncodedContent): FfiMultiRemoteAttachment {
return decodeMultiRemoteAttachment(content.toByteArray())
}

override fun fallback(content: FfiMultiRemoteAttachment): String = "MultiRemoteAttachment not supported"

override fun shouldPush(content: FfiMultiRemoteAttachment): Boolean = true

companion object {
fun generateMultiRemoteAttachment(multiEncryptedAttachment: FfiMultiEncryptedAttachment, urls: List<String>, scheme: String): FfiMultiRemoteAttachment? {
if (multiEncryptedAttachment.encryptedAttachments.size != urls.size) {
return null
}

var remoteAttachmentInfos: MutableList<FfiRemoteAttachmentInfo> = ArrayList()
for (index in multiEncryptedAttachment.encryptedAttachments.indices) {
val remoteAttachmentInfo = FfiRemoteAttachmentInfo(
url = urls[index],
contentDigest = multiEncryptedAttachment.encryptedAttachments[index].contentDigest,
nonce = multiEncryptedAttachment.encryptedAttachments[index].nonce,
scheme = scheme,
filename = multiEncryptedAttachment.encryptedAttachments[index].filename ?: "default attachment name",
salt = multiEncryptedAttachment.encryptedAttachments[index].salt
)
remoteAttachmentInfos.add(remoteAttachmentInfo)
}
return FfiMultiRemoteAttachment(
secret = multiEncryptedAttachment.secret,
attachments = remoteAttachmentInfos,
numAttachments = multiEncryptedAttachment.encryptedAttachments.size.toUInt(),
maxAttachmentContentLength = null
)
}

fun decryptMultiRemoteAttachment(ffiMultiRemoteAttachment: FfiMultiRemoteAttachment, encryptedByteArrayList: List<ByteArray>): List<EncodedContent> {
var encodedContentList: MutableList<EncodedContent> = ArrayList()
var encryptedAttachmentList: MutableList<FfiEncryptedEncodedContent> = ArrayList()
for (index in ffiMultiRemoteAttachment.attachments.indices) {
val encryptedAttachment: FfiEncryptedEncodedContent = FfiEncryptedEncodedContent(
payload = encryptedByteArrayList[index].also {
Log.d("XMTP", "MultiRemoteAttachment payload[${index}]: ${it.contentToString()}")
},
contentDigest = ffiMultiRemoteAttachment.attachments[index].contentDigest,
nonce = ffiMultiRemoteAttachment.attachments[index].nonce.also {
Log.d("XMTP", "MultiRemoteAttachment nonce[${index}]: ${it.contentToString()}")
},
filename = ffiMultiRemoteAttachment.attachments[index].filename,
salt = ffiMultiRemoteAttachment.attachments[index].salt.also {
Log.d("XMTP", "MultiRemoteAttachment salt[${index}]: ${it.contentToString()}")
},
contentLength = null
)
encryptedAttachmentList.add(encryptedAttachment)
}
val multiEncryptedAttachment = FfiMultiEncryptedAttachment(
secret = ffiMultiRemoteAttachment.secret.also {
Log.d("XMTP", "MultiRemoteAttachment SECRET[]: ${it.contentToString()}")
},
encryptedAttachments = encryptedAttachmentList,
numAttachments = ffiMultiRemoteAttachment.numAttachments,
maxAttachmentContentLength = ffiMultiRemoteAttachment.maxAttachmentContentLength
)
val decryptedEncodedContentBytesList = decryptMultiEncryptedAttachment(multiEncryptedAttachment)
for (decryptedEncodedContentBytes in decryptedEncodedContentBytesList) {
val encodedContent = EncodedContent.parseFrom(decryptedEncodedContentBytes)
encodedContentList.add(encodedContent)
}
return encodedContentList
}
}
}


Loading

0 comments on commit 4137e83

Please sign in to comment.