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

Speed up build client performance #575

Merged
merged 4 commits into from
Dec 18, 2024
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
8 changes: 8 additions & 0 deletions .changeset/wet-wasps-search.md
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -191,6 +192,7 @@ class XMTPModule : Module() {
}

private var clients: MutableMap<String, Client> = 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
Expand Down Expand Up @@ -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<Int>, authParams: String ->
withContext(Dispatchers.IO) {
logV("createRandom")
Expand All @@ -299,10 +310,12 @@ 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)
}
}
Expand All @@ -324,8 +337,10 @@ 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))
Expand All @@ -339,9 +354,15 @@ 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)
}
}
Expand Down Expand Up @@ -450,7 +471,8 @@ class XMTPModule : Module() {
Client.canMessage(
peerAddresses,
context,
apiEnvironments(environment, null)
apiEnvironments(environment, null),
apiClient = apiClient
)
}
}
Expand Down
24 changes: 24 additions & 0 deletions example/src/tests/groupPerformanceTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
})
20 changes: 16 additions & 4 deletions ios/XMTPModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ actor IsolatedManager<T> {
public class XMTPModule: Module {
var signer: ReactNativeSigner?
let clientsManager = ClientsManager()
var apiClient: XmtpApiClient?
let subscriptionsManager = IsolatedManager<Task<Void, Never>>()
private var preAuthenticateToInboxCallbackDeferred: DispatchSemaphore?

Expand Down Expand Up @@ -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],
Expand All @@ -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)
Expand Down Expand Up @@ -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))
}
Expand All @@ -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)
}

Expand Down
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ export async function receiveSCWSignature(
return await XMTPModule.receiveSCWSignature(requestID, signature)
}

export async function connectToApiBackend(
environment: XMTPEnvironment
): Promise<void> {
return await XMTPModule.connectToApiBackend(environment)
}

export async function createRandom(
environment: 'local' | 'dev' | 'production',
dbEncryptionKey: Uint8Array,
Expand Down
10 changes: 10 additions & 0 deletions src/lib/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>} A Promise to let you know the api has been connected
*/
static async connectToApiBackend(env: XMTPEnvironment): Promise<void> {
return await XMTPModule.connectToApiBackend(env)
}

/**
* Creates a new instance of the XMTP Client with a randomly generated address.
*
Expand Down
Loading