Skip to content

Commit

Permalink
do the entire swift side
Browse files Browse the repository at this point in the history
  • Loading branch information
nplasterer committed Oct 25, 2024
1 parent 50b080d commit 4fdbf73
Show file tree
Hide file tree
Showing 9 changed files with 426 additions and 110 deletions.
65 changes: 39 additions & 26 deletions android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import org.xmtp.android.library.ClientOptions
import org.xmtp.android.library.ConsentState
import org.xmtp.android.library.Conversation
import org.xmtp.android.library.Conversations.ConversationOrder
import org.xmtp.android.library.Dm
import org.xmtp.android.library.Group
import org.xmtp.android.library.PreEventCallback
import org.xmtp.android.library.PreparedMessage
Expand Down Expand Up @@ -263,7 +262,7 @@ class XMTPModule : Module() {
"groupMessage",
"allGroupMessage",
"group",
)
)

Function("address") { inboxId: String ->
logV("address")
Expand Down Expand Up @@ -697,7 +696,7 @@ class XMTPModule : Module() {
withContext(Dispatchers.IO) {
logV("listGroups")
val client = clients[inboxId] ?: throw XMTPException("No client")
val params = ConversationParamsWrapper.groupParamsFromJson(groupParams ?: "")
val params = ConversationParamsWrapper.conversationParamsFromJson(groupParams ?: "")
val order = getConversationSortOrder(sortOrder ?: "")
val sortedGroupList = if (order == ConversationOrder.LAST_MESSAGE) {
client.conversations.listGroups()
Expand All @@ -717,11 +716,12 @@ class XMTPModule : Module() {
}
}

AsyncFunction("listV3Conversations") Coroutine { inboxId: String, groupParams: String?, sortOrder: String?, limit: Int? ->
AsyncFunction("listV3Conversations") Coroutine { inboxId: String, conversationParams: String?, sortOrder: String?, limit: Int? ->
withContext(Dispatchers.IO) {
logV("listV3Conversations")
val client = clients[inboxId] ?: throw XMTPException("No client")
val params = ConversationParamsWrapper.groupParamsFromJson(groupParams ?: "")
val params =
ConversationParamsWrapper.conversationParamsFromJson(conversationParams ?: "")
val order = getConversationSortOrder(sortOrder ?: "")
val conversations =
client.conversations.listConversations(order = order, limit = limit)
Expand Down Expand Up @@ -940,7 +940,7 @@ class XMTPModule : Module() {
val conversation = client.findConversation(id)
?: throw XMTPException("no conversation found for $id")
val sending = ContentJson.fromJson(contentJson)
conversation.prepareMessage(
conversation.prepareMessageV3(
content = sending.content,
options = SendOptions(contentType = sending.type)
)
Expand Down Expand Up @@ -1147,7 +1147,9 @@ class XMTPModule : Module() {
withContext(Dispatchers.IO) {
logV("listPeerInboxId")
val client = clients[inboxId] ?: throw XMTPException("No client")
val dm = (findConversation(inboxId, dmId) as Conversation.Dm).dm
val conversation = client.findConversation(dmId)
?: throw XMTPException("no conversation found for $dmId")
val dm = (conversation as Conversation.Dm).dm
dm.peerInboxId()
}
}
Expand Down Expand Up @@ -1543,7 +1545,12 @@ class XMTPModule : Module() {
val client = clients[inboxId] ?: throw XMTPException("No client")

val conversation =
client.conversations.conversationFromWelcome(Base64.decode(encryptedMessage, NO_WRAP))
client.conversations.conversationFromWelcome(
Base64.decode(
encryptedMessage,
NO_WRAP
)
)
ConversationContainerWrapper.encode(client, conversation)
}
}
Expand Down Expand Up @@ -1829,12 +1836,14 @@ class XMTPModule : Module() {
client.contacts.isGroupDenied(groupId)
}
}
AsyncFunction("updateGroupConsent") Coroutine { inboxId: String, groupId: String, state: String ->
AsyncFunction("updateConversationConsent") Coroutine { inboxId: String, conversationId: String, state: String ->
withContext(Dispatchers.IO) {
logV("updateGroupConsent")
val group = findGroup(inboxId, groupId)
logV("updateConversationConsent")
val client = clients[inboxId] ?: throw XMTPException("No client")
val conversation = client.findConversation(conversationId)
?: throw XMTPException("no group found for $conversationId")

group?.updateConsentState(getConsentState(state))
conversation.updateConsentState(getConsentState(state))
}
}

Expand Down Expand Up @@ -2023,22 +2032,26 @@ class XMTPModule : Module() {
val client = clients[inboxId] ?: throw XMTPException("No client")

subscriptions[getV3ConversationsKey(client.inboxId)]?.cancel()
subscriptions[getV3ConversationsKey(client.inboxId)] = CoroutineScope(Dispatchers.IO).launch {
try {
client.conversations.streamConversations().collect { conversation ->
sendEvent(
"conversationV3",
mapOf(
"inboxId" to inboxId,
"conversation" to ConversationContainerWrapper.encodeToObj(client, conversation)
subscriptions[getV3ConversationsKey(client.inboxId)] =
CoroutineScope(Dispatchers.IO).launch {
try {
client.conversations.streamConversations().collect { conversation ->
sendEvent(
"conversationV3",
mapOf(
"inboxId" to inboxId,
"conversation" to ConversationContainerWrapper.encodeToObj(
client,
conversation
)
)
)
)
}
} catch (e: Exception) {
Log.e("XMTPModule", "Error in group subscription: $e")
subscriptions[getV3ConversationsKey(client.inboxId)]?.cancel()
}
} catch (e: Exception) {
Log.e("XMTPModule", "Error in group subscription: $e")
subscriptions[getV3ConversationsKey(client.inboxId)]?.cancel()
}
}
}

private fun subscribeToAll(inboxId: String) {
Expand Down Expand Up @@ -2117,7 +2130,7 @@ class XMTPModule : Module() {
subscriptions[getConversationMessagesKey(inboxId)]?.cancel()
subscriptions[getConversationMessagesKey(inboxId)] = CoroutineScope(Dispatchers.IO).launch {
try {
client.conversations.streamAllGroupDecryptedMessages().collect { message ->
client.conversations.streamAllConversationDecryptedMessages().collect { message ->
sendEvent(
"allConversationMessages",
mapOf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ class ConversationParamsWrapper(
val lastMessage: Boolean = false,
) {
companion object {
fun groupParamsFromJson(groupParams: String): ConversationParamsWrapper {
if (groupParams.isEmpty()) return ConversationParamsWrapper()
val jsonOptions = JsonParser.parseString(groupParams).asJsonObject
fun conversationParamsFromJson(conversationParams: String): ConversationParamsWrapper {
if (conversationParams.isEmpty()) return ConversationParamsWrapper()
val jsonOptions = JsonParser.parseString(conversationParams).asJsonObject
return ConversationParamsWrapper(
if (jsonOptions.has("members")) jsonOptions.get("members").asBoolean else true,
if (jsonOptions.has("creatorInboxId")) jsonOptions.get("creatorInboxId").asBoolean else true,
Expand Down
8 changes: 4 additions & 4 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ PODS:
- GenericJSON (~> 2.0)
- Logging (~> 1.0.0)
- secp256k1.swift (~> 0.1)
- XMTP (0.15.2):
- XMTP (0.16.0):
- Connect-Swift (= 0.12.0)
- GzipSwift
- LibXMTP (= 0.5.10)
Expand All @@ -458,7 +458,7 @@ PODS:
- ExpoModulesCore
- MessagePacker
- secp256k1.swift
- XMTP (= 0.15.2)
- XMTP (= 0.16.0)
- Yoga (1.14.0)

DEPENDENCIES:
Expand Down Expand Up @@ -763,8 +763,8 @@ SPEC CHECKSUMS:
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959
XMTP: 7d47e6bc507db66dd01116ce2b4ed04dd3560a4f
XMTPReactNative: 1a946cd697598fb4bc560a637094e63c4d553df3
XMTP: 18d555dbf5afd3dcafa11b108042f9673da3c6b9
XMTPReactNative: cd8be3d8547d116005f3d0f4f207f19c7b34d035
Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9

PODFILE CHECKSUM: 0e6fe50018f34e575d38dc6a1fdf1f99c9596cdd
Expand Down
2 changes: 2 additions & 0 deletions ios/Wrappers/ConversationContainerWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ struct ConversationContainerWrapper {
switch conversation {
case .group(let group):
return try await GroupWrapper.encodeToObj(group, client: client)
case .dm(let dm):
return try await DmWrapper.encodeToObj(dm, client: client)
default:
return try ConversationWrapper.encodeToObj(conversation, client: client)
}
Expand Down
50 changes: 50 additions & 0 deletions ios/Wrappers/DmWrapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// DmWrapper.swift
// Pods
//
// Created by Naomi Plasterer on 10/24/24.
//

import Foundation
import XMTP

// Wrapper around XMTP.Dm to allow passing these objects back into react native.
struct DmWrapper {
static func encodeToObj(_ dm: XMTP.Dm, client: XMTP.Client, conversationParams: ConversationParamsWrapper = ConversationParamsWrapper()) async throws -> [String: Any] {
var result: [String: Any] = [
"clientAddress": client.address,
"id": dm.id,
"createdAt": UInt64(dm.createdAt.timeIntervalSince1970 * 1000),
"version": "DM",
"topic": dm.topic,
"peerInboxId": try await dm.peerInboxId
]

if conversationParams.members {
result["members"] = try await dm.members.compactMap { member in return try MemberWrapper.encode(member) }
}
if conversationParams.creatorInboxId {
result["creatorInboxId"] = try dm.creatorInboxId()
}
if conversationParams.consentState {
result["consentState"] = ConsentWrapper.consentStateToString(state: try dm.consentState())
}
if conversationParams.lastMessage {
if let lastMessage = try await dm.decryptedMessages(limit: 1).first {
result["lastMessage"] = try DecodedMessageWrapper.encode(lastMessage, client: client)
}
}

return result
}

static func encode(_ dm: XMTP.Dm, client: XMTP.Client, conversationParams: ConversationParamsWrapper = ConversationParamsWrapper()) async throws -> String {
let obj = try await encodeToObj(dm, client: client, conversationParams: conversationParams)
let data = try JSONSerialization.data(withJSONObject: obj)
guard let result = String(data: data, encoding: .utf8) else {
throw WrapperError.encodeError("could not encode dm")
}
return result
}
}

38 changes: 17 additions & 21 deletions ios/Wrappers/GroupWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,9 @@
import Foundation
import XMTP

enum ConversationOrder {
case lastMessage, createdAt
}

// Wrapper around XMTP.Group to allow passing these objects back into react native.
struct GroupWrapper {
static func encodeToObj(_ group: XMTP.Group, client: XMTP.Client, groupParams: GroupParamsWrapper = GroupParamsWrapper()) async throws -> [String: Any] {
static func encodeToObj(_ group: XMTP.Group, client: XMTP.Client, conversationParams: ConversationParamsWrapper = ConversationParamsWrapper()) async throws -> [String: Any] {
var result: [String: Any] = [
"clientAddress": client.address,
"id": group.id,
Expand All @@ -23,31 +19,31 @@ struct GroupWrapper {
"topic": group.topic
]

if groupParams.members {
if conversationParams.members {
result["members"] = try await group.members.compactMap { member in return try MemberWrapper.encode(member) }
}
if groupParams.creatorInboxId {
if conversationParams.creatorInboxId {
result["creatorInboxId"] = try group.creatorInboxId()
}
if groupParams.isActive {
if conversationParams.isActive {
result["isActive"] = try group.isActive()
}
if groupParams.addedByInboxId {
if conversationParams.addedByInboxId {
result["addedByInboxId"] = try group.addedByInboxId()
}
if groupParams.name {
if conversationParams.name {
result["name"] = try group.groupName()
}
if groupParams.imageUrlSquare {
if conversationParams.imageUrlSquare {
result["imageUrlSquare"] = try group.groupImageUrlSquare()
}
if groupParams.description {
if conversationParams.description {
result["description"] = try group.groupDescription()
}
if groupParams.consentState {
if conversationParams.consentState {
result["consentState"] = ConsentWrapper.consentStateToString(state: try group.consentState())
}
if groupParams.lastMessage {
if conversationParams.lastMessage {
if let lastMessage = try await group.decryptedMessages(limit: 1).first {
result["lastMessage"] = try DecodedMessageWrapper.encode(lastMessage, client: client)
}
Expand All @@ -56,8 +52,8 @@ struct GroupWrapper {
return result
}

static func encode(_ group: XMTP.Group, client: XMTP.Client, groupParams: GroupParamsWrapper = GroupParamsWrapper()) async throws -> String {
let obj = try await encodeToObj(group, client: client, groupParams: groupParams)
static func encode(_ group: XMTP.Group, client: XMTP.Client, conversationParams: ConversationParamsWrapper = ConversationParamsWrapper()) async throws -> String {
let obj = try await encodeToObj(group, client: client, conversationParams: conversationParams)
let data = try JSONSerialization.data(withJSONObject: obj)
guard let result = String(data: data, encoding: .utf8) else {
throw WrapperError.encodeError("could not encode group")
Expand All @@ -66,7 +62,7 @@ struct GroupWrapper {
}
}

struct GroupParamsWrapper {
struct ConversationParamsWrapper {
let members: Bool
let creatorInboxId: Bool
let isActive: Bool
Expand Down Expand Up @@ -99,14 +95,14 @@ struct GroupParamsWrapper {
self.lastMessage = lastMessage
}

static func groupParamsFromJson(_ groupParams: String) -> GroupParamsWrapper {
guard let jsonData = groupParams.data(using: .utf8),
static func conversationParamsFromJson(_ conversationParams: String) -> ConversationParamsWrapper {
guard let jsonData = conversationParams.data(using: .utf8),
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []),
let jsonDict = jsonObject as? [String: Any] else {
return GroupParamsWrapper()
return ConversationParamsWrapper()
}

return GroupParamsWrapper(
return ConversationParamsWrapper(
members: jsonDict["members"] as? Bool ?? true,
creatorInboxId: jsonDict["creatorInboxId"] as? Bool ?? true,
isActive: jsonDict["isActive"] as? Bool ?? true,
Expand Down
Loading

0 comments on commit 4fdbf73

Please sign in to comment.