From e60533b4a1e724aeb05a0b48adf990c2810d29f7 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Fri, 22 Nov 2024 16:43:04 -0800 Subject: [PATCH] clean up the consent code and add streaming --- Sources/XMTPiOS/Client.swift | 4 - Sources/XMTPiOS/Extensions/Ffi.swift | 16 ++++ Sources/XMTPiOS/PrivatePreferences.swift | 93 ++++++++++++++++-------- 3 files changed, 78 insertions(+), 35 deletions(-) diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 97f9c46e..738b768f 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -474,10 +474,6 @@ public final class Client { try await ffiClient.sendSyncRequest(kind: .messages) } - public func syncConsent() async throws { - try await ffiClient.sendSyncRequest(kind: .consent) - } - public func inboxState(refreshFromNetwork: Bool) async throws -> InboxState { return InboxState( diff --git a/Sources/XMTPiOS/Extensions/Ffi.swift b/Sources/XMTPiOS/Extensions/Ffi.swift index 743a1a4c..7158547f 100644 --- a/Sources/XMTPiOS/Extensions/Ffi.swift +++ b/Sources/XMTPiOS/Extensions/Ffi.swift @@ -45,6 +45,16 @@ extension FfiConsentState { } } +extension FfiConsentEntityType { + var fromFFI: EntryType { + switch self { + case .inboxId: return EntryType.inbox_id + case .address: return EntryType.address + case .conversationId: return EntryType.conversation_id + } + } +} + extension EntryType { var toFFI: FfiConsentEntityType { switch self { @@ -62,3 +72,9 @@ extension ConsentListEntry { ) } } + +extension FfiConsent { + var fromFfi: ConsentListEntry { + ConsentListEntry(value: self.entity, entryType: self.entityType.fromFFI, consentType: self.state.fromFFI) + } +} diff --git a/Sources/XMTPiOS/PrivatePreferences.swift b/Sources/XMTPiOS/PrivatePreferences.swift index 703c54e5..c0509602 100644 --- a/Sources/XMTPiOS/PrivatePreferences.swift +++ b/Sources/XMTPiOS/PrivatePreferences.swift @@ -9,12 +9,13 @@ public enum EntryType: String, Codable { } public struct ConsentListEntry: Codable, Hashable { - public init(value: String, entryType: EntryType, consentType: ConsentState) { + public init(value: String, entryType: EntryType, consentType: ConsentState) + { self.value = value self.entryType = entryType self.consentType = consentType } - + static func address(_ address: String, type: ConsentState = .unknown) -> ConsentListEntry { @@ -25,7 +26,8 @@ public struct ConsentListEntry: Codable, Hashable { conversationId: String, type: ConsentState = ConsentState.unknown ) -> ConsentListEntry { ConsentListEntry( - value: conversationId, entryType: .conversation_id, consentType: type) + value: conversationId, entryType: .conversation_id, + consentType: type) } static func inboxId(_ inboxId: String, type: ConsentState = .unknown) @@ -44,25 +46,8 @@ public struct ConsentListEntry: Codable, Hashable { } } -public enum ContactError: Error { - case invalidIdentifier -} - -public actor EntriesManager { - public var map: [String: ConsentListEntry] = [:] - - func set(_ key: String, _ object: ConsentListEntry) { - map[key] = object - } - - func get(_ key: String) -> ConsentListEntry? { - map[key] - } -} - -public class ConsentList { - public let entriesManager = EntriesManager() - var lastFetched: Date? +/// Provides access to contact bundles. +public actor PrivatePreferences { var client: Client var ffiClient: FfiXmtpClient @@ -82,7 +67,9 @@ public class ConsentList { ).fromFFI } - public func conversationState(conversationId: String) async throws -> ConsentState { + public func conversationState(conversationId: String) async throws + -> ConsentState + { return try await ffiClient.getConsentState( entityType: .conversationId, entity: conversationId @@ -95,17 +82,61 @@ public class ConsentList { entity: inboxId ).fromFFI } + + public func syncConsent() async throws { + try await ffiClient.sendSyncRequest(kind: .consent) + } + + public func streamConsent() + -> AsyncThrowingStream + { + AsyncThrowingStream { continuation in + let ffiStreamActor = FfiStreamActor() + + let consentCallback = ConsentCallback(client: self.client) { + consent in + guard !Task.isCancelled else { + continuation.finish() + Task { + await ffiStreamActor.endStream() + } + return + } + continuation.yield(consent) + } + + let task = Task { + let stream = await ffiClient.conversations().streamConsent( + callback: consentCallback) + await ffiStreamActor.setFfiStream(stream) + } + + continuation.onTermination = { _ in + task.cancel() + Task { + await ffiStreamActor.endStream() + } + } + } + } } -/// Provides access to contact bundles. -public actor PrivatePreferences { - var client: Client - var ffiClient: FfiXmtpClient - public var consentList: ConsentList +final class ConsentCallback: FfiConsentCallback { + let client: Client + let callback: (ConsentListEntry) -> Void - init(client: Client, ffiClient: FfiXmtpClient) { + init(client: Client, _ callback: @escaping (ConsentListEntry) -> Void) { self.client = client - self.ffiClient = ffiClient - consentList = ConsentList(client: client, ffiClient: ffiClient) + self.callback = callback + } + + func onConsentUpdate(consent: [LibXMTP.FfiConsent]) { + for record in consent { + callback(record.fromFfi) + } + } + + func onError(error: LibXMTP.FfiSubscribeError) { + print("Error ConsentCallback \(error)") } }