Skip to content

Commit

Permalink
feat: do the iOS side of the work
Browse files Browse the repository at this point in the history
  • Loading branch information
nplasterer committed May 29, 2024
1 parent 84fc467 commit d3dd72f
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 42 deletions.
20 changes: 10 additions & 10 deletions android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1244,8 +1244,8 @@ class XMTPModule : Module() {
private fun subscribeToGroups(clientAddress: String) {
val client = clients[clientAddress] ?: throw XMTPException("No client")

subscriptions[getGroupsKey(clientAddress)]?.cancel()
subscriptions[getGroupsKey(clientAddress)] = CoroutineScope(Dispatchers.IO).launch {
subscriptions[getGroupsKey(client.inboxId)]?.cancel()
subscriptions[getGroupsKey(client.inboxId)] = CoroutineScope(Dispatchers.IO).launch {
try {
client.conversations.streamGroups().collect { group ->
sendEvent(
Expand All @@ -1258,7 +1258,7 @@ class XMTPModule : Module() {
}
} catch (e: Exception) {
Log.e("XMTPModule", "Error in group subscription: $e")
subscriptions[getGroupsKey(clientAddress)]?.cancel()
subscriptions[getGroupsKey(client.inboxId)]?.cancel()
}
}
}
Expand Down Expand Up @@ -1314,8 +1314,8 @@ class XMTPModule : Module() {
private fun subscribeToAllGroupMessages(clientAddress: String) {
val client = clients[clientAddress] ?: throw XMTPException("No client")

subscriptions[getGroupMessagesKey(clientAddress)]?.cancel()
subscriptions[getGroupMessagesKey(clientAddress)] = CoroutineScope(Dispatchers.IO).launch {
subscriptions[getGroupMessagesKey(client.inboxId)]?.cancel()
subscriptions[getGroupMessagesKey(client.inboxId)] = CoroutineScope(Dispatchers.IO).launch {
try {
client.conversations.streamAllGroupDecryptedMessages().collect { message ->
sendEvent(
Expand All @@ -1328,7 +1328,7 @@ class XMTPModule : Module() {
}
} catch (e: Exception) {
Log.e("XMTPModule", "Error in all group messages subscription: $e")
subscriptions[getGroupMessagesKey(clientAddress)]?.cancel()
subscriptions[getGroupMessagesKey(client.inboxId)]?.cancel()
}
}
}
Expand Down Expand Up @@ -1392,16 +1392,16 @@ class XMTPModule : Module() {
return "messages:$clientAddress"
}

private fun getGroupMessagesKey(clientAddress: String): String {
return "groupMessages:$clientAddress"
private fun getGroupMessagesKey(inboxId: String): String {
return "groupMessages:$inboxId"
}

private fun getConversationsKey(clientAddress: String): String {
return "conversations:$clientAddress"
}

private fun getGroupsKey(clientAddress: String): String {
return "groups:$clientAddress"
private fun getGroupsKey(inboxId: String): String {
return "groups:$inboxId"
}

private suspend fun unsubscribeFromMessages(
Expand Down
117 changes: 85 additions & 32 deletions ios/XMTPModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ extension Conversation {
}

extension XMTP.Group {
static func cacheKeyForId(clientAddress: String, id: String) -> String {
return "\(clientAddress):\(id)"
static func cacheKeyForId(inboxId: String, id: String) -> String {
return "\(inboxId):\(id)"
}

func cacheKey(_ clientAddress: String) -> String {
return XMTP.Group.cacheKeyForId(clientAddress: clientAddress, id: id.toHex)
func cacheKey(_ inboxId: String) -> String {
return XMTP.Group.cacheKeyForId(inboxId: inboxId, id: id.toHex)
}
}

Expand Down Expand Up @@ -90,13 +90,35 @@ public class XMTPModule: Module {
return "No Client."
}
}

AsyncFunction("inboxId") { (clientAddress: String) -> String in
if let client = await clientsManager.getClient(key: clientAddress) {
return client.inboxID
} else {
return "No Client."
}
}

AsyncFunction("deleteLocalDatabase") { (clientAddress: String) in
guard let client = await clientsManager.getClient(key: clientAddress) else {
throw Error.noClient
}
try client.deleteLocalDatabase()
}

AsyncFunction("dropLocalDatabaseConnection") { (clientAddress: String) in
guard let client = await clientsManager.getClient(key: clientAddress) else {
throw Error.noClient
}
try client.dropLocalDatabaseConnection()
}

AsyncFunction("reconnectLocalDatabase") { (clientAddress: String) in
guard let client = await clientsManager.getClient(key: clientAddress) else {
throw Error.noClient
}
try await client.reconnectLocalDatabase()
}

//
// Auth functions
Expand All @@ -117,17 +139,18 @@ public class XMTPModule: Module {
let encryptionKeyData = dbEncryptionKey == nil ? nil : Data(dbEncryptionKey!)

let options = createClientConfig(env: environment, appVersion: appVersion, preEnableIdentityCallback: preEnableIdentityCallback, preCreateIdentityCallback: preCreateIdentityCallback, mlsAlpha: enableAlphaMls == true, encryptionKey: encryptionKeyData)
try await clientsManager.updateClient(key: address, client: await XMTP.Client.create(account: signer, options: options))
let client = try await XMTP.Client.create(account: signer, options: options)
await clientsManager.updateClient(key: address, client: client)
self.signer = nil
sendEvent("authed")
sendEvent("authed", ["inboxId": client.inboxID])
}

Function("receiveSignature") { (requestID: String, signature: String) in
try signer?.handle(id: requestID, signature: signature)
}

// Generate a random wallet and set the client to that
AsyncFunction("createRandom") { (environment: String, appVersion: String?, hasCreateIdentityCallback: Bool?, hasEnableIdentityCallback: Bool?, enableAlphaMls: Bool?, dbEncryptionKey: [UInt8]?) -> String in
AsyncFunction("createRandom") { (environment: String, appVersion: String?, hasCreateIdentityCallback: Bool?, hasEnableIdentityCallback: Bool?, enableAlphaMls: Bool?, dbEncryptionKey: [UInt8]?) -> [String: String] in
try requireNotProductionEnvForAlphaMLS(enableAlphaMls: enableAlphaMls, environment: environment)

let privateKey = try PrivateKey.generate()
Expand All @@ -145,11 +168,14 @@ public class XMTPModule: Module {
let client = try await Client.create(account: privateKey, options: options)

await clientsManager.updateClient(key: client.address, client: client)
return client.address
return [
"address": client.address,
"inboxId": client.inboxID
]
}

// Create a client using its serialized key bundle.
AsyncFunction("createFromKeyBundle") { (keyBundle: String, environment: String, appVersion: String?, enableAlphaMls: Bool?, dbEncryptionKey: [UInt8]?) -> String in
AsyncFunction("createFromKeyBundle") { (keyBundle: String, environment: String, appVersion: String?, enableAlphaMls: Bool?, dbEncryptionKey: [UInt8]?) -> [String: String] in
try requireNotProductionEnvForAlphaMLS(enableAlphaMls: enableAlphaMls, environment: environment)

do {
Expand All @@ -162,7 +188,10 @@ public class XMTPModule: Module {
let options = createClientConfig(env: environment, appVersion: appVersion, mlsAlpha: enableAlphaMls == true, encryptionKey: encryptionKeyData)
let client = try await Client.from(bundle: bundle, options: options)
await clientsManager.updateClient(key: client.address, client: client)
return client.address
return [
"address": client.address,
"inboxId": client.inboxID
]
} catch {
print("ERRO! Failed to create client: \(error)")
throw error
Expand Down Expand Up @@ -643,9 +672,9 @@ public class XMTPModule: Module {
let permissionLevel: GroupPermissions = {
switch permission {
case "admin_only":
return .groupCreatorIsAdmin
return .adminOnly
default:
return .everyoneIsAdmin
return .allMembers
}
}()
do {
Expand All @@ -665,7 +694,7 @@ public class XMTPModule: Module {
guard let group = try await findGroup(clientAddress: clientAddress, id: groupId) else {
throw Error.conversationNotFound("no group found for \(groupId)")
}
return group.memberInboxIds
return try group.members.map(\.inboxId)
}

AsyncFunction("syncGroups") { (clientAddress: String) in
Expand Down Expand Up @@ -708,6 +737,30 @@ public class XMTPModule: Module {

try await group.removeMembers(addresses: peerAddresses)
}

AsyncFunction("addGroupMembersByInboxId") { (clientAddress: String, id: String, inboxIds: [String]) in
guard let client = await clientsManager.getClient(key: clientAddress) else {
throw Error.noClient
}

guard let group = try await findGroup(clientAddress: clientAddress, id: id) else {
throw Error.conversationNotFound("no group found for \(id)")
}
try await group.addMembersByInboxId(inboxIds: inboxIds)
}

AsyncFunction("removeGroupMembersByInboxId") { (clientAddress: String, id: String, inboxIds: [String]) in
guard let client = await clientsManager.getClient(key: clientAddress) else {
throw Error.noClient
}

guard let group = try await findGroup(clientAddress: clientAddress, id: id) else {
throw Error.conversationNotFound("no group found for \(id)")
}

try await group.removeMembersByInboxId(inboxIds: inboxIds)
}


AsyncFunction("groupName") { (clientAddress: String, id: String) -> String in
guard let client = await clientsManager.getClient(key: clientAddress) else {
Expand Down Expand Up @@ -760,7 +813,7 @@ public class XMTPModule: Module {
throw Error.conversationNotFound("no group found for \(id)")
}

return try group.isAdmin()
return try group.isAdmin(inboxId: client.inboxID)
}

AsyncFunction("processGroupMessage") { (clientAddress: String, id: String, encryptedMessage: String) -> String in
Expand Down Expand Up @@ -829,8 +882,8 @@ public class XMTPModule: Module {
await subscriptionsManager.get(getMessagesKey(clientAddress: clientAddress))?.cancel()
}

AsyncFunction("unsubscribeFromAllGroupMessages") { (clientAddress: String) in
await subscriptionsManager.get(getGroupMessagesKey(clientAddress: clientAddress))?.cancel()
AsyncFunction("unsubscribeFromAllGroupMessages") { (inboxId: String) in
await subscriptionsManager.get(getGroupMessagesKey(inboxId: inboxId))?.cancel()
}


Expand All @@ -842,8 +895,8 @@ public class XMTPModule: Module {
try await unsubscribeFromGroupMessages(clientAddress: clientAddress, id: id)
}

AsyncFunction("unsubscribeFromGroups") { (clientAddress: String) in
await subscriptionsManager.get(getGroupsKey(clientAddress: clientAddress))?.cancel()
AsyncFunction("unsubscribeFromGroups") { (inboxId: String) in
await subscriptionsManager.get(getGroupsKey(inboxId: inboxId))?.cancel()
}

AsyncFunction("registerPushToken") { (pushServer: String, token: String) in
Expand Down Expand Up @@ -947,14 +1000,14 @@ public class XMTPModule: Module {
guard let conversation = try await findConversation(clientAddress: clientAddress, topic: conversationTopic) else {
throw Error.conversationNotFound(conversationTopic)
}
return ConsentWrapper.consentStateToString(state: await conversation.consentState())
return try ConsentWrapper.consentStateToString(state: await conversation.consentState())
}

AsyncFunction("groupConsentState") { (clientAddress: String, groupId: String) -> String in
guard let group = try await findGroup(clientAddress: clientAddress, id: groupId) else {
throw Error.conversationNotFound("no group found for \(groupId)")
}
return ConsentWrapper.consentStateToString(state: await XMTP.Conversation.group(group).consentState())
return try ConsentWrapper.consentStateToString(state: await XMTP.Conversation.group(group).consentState())
}

AsyncFunction("consentList") { (clientAddress: String) -> [String] in
Expand Down Expand Up @@ -1068,7 +1121,7 @@ public class XMTPModule: Module {
throw Error.noClient
}

let cacheKey = XMTP.Group.cacheKeyForId(clientAddress: clientAddress, id: id)
let cacheKey = XMTP.Group.cacheKeyForId(inboxId: client.inboxID, id: id)
if let group = await groupsManager.get(cacheKey) {
return group
} else if let group = try await client.conversations.groups().first(where: { $0.id.toHex == id }) {
Expand Down Expand Up @@ -1131,8 +1184,8 @@ public class XMTPModule: Module {
return
}

await subscriptionsManager.get(getGroupMessagesKey(clientAddress: clientAddress))?.cancel()
await subscriptionsManager.set(getGroupMessagesKey(clientAddress: clientAddress), Task {
await subscriptionsManager.get(getGroupMessagesKey(inboxId: client.inboxID))?.cancel()
await subscriptionsManager.set(getGroupMessagesKey(inboxId: client.inboxID), Task {
do {
for try await message in await client.conversations.streamAllGroupDecryptedMessages() {
do {
Expand Down Expand Up @@ -1185,8 +1238,8 @@ public class XMTPModule: Module {
guard let client = await clientsManager.getClient(key: clientAddress) else {
return
}
await subscriptionsManager.get(getGroupsKey(clientAddress: clientAddress))?.cancel()
await subscriptionsManager.set(getGroupsKey(clientAddress: clientAddress), Task {
await subscriptionsManager.get(getGroupsKey(inboxId: client.inboxID))?.cancel()
await subscriptionsManager.set(getGroupsKey(inboxId: client.inboxID), Task {
do {
for try await group in try await client.conversations.streamGroups() {
try sendEvent("group", [
Expand All @@ -1196,7 +1249,7 @@ public class XMTPModule: Module {
}
} catch {
print("Error in groups subscription: \(error)")
await subscriptionsManager.get(getGroupsKey(clientAddress: clientAddress))?.cancel()
await subscriptionsManager.get(getGroupsKey(inboxId: client.inboxID))?.cancel()
}
})
}
Expand Down Expand Up @@ -1231,8 +1284,8 @@ public class XMTPModule: Module {
throw Error.noClient
}

await subscriptionsManager.get(group.cacheKey(clientAddress))?.cancel()
await subscriptionsManager.set(group.cacheKey(clientAddress), Task {
await subscriptionsManager.get(group.cacheKey(client.inboxID))?.cancel()
await subscriptionsManager.set(group.cacheKey(client.inboxID), Task {
do {
for try await message in group.streamDecryptedMessages() {
do {
Expand Down Expand Up @@ -1273,16 +1326,16 @@ public class XMTPModule: Module {
return "messages:\(clientAddress)"
}

func getGroupMessagesKey(clientAddress: String) -> String {
return "groupMessages:\(clientAddress)"
func getGroupMessagesKey(inboxId: String) -> String {
return "groupMessages:\(inboxId)"
}

func getConversationsKey(clientAddress: String) -> String {
return "conversations:\(clientAddress)"
}

func getGroupsKey(clientAddress: String) -> String {
return "groups:\(clientAddress)"
func getGroupsKey(inboxId: String) -> String {
return "groups:\(inboxId)"
}

func preEnableIdentityCallback() {
Expand Down

0 comments on commit d3dd72f

Please sign in to comment.