From 940825efdb258d8e441d2c07bc57c61671ad8606 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 18 Dec 2024 11:52:59 -0800 Subject: [PATCH 1/3] add the ability to cache the api client in android --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 20 +++++++++++++--- example/src/tests/groupPerformanceTests.ts | 24 +++++++++++++++++++ src/index.ts | 6 +++++ src/lib/Client.ts | 10 ++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 854d8a32..1436c7ff 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -59,6 +59,7 @@ import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.Signature import org.xmtp.android.library.push.Service import org.xmtp.android.library.push.XMTPPush +import uniffi.xmtpv3.XmtpApiClient import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption import java.io.BufferedReader @@ -191,6 +192,7 @@ class XMTPModule : Module() { } private var clients: MutableMap = mutableMapOf() + private var apiClient: XmtpApiClient? = null private var xmtpPush: XMTPPush? = null private var signer: ReactNativeSigner? = null private val isDebugEnabled = BuildConfig.DEBUG // TODO: consider making this configurable @@ -290,6 +292,15 @@ class XMTPModule : Module() { signer?.handleSCW(id = requestID, signature = signature) } + AsyncFunction("connectToApiBackend") Coroutine { environment: String -> + withContext(Dispatchers.IO) { + logV("connectToApiBackend") + val api = apiEnvironments(environment, null) + val xmtpApiClient = Client().connectToApiBackend(api) + apiClient = xmtpApiClient + } + } + AsyncFunction("createRandom") Coroutine { hasPreAuthenticateToInboxCallback: Boolean?, dbEncryptionKey: List, authParams: String -> withContext(Dispatchers.IO) { logV("createRandom") @@ -299,10 +310,11 @@ class XMTPModule : Module() { authParams, hasPreAuthenticateToInboxCallback, ) - val randomClient = Client().create(account = privateKey, options = options) + val randomClient = Client().create(account = privateKey, options = options, apiClient = apiClient) ContentJson.Companion clients[randomClient.installationId] = randomClient + apiClient = randomClient.apiClient ClientWrapper.encodeToObj(randomClient) } } @@ -324,8 +336,9 @@ class XMTPModule : Module() { authParams, hasAuthInboxCallback, ) - val client = Client().create(account = reactSigner, options = options) + val client = Client().create(account = reactSigner, options = options, apiClient = apiClient) clients[client.installationId] = client + apiClient = client.apiClient ContentJson.Companion signer = null sendEvent("authed", ClientWrapper.encodeToObj(client)) @@ -339,9 +352,10 @@ class XMTPModule : Module() { dbEncryptionKey, authParams, ) - val client = Client().build(address = address, options = options, inboxId = inboxId) + val client = Client().build(address = address, options = options, inboxId = inboxId, apiClient = apiClient) ContentJson.Companion clients[client.installationId] = client + apiClient = client.apiClient ClientWrapper.encodeToObj(client) } } diff --git a/example/src/tests/groupPerformanceTests.ts b/example/src/tests/groupPerformanceTests.ts index abada6c0..df43994f 100644 --- a/example/src/tests/groupPerformanceTests.ts +++ b/example/src/tests/groupPerformanceTests.ts @@ -88,6 +88,26 @@ test('building and creating', async () => { const end3 = performance.now() console.log(`Built a client with inboxId in ${end3 - start3}ms`) + await Client.connectToApiBackend('dev') + const start4 = performance.now() + await Client.createRandom({ + env: 'dev', + appVersion: 'Testing/0.0.0', + dbEncryptionKey: keyBytes, + dbDirectory: dbDirPath, + codecs: [ + new ReactionCodec(), + new ReplyCodec(), + new GroupUpdatedCodec(), + new StaticAttachmentCodec(), + new RemoteAttachmentCodec(), + ], + }) + const end4 = performance.now() + console.log( + `Created a client after connecting to backend in ${end4 - start4}ms` + ) + assert( end2 - start2 < end1 - start1, 'building a client should be faster than creating one' @@ -100,6 +120,10 @@ test('building and creating', async () => { end3 - start3 < end2 - start2, 'building a client with an inboxId should be faster than building without' ) + assert( + end4 - start4 < end1 - start1, + 'creating a client with an apiClient cached should be faster than creating one without' + ) return true }) diff --git a/src/index.ts b/src/index.ts index a48bb7c9..be4acc4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -119,6 +119,12 @@ export async function receiveSCWSignature( return await XMTPModule.receiveSCWSignature(requestID, signature) } +export async function connectToApiBackend( + environment: XMTPEnvironment +): Promise { + return await XMTPModule.connectToApiBackend(environment) +} + export async function createRandom( environment: 'local' | 'dev' | 'production', dbEncryptionKey: Uint8Array, diff --git a/src/lib/Client.ts b/src/lib/Client.ts index eaf6492d..0689d659 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -79,6 +79,16 @@ export class Client< } } + /** + * Connects to the XMTP api backend to speed up creating and building future clients. + * + * @param {XMTPEnvironment} env - Environment to connect to + * @returns {Promise} A Promise to let you know the api has been connected + */ + static async connectToApiBackend(env: XMTPEnvironment): Promise { + return await XMTPModule.connectToApiBackend(env) + } + /** * Creates a new instance of the XMTP Client with a randomly generated address. * From fd6b8fc1aec969f42090d459342cba1cd6a3a80b Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 18 Dec 2024 12:23:25 -0800 Subject: [PATCH 2/3] make it faster --- .../modules/xmtpreactnativesdk/XMTPModule.kt | 18 ++++++++++++----- ios/XMTPModule.swift | 20 +++++++++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 1436c7ff..dc080891 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -296,7 +296,7 @@ class XMTPModule : Module() { withContext(Dispatchers.IO) { logV("connectToApiBackend") val api = apiEnvironments(environment, null) - val xmtpApiClient = Client().connectToApiBackend(api) + val xmtpApiClient = Client.connectToApiBackend(api) apiClient = xmtpApiClient } } @@ -310,7 +310,8 @@ class XMTPModule : Module() { authParams, hasPreAuthenticateToInboxCallback, ) - val randomClient = Client().create(account = privateKey, options = options, apiClient = apiClient) + val randomClient = + Client().create(account = privateKey, options = options, apiClient = apiClient) ContentJson.Companion clients[randomClient.installationId] = randomClient @@ -336,7 +337,8 @@ class XMTPModule : Module() { authParams, hasAuthInboxCallback, ) - val client = Client().create(account = reactSigner, options = options, apiClient = apiClient) + val client = + Client().create(account = reactSigner, options = options, apiClient = apiClient) clients[client.installationId] = client apiClient = client.apiClient ContentJson.Companion @@ -352,7 +354,12 @@ class XMTPModule : Module() { dbEncryptionKey, authParams, ) - val client = Client().build(address = address, options = options, inboxId = inboxId, apiClient = apiClient) + val client = Client().build( + address = address, + options = options, + inboxId = inboxId, + apiClient = apiClient + ) ContentJson.Companion clients[client.installationId] = client apiClient = client.apiClient @@ -464,7 +471,8 @@ class XMTPModule : Module() { Client.canMessage( peerAddresses, context, - apiEnvironments(environment, null) + apiEnvironments(environment, null), + apiClient = apiClient ) } } diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index c0f335cb..05d36c4f 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -31,6 +31,7 @@ actor IsolatedManager { public class XMTPModule: Module { var signer: ReactNativeSigner? let clientsManager = ClientsManager() + var apiClient: XmtpApiClient? let subscriptionsManager = IsolatedManager>() private var preAuthenticateToInboxCallbackDeferred: DispatchSemaphore? @@ -219,6 +220,14 @@ public class XMTPModule: Module { try signer?.handleSCW(id: requestID, signature: signature) } + AsyncFunction("connectToApiBackend") { + (environment: String) in + let xmtpApiClient = try await XMTP.Client.connectToApiBackend( + api: createApiClient(env: environment) + ) + apiClient = xmtpApiClient + } + AsyncFunction("createRandom") { ( hasAuthenticateToInboxCallback: Bool?, dbEncryptionKey: [UInt8], @@ -241,8 +250,8 @@ public class XMTPModule: Module { preAuthenticateToInboxCallback: preAuthenticateToInboxCallback ) let client = try await Client.create( - account: privateKey, options: options) - + account: privateKey, options: options, apiClient: apiClient) + apiClient = client.apiClient await clientsManager.updateClient( key: client.installationID, client: client) return try ClientWrapper.encodeToObj(client) @@ -277,9 +286,10 @@ public class XMTPModule: Module { preAuthenticateToInboxCallback: preAuthenticateToInboxCallback ) let client = try await XMTP.Client.create( - account: signer, options: options) + account: signer, options: options, apiClient: apiClient) await self.clientsManager.updateClient( key: client.installationID, client: client) + apiClient = client.apiClient self.signer = nil self.sendEvent("authed", try ClientWrapper.encodeToObj(client)) } @@ -299,9 +309,11 @@ public class XMTPModule: Module { preAuthenticateToInboxCallback: preAuthenticateToInboxCallback ) let client = try await XMTP.Client.build( - address: address, options: options, inboxId: inboxId) + address: address, options: options, inboxId: inboxId, + apiClient: apiClient) await clientsManager.updateClient( key: client.installationID, client: client) + apiClient = client.apiClient return try ClientWrapper.encodeToObj(client) } From 5dbd79e29db9a15c95550168cb5159ac17231969 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 18 Dec 2024 12:27:57 -0800 Subject: [PATCH 3/3] Create wet-wasps-search.md --- .changeset/wet-wasps-search.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/wet-wasps-search.md diff --git a/.changeset/wet-wasps-search.md b/.changeset/wet-wasps-search.md new file mode 100644 index 00000000..bc420359 --- /dev/null +++ b/.changeset/wet-wasps-search.md @@ -0,0 +1,8 @@ +--- +"@xmtp/react-native-sdk": patch +--- + +Speed up build client performance +Adds ability to filter syncAllConversations by consent state +Fixes potential forked group issues +Renames senderAddress to senderInboxId