Skip to content
Open
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
13 changes: 8 additions & 5 deletions Sources/XMTPiOS/Client.swift
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public enum ClientError: Error, CustomStringConvertible, LocalizedError {
case creationError(String)
case missingInboxId
case invalidInboxId(String)
case clientDeallocated

public var description: String {
switch self {
Expand All @@ -18,6 +19,8 @@ public enum ClientError: Error, CustomStringConvertible, LocalizedError {
case let .invalidInboxId(inboxId):
return
"Invalid inboxId: \(inboxId). Inbox IDs cannot start with '0x'."
case .clientDeallocated:
return "ClientError.clientDeallocated: The Client has been deallocated."
}
}

Expand Down Expand Up @@ -154,23 +157,23 @@ struct ApiCacheKey {
}

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

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

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

func getSyncClient(forKey key: String) -> XmtpApiClient? {
syncApiClientCache[key]
}

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

Expand All @@ -192,11 +195,11 @@ public final class Client {
)

public lazy var preferences: PrivatePreferences = .init(
client: self, ffiClient: ffiClient
ffiClient: ffiClient
)

public lazy var debugInformation: XMTPDebugInformation = .init(
client: self, ffiClient: ffiClient
historySyncUrl: environment.getHistorySyncUrl(), ffiClient: ffiClient
)

static var codecRegistry = CodecRegistry()
Expand Down
31 changes: 28 additions & 3 deletions Sources/XMTPiOS/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ actor FfiStreamActor {

/// Handles listing and creating Conversations.
public class Conversations {
var client: Client
private weak var client: Client?
var ffiConversations: FfiConversations
var ffiClient: FfiXmtpClient

Expand All @@ -136,6 +136,13 @@ public class Conversations {
self.ffiClient = ffiClient
}

private func requireClient() throws -> Client {
guard let client = client else {
throw ClientError.clientDeallocated
}
return client
}

/// Helper function to convert DisappearingMessageSettings to FfiMessageDisappearingSettings
/// Returns nil if the input is nil, making it explicit that nil will be passed to FFI
private func toFfiDisappearingMessageSettings(_ settings: DisappearingMessageSettings?)
Expand All @@ -149,6 +156,7 @@ public class Conversations {
}

public func findGroup(groupId: String) throws -> Group? {
let client = try requireClient()
do {
return try Group(
ffiGroup: ffiClient.conversation(
Expand All @@ -164,6 +172,7 @@ public class Conversations {
public func findConversation(conversationId: String) async throws
-> Conversation?
{
let client = try requireClient()
do {
let conversation = try ffiClient.conversation(
conversationId: conversationId.hexToData
Expand All @@ -177,6 +186,7 @@ public class Conversations {
public func findConversationByTopic(topic: String) async throws
-> Conversation?
{
let client = try requireClient()
do {
let regexPattern = #"/xmtp/mls/1/g-(.*?)/proto"#
if let regex = try? NSRegularExpression(pattern: regexPattern) {
Expand All @@ -200,6 +210,7 @@ public class Conversations {
}

public func findDmByInboxId(inboxId: InboxId) throws -> Dm? {
let client = try requireClient()
do {
let conversation = try ffiClient.dmConversation(
targetInboxId: inboxId
Expand All @@ -215,6 +226,7 @@ public class Conversations {
public func findDmByIdentity(publicIdentity: PublicIdentity) async throws
-> Dm?
{
let client = try requireClient()
guard
let inboxId = try await client.inboxIdFromIdentity(
identity: publicIdentity
Expand Down Expand Up @@ -288,6 +300,7 @@ public class Conversations {
if let limit {
options.limit = Int64(limit)
}
let client = try requireClient()
let conversations = try ffiConversations.listGroups(
opts: options
)
Expand Down Expand Up @@ -321,6 +334,7 @@ public class Conversations {
options.limit = Int64(limit)
}

let client = try requireClient()
let conversations = try ffiConversations.listDms(
opts: options
)
Expand Down Expand Up @@ -353,6 +367,7 @@ public class Conversations {
if let limit {
options.limit = Int64(limit)
}
let client = try requireClient()
let ffiConversations = try ffiConversations.list(
opts: options
)
Expand All @@ -373,6 +388,10 @@ public class Conversations {
Conversation, Error
> {
AsyncThrowingStream { continuation in
guard let client = self.client else {
continuation.finish(throwing: ClientError.clientDeallocated)
return
}
let ffiStreamActor = FfiStreamActor()
let conversationCallback = ConversationStreamCallback {
conversation in
Expand All @@ -387,14 +406,14 @@ public class Conversations {
if conversationType == .dm {
continuation.yield(
Conversation.dm(
conversation.dmFromFFI(client: self.client)
conversation.dmFromFFI(client: client)
)
)
} else if conversationType == .group {
continuation.yield(
Conversation.group(
conversation.groupFromFFI(
client: self.client
client: client
)
)
)
Expand Down Expand Up @@ -456,6 +475,7 @@ public class Conversations {
with peerIdentity: PublicIdentity,
disappearingMessageSettings: DisappearingMessageSettings? = nil
) async throws -> Dm {
let client = try requireClient()
if try await client.inboxState(refreshFromNetwork: false).identities
.map(\.identifier).contains(peerIdentity.identifier)
{
Expand Down Expand Up @@ -493,6 +513,7 @@ public class Conversations {
)
async throws -> Dm
{
let client = try requireClient()
if peerInboxId == client.inboxID {
throw ConversationError.memberCannotBeSelf
}
Expand Down Expand Up @@ -567,6 +588,7 @@ public class Conversations {
disappearingMessageSettings: DisappearingMessageSettings? = nil,
appData: String?
) async throws -> Group {
let client = try requireClient()
let group = try await ffiConversations.createGroup(
accountIdentities: identities.map(\.ffiPrivate),
opts: FfiCreateGroupOptions(
Expand Down Expand Up @@ -641,6 +663,7 @@ public class Conversations {
disappearingMessageSettings: DisappearingMessageSettings? = nil,
appData: String?
) async throws -> Group {
let client = try requireClient()
try validateInboxIds(inboxIds)
let group = try await ffiConversations.createGroupWithInboxIds(
inboxIds: inboxIds,
Expand All @@ -667,6 +690,7 @@ public class Conversations {
disappearingMessageSettings: DisappearingMessageSettings? = nil,
appData: String? = nil
) throws -> Group {
let client = try requireClient()
let ffiOpts = FfiCreateGroupOptions(
permissions:
GroupPermissionPreconfiguration.toFfiGroupPermissionOptions(
Expand Down Expand Up @@ -786,6 +810,7 @@ public class Conversations {
public func fromWelcome(envelopeBytes: Data) async throws
-> Conversation?
{
let client = try requireClient()
let conversations =
try await ffiConversations
.processStreamedWelcomeMessage(envelopeBytes: envelopeBytes)
Expand Down
11 changes: 8 additions & 3 deletions Sources/XMTPiOS/Libxmtp/XMTPDebugInformation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import Foundation

public class XMTPDebugInformation {
private let client: Client
private let historySyncUrl: String
private let ffiClient: FfiXmtpClient

public init(client: Client, ffiClient: FfiXmtpClient) {
self.client = client
public init(historySyncUrl: String, ffiClient: FfiXmtpClient) {
self.historySyncUrl = historySyncUrl
self.ffiClient = ffiClient
}

Expand All @@ -31,6 +31,11 @@ public class XMTPDebugInformation {
public func clearAllStatistics() {
ffiClient.clearAllStatistics()
}

public func uploadDebugInformation(serverUrl: String? = nil) async throws -> String {
let url = serverUrl ?? historySyncUrl
return try await ffiClient.uploadDebugArchive(serverUrl: url)
}
}

public class ApiStats {
Expand Down
74 changes: 36 additions & 38 deletions Sources/XMTPiOS/PrivatePreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,9 @@ public struct ConsentRecord: Codable, Hashable {

/// Provides access to contact bundles.
public actor PrivatePreferences {
var client: Client
var ffiClient: FfiXmtpClient

init(client: Client, ffiClient: FfiXmtpClient) {
self.client = client
init(ffiClient: FfiXmtpClient) {
self.ffiClient = ffiClient
}

Expand Down Expand Up @@ -93,22 +91,24 @@ public actor PrivatePreferences {
AsyncThrowingStream { continuation in
let ffiStreamActor = FfiStreamActor()

let consentCallback = ConsentCallback(client: self.client) {
records in
guard !Task.isCancelled else {
continuation.finish()
Task {
await ffiStreamActor.endStream()
let consentCallback = ConsentCallback(
{ records in
guard !Task.isCancelled else {
continuation.finish()
Task {
await ffiStreamActor.endStream()
}
return
}
return
}
for consent in records {
continuation.yield(consent.fromFfi)
for consent in records {
continuation.yield(consent.fromFfi)
}
},
onClose: {
onClose?()
continuation.finish()
}
} onClose: {
onClose?()
continuation.finish()
}
)

let task = Task {
let stream = await ffiClient.conversations().streamConsent(
Expand All @@ -132,24 +132,26 @@ public actor PrivatePreferences {
AsyncThrowingStream { continuation in
let ffiStreamActor = FfiStreamActor()

let preferenceCallback = PreferenceCallback(client: self.client) {
records in
guard !Task.isCancelled else {
continuation.finish()
Task {
await ffiStreamActor.endStream()
let preferenceCallback = PreferenceCallback(
{ records in
guard !Task.isCancelled else {
continuation.finish()
Task {
await ffiStreamActor.endStream()
}
return
}
return
}
for preference in records {
if case let .hmac(key) = preference {
continuation.yield(.hmac_keys)
for preference in records {
if case let .hmac(key) = preference {
continuation.yield(.hmac_keys)
}
}
},
onClose: {
onClose?()
continuation.finish()
}
} onClose: {
onClose?()
continuation.finish()
}
)

let task = Task {
let stream = await ffiClient.conversations().streamPreferences(
Expand All @@ -169,15 +171,13 @@ public actor PrivatePreferences {
}

final class ConsentCallback: FfiConsentCallback {
let client: Client
let callback: ([FfiConsent]) -> Void
let onCloseCallback: () -> Void

init(
client: Client, _ callback: @escaping ([FfiConsent]) -> Void,
_ callback: @escaping ([FfiConsent]) -> Void,
onClose: @escaping () -> Void
) {
self.client = client
self.callback = callback
onCloseCallback = onClose
}
Expand All @@ -196,15 +196,13 @@ final class ConsentCallback: FfiConsentCallback {
}

final class PreferenceCallback: FfiPreferenceCallback {
let client: Client
let callback: ([FfiPreferenceUpdate]) -> Void
let onCloseCallback: () -> Void

init(
client: Client, _ callback: @escaping ([FfiPreferenceUpdate]) -> Void,
_ callback: @escaping ([FfiPreferenceUpdate]) -> Void,
onClose: @escaping () -> Void
) {
self.client = client
self.callback = callback
onCloseCallback = onClose
}
Expand Down
Loading