diff --git a/android/build.gradle b/android/build.gradle index 59e5353db..e0a2f264c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -95,7 +95,7 @@ repositories { dependencies { implementation project(':expo-modules-core') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" - implementation "org.xmtp:android:0.6.12" + implementation "org.xmtp:android:0.6.14" implementation 'com.google.code.gson:gson:2.10.1' implementation 'com.facebook.react:react-native:0.71.3' implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1" diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 6848a8e26..038dcbef9 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -268,6 +268,27 @@ class XMTPModule : Module() { ).toJson() } + AsyncFunction("sendEncodedContent") { clientAddress: String, topic: String, encodedContentData: List -> + val conversation = + findConversation( + clientAddress = clientAddress, + topic = topic + ) ?: throw XMTPException("no conversation found for $topic") + + val encodedContentDataBytes = + encodedContentData.foldIndexed(ByteArray(encodedContentData.size)) { i, a, v -> + a.apply { + set( + i, + v.toByte() + ) + } + } + val encodedContent = EncodedContent.parseFrom(encodedContentDataBytes) + + conversation.send(encodedContent = encodedContent) + } + AsyncFunction("listConversations") { clientAddress: String -> logV("listConversations") val client = clients[clientAddress] ?: throw XMTPException("No client") @@ -288,7 +309,7 @@ class XMTPModule : Module() { val beforeDate = if (before != null) Date(before) else null val afterDate = if (after != null) Date(after) else null - conversation.messages( + conversation.decryptedMessages( limit = limit, before = beforeDate, after = afterDate, @@ -340,7 +361,7 @@ class XMTPModule : Module() { topicsList.add(Pair(topic, page)) } - client.conversations.listBatchMessages(topicsList) + client.conversations.listBatchDecryptedMessages(topicsList) .map { DecodedMessageWrapper.encode(it) } } @@ -486,7 +507,7 @@ class XMTPModule : Module() { topic = topic ) ?: throw XMTPException("no conversation found for $topic") - val decodedMessage = conversation.decode(envelope) + val decodedMessage = conversation.decrypt(envelope) DecodedMessageWrapper.encode(decodedMessage) } @@ -581,7 +602,7 @@ class XMTPModule : Module() { subscriptions[getMessagesKey(clientAddress)]?.cancel() subscriptions[getMessagesKey(clientAddress)] = CoroutineScope(Dispatchers.IO).launch { try { - client.conversations.streamAllMessages().collect { message -> + client.conversations.streamAllDecryptedMessages().collect { message -> sendEvent( "message", mapOf( @@ -607,7 +628,7 @@ class XMTPModule : Module() { subscriptions[conversation.cacheKey(clientAddress)] = CoroutineScope(Dispatchers.IO).launch { try { - conversation.streamMessages().collect { message -> + conversation.streamDecryptedMessages().collect { message -> sendEvent( "message", mapOf( diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt index 775891a85..989f19017 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/ContentJson.kt @@ -1,6 +1,7 @@ package expo.modules.xmtpreactnativesdk.wrappers import android.util.Base64 +import com.google.gson.GsonBuilder import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.protobuf.ByteString @@ -14,6 +15,7 @@ import org.xmtp.android.library.codecs.ContentTypeReadReceipt import org.xmtp.android.library.codecs.ContentTypeRemoteAttachment import org.xmtp.android.library.codecs.ContentTypeReply import org.xmtp.android.library.codecs.ContentTypeText +import org.xmtp.android.library.codecs.EncodedContent import org.xmtp.android.library.codecs.Reaction import org.xmtp.android.library.codecs.ReactionCodec import org.xmtp.android.library.codecs.ReadReceipt @@ -28,16 +30,17 @@ import org.xmtp.android.library.codecs.description import org.xmtp.android.library.codecs.getReactionAction import org.xmtp.android.library.codecs.getReactionSchema import org.xmtp.android.library.codecs.id -import org.xmtp.proto.message.contents.Content.EncodedContent import java.net.URL class ContentJson( val type: ContentTypeId, val content: Any?, + private val encodedContent: EncodedContent? = null, ) { constructor(encoded: EncodedContent) : this( type = encoded.type, content = encoded.decoded(), + encodedContent = encoded ); companion object { @@ -157,7 +160,11 @@ class ContentJson( ContentTypeReply.id -> mapOf( "reply" to mapOf( "reference" to (content as Reply).reference, - "content" to ContentJson(content.contentType, content.content).toJsonMap(), + "content" to ContentJson( + content.contentType, + content.content, + encodedContent + ).toJsonMap(), ) ) @@ -165,11 +172,31 @@ class ContentJson( "readReceipt" to "" ) - else -> mapOf( - "unknown" to mapOf( - "contentTypeId" to type.description - ) - ) + else -> { + val json = JsonObject() + encodedContent?.let { + val typeJson = JsonObject() + typeJson.addProperty("authorityId", encodedContent.type.authorityId) + typeJson.addProperty("typeId", encodedContent.type.typeId) + typeJson.addProperty("versionMajor", encodedContent.type.versionMajor) + typeJson.addProperty("versionMinor", encodedContent.type.versionMinor) + val parameters = GsonBuilder().create().toJson(encodedContent.parametersMap) + + json.addProperty("fallback", encodedContent.fallback) + json.add("parameters", JsonParser.parseString(parameters)) + json.add("type", typeJson) + } + val encodedContentJSON = json.toString() + if (encodedContentJSON.isNotBlank()) { + mapOf("encoded" to encodedContentJSON) + } else { + mapOf( + "unknown" to mapOf( + "contentTypeId" to type.description + ) + ) + } + } } } -} +} \ No newline at end of file diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt index a0f7a3126..775ef66a5 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/wrappers/DecodedMessageWrapper.kt @@ -1,27 +1,26 @@ package expo.modules.xmtpreactnativesdk.wrappers import com.google.gson.GsonBuilder -import org.xmtp.android.library.DecodedMessage import org.xmtp.android.library.codecs.description -import org.xmtp.android.library.codecs.id +import org.xmtp.android.library.messages.DecryptedMessage class DecodedMessageWrapper { companion object { - fun encode(model: DecodedMessage): String { + fun encode(model: DecryptedMessage): String { val gson = GsonBuilder().create() val message = encodeMap(model) return gson.toJson(message) } - fun encodeMap(model: DecodedMessage): Map = mapOf( + fun encodeMap(model: DecryptedMessage): Map = mapOf( "id" to model.id, "topic" to model.topic, "contentTypeId" to model.encodedContent.type.description, "content" to ContentJson(model.encodedContent).toJsonMap(), "senderAddress" to model.senderAddress, - "sent" to model.sent.time, - "fallback" to model.fallbackContent + "sent" to model.sentAt.time, + "fallback" to model.encodedContent.fallback ) } }