Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: misc missing properties and type fixes #86

Merged
merged 1 commit into from
Aug 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package expo.modules.xmtpreactnativesdk
import android.util.Base64
import android.util.Base64.NO_WRAP
import android.util.Log
import com.google.gson.JsonParser
import com.google.protobuf.kotlin.toByteString
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import expo.modules.xmtpreactnativesdk.wrappers.ConversationWithClientAddress
import expo.modules.xmtpreactnativesdk.wrappers.ConversationWrapper
import expo.modules.xmtpreactnativesdk.wrappers.ContentJson
import expo.modules.xmtpreactnativesdk.wrappers.ConversationWrapper
import expo.modules.xmtpreactnativesdk.wrappers.DecodedMessageWrapper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -30,9 +30,7 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.Signature
import org.xmtp.android.library.push.XMTPPush
import org.xmtp.proto.keystore.api.v1.Keystore.TopicMap.TopicData
import org.xmtp.proto.message.contents.Content.EncodedContent
import org.xmtp.proto.message.contents.PrivateKeyOuterClass
import org.xmtp.proto.message.contents.SignatureOuterClass
import java.util.Date
import java.util.UUID
import kotlin.coroutines.Continuation
Expand All @@ -50,7 +48,7 @@ class ReactNativeSigner(var module: XMTPModule, override var address: String) :
continuations.remove(id)
return
}
val sig = SignatureOuterClass.Signature.newBuilder().also {
val sig = Signature.newBuilder().also {
it.ecdsaCompact = it.ecdsaCompact.toBuilder().also { builder ->
builder.bytes = signatureData.take(64).toByteArray().toByteString()
builder.recovery = signatureData[64].toInt()
Expand Down Expand Up @@ -107,7 +105,7 @@ class XMTPModule : Module() {
private var clients: MutableMap<String, Client> = mutableMapOf()
private var xmtpPush: XMTPPush? = null
private var signer: ReactNativeSigner? = null
private val isDebugEnabled = BuildConfig.DEBUG; // TODO: consider making this configurable
private val isDebugEnabled = BuildConfig.DEBUG // TODO: consider making this configurable
private val conversations: MutableMap<String, Conversation> = mutableMapOf()
private val subscriptions: MutableMap<String, Job> = mutableMapOf()

Expand Down Expand Up @@ -177,7 +175,6 @@ class XMTPModule : Module() {
// Export the conversation's serialized topic data.
AsyncFunction("exportConversationTopicData") { clientAddress: String, topic: String ->
logV("exportConversationTopicData")
val client = clients[clientAddress] ?: throw XMTPException("No client")
val conversation = findConversation(clientAddress, topic)
?: throw XMTPException("no conversation found for $topic")
Base64.encodeToString(conversation.toTopicData().toByteArray(), NO_WRAP)
Expand All @@ -190,7 +187,7 @@ class XMTPModule : Module() {
val data = TopicData.parseFrom(Base64.decode(topicData, NO_WRAP))
val conversation = client.conversations.importTopicData(data)
conversations[conversation.cacheKey(clientAddress)] = conversation
ConversationWrapper.encode(ConversationWithClientAddress(client, conversation))
ConversationWrapper.encode(client, conversation)
}

//
Expand All @@ -208,7 +205,7 @@ class XMTPModule : Module() {
val conversationList = client.conversations.list()
conversationList.map { conversation ->
conversations[conversation.cacheKey(clientAddress)] = conversation
ConversationWrapper.encode(ConversationWithClientAddress(client, conversation))
ConversationWrapper.encode(client, conversation)
}
}

Expand All @@ -223,7 +220,7 @@ class XMTPModule : Module() {
val afterDate = if (after != null) Date(after) else null

conversation.messages(limit = limit, before = beforeDate, after = afterDate)
.map { DecodedMessageWrapper.encode(it) }
.map { DecodedMessageWrapper.encode(it, topic) }
}

AsyncFunction("loadBatchMessages") { clientAddress: String, topics: List<String> ->
Expand Down Expand Up @@ -258,10 +255,11 @@ class XMTPModule : Module() {
}

client.conversations.listBatchMessages(topicsList)
.map { DecodedMessageWrapper.encode(it) }
// TODO: change xmtp-android `listBatchMessages` to include `topic`
.map { DecodedMessageWrapper.encode(it, "") }
}

AsyncFunction("sendMessage") { clientAddress: String, conversationTopic: String, conversationID: String?, contentJson: String ->
AsyncFunction("sendMessage") { clientAddress: String, conversationTopic: String, contentJson: String ->
logV("sendMessage")
val conversation =
findConversation(
Expand All @@ -276,17 +274,28 @@ class XMTPModule : Module() {
)
}

AsyncFunction("createConversation") { clientAddress: String, peerAddress: String, conversationID: String? ->
logV("createConversation")
AsyncFunction("createConversation") { clientAddress: String, peerAddress: String, contextJson: String ->
logV("createConversation: $contextJson")
val client = clients[clientAddress] ?: throw XMTPException("No client")

val context = JsonParser.parseString(contextJson).asJsonObject
val conversation = client.conversations.newConversation(
peerAddress,
context = InvitationV1ContextBuilder.buildFromConversation(
conversationId = conversationID ?: "", metadata = mapOf()
conversationId = when {
context.has("conversationID") -> context.get("conversationID").asString
else -> ""
},
metadata = when {
context.has("metadata") -> {
val metadata = context.get("metadata").asJsonObject
metadata.entrySet().associate { (key, value) -> key to value.asString }
}

else -> mapOf()
},
)
)
ConversationWrapper.encode(ConversationWithClientAddress(client, conversation))
ConversationWrapper.encode(client, conversation)
}

Function("subscribeToConversations") { clientAddress: String ->
Expand All @@ -299,21 +308,19 @@ class XMTPModule : Module() {
subscribeToAllMessages(clientAddress = clientAddress)
}

AsyncFunction("subscribeToMessages") { clientAddress: String, topic: String, conversationID: String? ->
AsyncFunction("subscribeToMessages") { clientAddress: String, topic: String ->
logV("subscribeToMessages")
subscribeToMessages(
clientAddress = clientAddress,
topic = topic,
conversationId = conversationID
topic = topic
)
}

AsyncFunction("unsubscribeFromMessages") { clientAddress: String, topic: String, conversationID: String? ->
AsyncFunction("unsubscribeFromMessages") { clientAddress: String, topic: String ->
logV("unsubscribeFromMessages")
unsubscribeFromMessages(
clientAddress = clientAddress,
topic = topic,
conversationId = conversationID
topic = topic
)
}

Expand All @@ -333,9 +340,9 @@ class XMTPModule : Module() {
}
}

AsyncFunction("decodeMessage") { clientAddress: String, topic: String, encryptedMessage: String, conversationID: String? ->
AsyncFunction("decodeMessage") { clientAddress: String, topic: String, encryptedMessage: String ->
logV("decodeMessage")
val encryptedMessageData = Base64.decode(encryptedMessage, Base64.NO_WRAP)
val encryptedMessageData = Base64.decode(encryptedMessage, NO_WRAP)
val envelope = EnvelopeBuilder.buildFromString(topic, Date(), encryptedMessageData)
val conversation =
findConversation(
Expand All @@ -344,7 +351,7 @@ class XMTPModule : Module() {
)
?: throw XMTPException("no conversation found for $topic")
val decodedMessage = conversation.decode(envelope)
DecodedMessageWrapper.encode(decodedMessage)
DecodedMessageWrapper.encode(decodedMessage, topic)
}
}

Expand Down Expand Up @@ -375,16 +382,15 @@ class XMTPModule : Module() {
private fun subscribeToConversations(clientAddress: String) {
val client = clients[clientAddress] ?: throw XMTPException("No client")

subscriptions["conversations"]?.cancel()
subscriptions["conversations"] = CoroutineScope(Dispatchers.IO).launch {
try {
client!!.conversations.stream().collect { conversation ->
client.conversations.stream().collect { conversation ->
sendEvent(
"conversation",
mapOf(
"topic" to conversation.topic,
"peerAddress" to conversation.peerAddress,
"version" to if (conversation.version == Conversation.Version.V1) "v1" else "v2",
"conversationID" to conversation.conversationId
"clientAddress" to clientAddress,
"conversation" to ConversationWrapper.encodeToObj(client, conversation)
)
)
}
Expand All @@ -398,16 +404,16 @@ class XMTPModule : Module() {
private fun subscribeToAllMessages(clientAddress: String) {
val client = clients[clientAddress] ?: throw XMTPException("No client")

subscriptions["messages"]?.cancel()
subscriptions["messages"] = CoroutineScope(Dispatchers.IO).launch {
try {
client!!.conversations.streamAllMessages().collect { message ->
client.conversations.streamAllMessages().collect { message ->
sendEvent(
"message",
mapOf(
"id" to message.id,
"content" to message.body,
"senderAddress" to message.senderAddress,
"sent" to message.sent
"clientAddress" to clientAddress,
// TODO: change xmtp-android `streamAllMessages` to include `topic`
"message" to DecodedMessageWrapper.encodeMap(message, ""),
)
)
}
Expand All @@ -418,22 +424,22 @@ class XMTPModule : Module() {
}
}

private fun subscribeToMessages(clientAddress: String, topic: String, conversationId: String?) {
private fun subscribeToMessages(clientAddress: String, topic: String) {
val conversation =
findConversation(
clientAddress = clientAddress,
topic = topic
) ?: return
subscriptions[conversation.cacheKey(clientAddress)]?.cancel()
subscriptions[conversation.cacheKey(clientAddress)] =
CoroutineScope(Dispatchers.IO).launch {
try {
conversation.streamMessages().collect { message ->
sendEvent(
"message",
mapOf(
"topic" to conversation.topic,
"conversationID" to conversation.conversationId,
"messageJSON" to DecodedMessageWrapper.encode(message)
"clientAddress" to clientAddress,
"message" to DecodedMessageWrapper.encodeMap(message, topic),
)
)
}
Expand All @@ -447,7 +453,6 @@ class XMTPModule : Module() {
private fun unsubscribeFromMessages(
clientAddress: String,
topic: String,
conversationId: String?,
) {
val conversation =
findConversation(
Expand All @@ -459,7 +464,7 @@ class XMTPModule : Module() {

private fun logV(msg: String) {
if (isDebugEnabled) {
Log.v("XMTPModule", msg);
Log.v("XMTPModule", msg)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,34 @@ import com.google.gson.GsonBuilder
import org.xmtp.android.library.Client
import org.xmtp.android.library.Conversation

data class ConversationWithClientAddress(
var clientAddress: String,
var topic: String,
var peerAddress: String,
var version: String,
var conversationId: String?,
) {
constructor(client: Client, conversation: Conversation): this(
clientAddress = client.address,
topic = conversation.topic,
peerAddress = conversation.peerAddress,
version = if (conversation.version == Conversation.Version.V1) "v1" else "v2",
conversationId = conversation.conversationId)

}

class ConversationWrapper {

companion object {
fun encode(model: ConversationWithClientAddress): String {
val gson = GsonBuilder().create()
val conversation = mapOf(
"clientAddress" to model.clientAddress,
"topic" to model.topic,
"peerAddress" to model.peerAddress,
"version" to model.version,
"conversationID" to model.conversationId
fun encodeToObj(client: Client, conversation: Conversation): Map<String, Any> {
val context = when (conversation.version) {
Conversation.Version.V2 -> mapOf<String, Any>(
"conversationID" to (conversation.conversationId ?: ""),
// TODO: expose the context/metadata explicitly in xmtp-android
"metadata" to conversation.toTopicData().invitation.context.metadataMap,
)

else -> mapOf()
}
return mapOf(
"clientAddress" to client.address,
"createdAt" to conversation.createdAt.time,
"context" to context,
"topic" to conversation.topic,
"peerAddress" to conversation.peerAddress,
"version" to if (conversation.version == Conversation.Version.V1) "v1" else "v2",
"conversationID" to (conversation.conversationId ?: "")
)
return gson.toJson(conversation)
}

fun encode(client: Client, conversation: Conversation): String {
val gson = GsonBuilder().create()
val obj = encodeToObj(client, conversation)
return gson.toJson(obj)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.GsonBuilder
import org.xmtp.android.library.DecodedMessage
import org.xmtp.android.library.codecs.id

class DecodedMessageWrapper {

companion object {
fun encode(model: DecodedMessage): String {
fun encode(model: DecodedMessage, topic: String): String {
val gson = GsonBuilder().create()
val message = encodeMap(model)
val message = encodeMap(model, topic)
return gson.toJson(message)
}

fun encodeMap(model: DecodedMessage): Map<String, Any> = mapOf(
fun encodeMap(model: DecodedMessage, topic: String): Map<String, Any> = mapOf(
"id" to model.id,
"topic" to topic,
"contentTypeId" to model.encodedContent.type.id,
"content" to ContentJson(model.encodedContent).toJsonMap(),
"senderAddress" to model.senderAddress,
"sent" to model.sent.getTime(),
"sent" to model.sent.time,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = expo.modules.xmtpreactnativesdk.example;
PRODUCT_NAME = "xmtpreactnativesdkexample";
PRODUCT_NAME = xmtpreactnativesdkexample;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -451,7 +451,7 @@
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = expo.modules.xmtpreactnativesdk.example;
PRODUCT_NAME = "xmtpreactnativesdkexample";
PRODUCT_NAME = xmtpreactnativesdkexample;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
Expand Down
2 changes: 1 addition & 1 deletion example/src/TestScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export default function TestScreen(): JSX.Element {
accessibilityLabel="tests-complete"
style={{ paddingHorizontal: 12 }}
>
{tests.slice(0, completedTests + 1).map((test: Test, i) => {
{(tests || []).slice(0, completedTests + 1).map((test: Test, i) => {
return (
<TestView
test={test}
Expand Down
Loading
Loading