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

Performance follow ups #451

Merged
merged 2 commits into from
Dec 20, 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
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ let package = Package(
.package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"),
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", exact: "1.8.3"),
.package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.13")
.package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.14")
],
targets: [
.target(
Expand Down
76 changes: 39 additions & 37 deletions Sources/XMTPiOS/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,27 @@ public struct ClientOptions {
}
}

actor ApiClientCache {
private var apiClientCache: [String: XmtpApiClient] = [:]

func getClient(forKey key: String) -> XmtpApiClient? {
return apiClientCache[key]
}

func setClient(_ client: XmtpApiClient, forKey key: String) {
apiClientCache[key] = client
}
}

public final class Client {
public let address: String
public let inboxID: String
public let libXMTPVersion: String = getVersionInfo()
public let dbPath: String
public let installationID: String
public let environment: XMTPEnvironment
public let apiClient: XmtpApiClient
private let ffiClient: LibXMTP.FfiXmtpClient
private static let apiCache = ApiClientCache()

public lazy var conversations: Conversations = .init(
client: self, ffiConversations: ffiClient.conversations())
Expand All @@ -112,12 +124,11 @@ public final class Client {
inboxId: String,
apiClient: XmtpApiClient? = nil
) async throws -> Client {
let (libxmtpClient, dbPath, apiClient) = try await initFFiClient(
let (libxmtpClient, dbPath) = try await initFFiClient(
accountAddress: accountAddress.lowercased(),
options: options,
signingKey: signingKey,
inboxId: inboxId,
apiClient: apiClient
inboxId: inboxId
)

let client = try Client(
Expand All @@ -126,8 +137,7 @@ public final class Client {
dbPath: dbPath,
installationID: libxmtpClient.installationId().toHex,
inboxID: libxmtpClient.inboxId(),
environment: options.api.env,
apiClient: apiClient
environment: options.api.env
)

// Register codecs
Expand All @@ -139,8 +149,7 @@ public final class Client {
}

public static func create(
account: SigningKey, options: ClientOptions,
apiClient: XmtpApiClient? = nil
account: SigningKey, options: ClientOptions
)
async throws -> Client
{
Expand All @@ -152,14 +161,12 @@ public final class Client {
accountAddress: accountAddress,
options: options,
signingKey: account,
inboxId: inboxId,
apiClient: apiClient
inboxId: inboxId
)
}

public static func build(
address: String, options: ClientOptions, inboxId: String? = nil,
apiClient: XmtpApiClient? = nil
address: String, options: ClientOptions, inboxId: String? = nil
)
async throws -> Client
{
Expand All @@ -176,18 +183,16 @@ public final class Client {
accountAddress: accountAddress,
options: options,
signingKey: nil,
inboxId: resolvedInboxId,
apiClient: apiClient
inboxId: resolvedInboxId
)
}

private static func initFFiClient(
accountAddress: String,
options: ClientOptions,
signingKey: SigningKey?,
inboxId: String,
apiClient: XmtpApiClient? = nil
) async throws -> (FfiXmtpClient, String, XmtpApiClient) {
inboxId: String
) async throws -> (FfiXmtpClient, String) {
let address = accountAddress.lowercased()

let mlsDbDirectory = options.dbDirectory
Expand All @@ -214,15 +219,8 @@ public final class Client {
let alias = "xmtp-\(options.api.env.rawValue)-\(inboxId).db3"
let dbURL = directoryURL.appendingPathComponent(alias).path

let xmtpApiClient: XmtpApiClient
if let existingApiClient = apiClient {
xmtpApiClient = existingApiClient
} else {
xmtpApiClient = try await connectToApiBackend(api: options.api)
}

let ffiClient = try await LibXMTP.createClient(
api: xmtpApiClient,
api: connectToApiBackend(api: options.api),
db: dbURL,
encryptionKey: options.dbEncryptionKey,
inboxId: inboxId,
Expand Down Expand Up @@ -252,7 +250,7 @@ public final class Client {
}
}

return (ffiClient, dbURL, xmtpApiClient)
return (ffiClient, dbURL)
}

private static func handleSignature(
Expand Down Expand Up @@ -282,12 +280,19 @@ public final class Client {
}
}

public static func connectToApiBackend(
api: ClientOptions.Api
) async throws -> XmtpApiClient {
return try await connectToBackend(
host: api.env.url,
isSecure: api.env.isSecure == true)
public static func connectToApiBackend(api: ClientOptions.Api) async throws
-> XmtpApiClient
{
let cacheKey = api.env.url

if let cachedClient = await apiCache.getClient(forKey: cacheKey) {
return cachedClient
}

let apiClient = try await connectToBackend(
host: api.env.url, isSecure: api.isSecure)
await apiCache.setClient(apiClient, forKey: cacheKey)
return apiClient
}

public static func getOrCreateInboxId(
Expand All @@ -297,8 +302,7 @@ public final class Client {
do {
inboxId =
try await getInboxIdForAddress(
host: api.env.url,
isSecure: api.env.isSecure == true,
api: connectToApiBackend(api: api),
accountAddress: address.lowercased()
)
?? generateInboxId(
Expand Down Expand Up @@ -344,16 +348,14 @@ public final class Client {

init(
address: String, ffiClient: LibXMTP.FfiXmtpClient, dbPath: String,
installationID: String, inboxID: String, environment: XMTPEnvironment,
apiClient: XmtpApiClient
installationID: String, inboxID: String, environment: XMTPEnvironment
) throws {
self.address = address
self.ffiClient = ffiClient
self.dbPath = dbPath
self.installationID = installationID
self.inboxID = inboxID
self.environment = environment
self.apiClient = apiClient
}

public func addAccount(newAccount: SigningKey)
Expand Down
25 changes: 6 additions & 19 deletions Tests/XMTPTests/ClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -532,19 +532,18 @@ class ClientTests: XCTestCase {
print("PERF: Built a client with inboxId in \(time3)s")

// Measure time to build a client with an inboxId and apiClient
try await Client.connectToApiBackend(api: ClientOptions.Api(env: .dev, isSecure: true))
let start4 = Date()
let buildClient3 = try await Client.build(
address: fakeWallet.address,
try await Client.create(
account: fakeWallet,
options: ClientOptions(
api: ClientOptions.Api(env: .dev, isSecure: true),
dbEncryptionKey: key
),
inboxId: client.inboxID,
apiClient: client.apiClient
)
)
let end4 = Date()
let time4 = end4.timeIntervalSince(start4)
print("PERF: Built a client with inboxId and apiClient in \(time4)s")
print("PERF: Create a client with prebuild in \(time4)s")

// Assert performance comparisons
XCTAssertTrue(
Expand All @@ -560,15 +559,7 @@ class ClientTests: XCTestCase {
)
XCTAssertTrue(
time4 < time1,
"Building a client with apiClient should be faster than creating one."
)
XCTAssertTrue(
time4 < time2,
"Building a client with apiClient should be faster than building one."
)
XCTAssertTrue(
time4 < time2,
"Building a client with apiClient should be faster than building one with inboxId."
"Creating a client with apiClient should be faster than creating one without."
)

// Assert that inbox IDs match
Expand All @@ -580,10 +571,6 @@ class ClientTests: XCTestCase {
client.inboxID, buildClient2.inboxID,
"Inbox ID of the created client and second built client should match."
)
XCTAssertEqual(
client.inboxID, buildClient3.inboxID,
"Inbox ID of the created client and second built client should match."
)
}

}
4 changes: 2 additions & 2 deletions XMTP.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "XMTP"
spec.version = "3.0.19"
spec.version = "3.0.20"

spec.summary = "XMTP SDK Cocoapod"

Expand All @@ -23,7 +23,7 @@ Pod::Spec.new do |spec|

spec.dependency 'CSecp256k1', '~> 0.2'
spec.dependency "Connect-Swift", "= 1.0.0"
spec.dependency 'LibXMTP', '= 3.0.13'
spec.dependency 'LibXMTP', '= 3.0.14'
spec.dependency 'CryptoSwift', '= 1.8.3'
spec.dependency 'SQLCipher', '= 4.5.7'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/xmtp/libxmtp-swift.git",
"state" : {
"revision" : "203fd6d67bb72e3114b273ce9bbddd6fc747d583",
"version" : "3.0.13"
"revision" : "9cf94acdea7d03008b1f130a9848c38ee6b711de",
"version" : "3.0.14"
}
},
{
Expand Down
Loading