From 24beaf32de227c526b81378282cae3eedc0bdd8a Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Thu, 8 Sep 2022 14:49:03 +0200 Subject: [PATCH 1/8] Add MessengerRegisterAuthCallbacks unimplemented placeholder --- .../Messenger/Functions/MessengerRegisterAuthCallbacks.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterAuthCallbacks.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterAuthCallbacks.swift index ad184957..3a8b0a5b 100644 --- a/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterAuthCallbacks.swift +++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerRegisterAuthCallbacks.swift @@ -19,6 +19,6 @@ extension MessengerRegisterAuthCallbacks { extension MessengerRegisterAuthCallbacks { public static let unimplemented = MessengerRegisterAuthCallbacks( - run: XCTUnimplemented("\(Self.self)") + run: XCTUnimplemented("\(Self.self)", placeholder: Cancellable {}) ) } -- GitLab From db42327efcf81e520fa5946dac4e8a56958b6bdf Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Thu, 8 Sep 2022 15:17:36 +0200 Subject: [PATCH 2/8] Handle auth requests in HomeFeature --- .../AppFeature/AppEnvironment+Live.swift | 1 + .../Sources/HomeFeature/HomeFeature.swift | 68 +++++++++ .../HomeFeatureTests/HomeFeatureTests.swift | 133 ++++++++++++++++++ 3 files changed, 202 insertions(+) diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift index 61bfba1f..4092af82 100644 --- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift +++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift @@ -55,6 +55,7 @@ extension AppEnvironment { dbManager: dbManager, mainQueue: mainQueue, bgQueue: bgQueue, + now: Date.init, register: { RegisterEnvironment( messenger: messenger, diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift index faa5757c..985ef329 100644 --- a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift +++ b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift @@ -6,8 +6,10 @@ import ContactsFeature import Foundation import RegisterFeature import UserSearchFeature +import XCTestDynamicOverlay import XXClient import XXMessengerClient +import XXModels public struct HomeState: Equatable { public init( @@ -47,6 +49,12 @@ public enum HomeAction: Equatable { case failure(NSError) } + public enum AuthCallbacks: Equatable { + case register + case unregister + case handle(XXClient.AuthCallbacks.Callback) + } + public enum NetworkMonitor: Equatable { case start case stop @@ -62,6 +70,7 @@ public enum HomeAction: Equatable { } case messenger(Messenger) + case authCallbacks(AuthCallbacks) case networkMonitor(NetworkMonitor) case deleteAccount(DeleteAccount) case didDismissAlert @@ -81,6 +90,7 @@ public struct HomeEnvironment { dbManager: DBManager, mainQueue: AnySchedulerOf<DispatchQueue>, bgQueue: AnySchedulerOf<DispatchQueue>, + now: @escaping () -> Date, register: @escaping () -> RegisterEnvironment, contacts: @escaping () -> ContactsEnvironment, userSearch: @escaping () -> UserSearchEnvironment @@ -89,6 +99,7 @@ public struct HomeEnvironment { self.dbManager = dbManager self.mainQueue = mainQueue self.bgQueue = bgQueue + self.now = now self.register = register self.contacts = contacts self.userSearch = userSearch @@ -98,6 +109,7 @@ public struct HomeEnvironment { public var dbManager: DBManager public var mainQueue: AnySchedulerOf<DispatchQueue> public var bgQueue: AnySchedulerOf<DispatchQueue> + public var now: () -> Date public var register: () -> RegisterEnvironment public var contacts: () -> ContactsEnvironment public var userSearch: () -> UserSearchEnvironment @@ -109,6 +121,7 @@ extension HomeEnvironment { dbManager: .unimplemented, mainQueue: .unimplemented, bgQueue: .unimplemented, + now: XCTUnimplemented("\(Self.self).now", placeholder: Date()), register: { .unimplemented }, contacts: { .unimplemented }, userSearch: { .unimplemented } @@ -119,10 +132,12 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment> { state, action, env in enum NetworkHealthEffectId {} enum NetworkNodesEffectId {} + enum AuthCallbacksEffectId {} switch action { case .messenger(.start): return .merge( + Effect(value: .authCallbacks(.register)), Effect(value: .networkMonitor(.stop)), Effect.result { do { @@ -160,6 +175,59 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment> state.failure = error.localizedDescription return .none + case .authCallbacks(.register): + return Effect.run { subscriber in + let handler = AuthCallbacks { callback in + subscriber.send(.authCallbacks(.handle(callback))) + } + let cancellable = env.messenger.registerAuthCallbacks(handler) + return AnyCancellable { cancellable.cancel() } + } + .subscribe(on: env.bgQueue) + .receive(on: env.mainQueue) + .eraseToEffect() + .cancellable(id: AuthCallbacksEffectId.self, cancelInFlight: true) + + case .authCallbacks(.unregister): + return .cancel(id: AuthCallbacksEffectId.self) + + case .authCallbacks(.handle(.request(let contact, _, _, _))): + return .fireAndForget { + let db = try env.dbManager.getDB() + let contactId = try contact.getId() + guard try db.fetchContacts(.init(id: [contactId])).isEmpty else { + return + } + var dbContact = XXModels.Contact(id: contactId) + dbContact.marshaled = contact.data + dbContact.username = try contact.getFact(.username)?.value + dbContact.email = try contact.getFact(.email)?.value + dbContact.phone = try contact.getFact(.phone)?.value + dbContact.authStatus = .verificationInProgress + dbContact.createdAt = env.now() + dbContact = try db.saveContact(dbContact) + } + .subscribe(on: env.bgQueue) + .receive(on: env.mainQueue) + .eraseToEffect() + + case .authCallbacks(.handle(.confirm(let contact, _, _, _))): + return .fireAndForget { + let db = try env.dbManager.getDB() + let contactId = try contact.getId() + guard var dbContact = try db.fetchContacts(.init(id: [contactId])).first else { + return + } + dbContact.authStatus = .friend + dbContact = try db.saveContact(dbContact) + } + .subscribe(on: env.bgQueue) + .receive(on: env.mainQueue) + .eraseToEffect() + + case .authCallbacks(.handle(.reset(let contact, _, _, _))): + return .none + case .networkMonitor(.start): return .merge( Effect.run { subscriber in diff --git a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift index 89aef4c9..40cd5a2a 100644 --- a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift +++ b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift @@ -21,6 +21,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) } store.environment.messenger.isConnected.run = { false } store.environment.messenger.connect.run = { messengerDidConnect += 1 } @@ -32,10 +33,13 @@ final class HomeFeatureTests: XCTestCase { XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000]) XCTAssertNoDifference(messengerDidConnect, 1) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.didStartUnregistered)) { $0.register = RegisterState() } + + store.send(.authCallbacks(.unregister)) } func testMessengerStartRegistered() { @@ -51,6 +55,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) } store.environment.messenger.isConnected.run = { false } store.environment.messenger.connect.run = { messengerDidConnect += 1 } @@ -73,11 +78,14 @@ final class HomeFeatureTests: XCTestCase { XCTAssertNoDifference(messengerDidConnect, 1) XCTAssertNoDifference(messengerDidLogIn, 1) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.didStartRegistered)) store.receive(.networkMonitor(.start)) store.send(.networkMonitor(.stop)) + + store.send(.authCallbacks(.unregister)) } func testRegisterFinished() { @@ -94,6 +102,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) } store.environment.messenger.isConnected.run = { true } store.environment.messenger.isLoggedIn.run = { false } @@ -118,11 +127,14 @@ final class HomeFeatureTests: XCTestCase { XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000]) XCTAssertNoDifference(messengerDidLogIn, 1) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.didStartRegistered)) store.receive(.networkMonitor(.start)) store.send(.networkMonitor(.stop)) + + store.send(.authCallbacks(.unregister)) } func testMessengerStartFailure() { @@ -137,14 +149,18 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in throw error } store.send(.messenger(.start)) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } + + store.send(.authCallbacks(.unregister)) } func testMessengerStartConnectFailure() { @@ -159,16 +175,20 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in } store.environment.messenger.isConnected.run = { false } store.environment.messenger.connect.run = { throw error } store.send(.messenger(.start)) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } + + store.send(.authCallbacks(.unregister)) } func testMessengerStartIsRegisteredFailure() { @@ -183,6 +203,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in } store.environment.messenger.isConnected.run = { true } store.environment.messenger.isLoggedIn.run = { false } @@ -190,10 +211,13 @@ final class HomeFeatureTests: XCTestCase { store.send(.messenger(.start)) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } + + store.send(.authCallbacks(.unregister)) } func testMessengerStartLogInFailure() { @@ -208,6 +232,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate + store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in } store.environment.messenger.isConnected.run = { true } store.environment.messenger.isLoggedIn.run = { false } @@ -216,10 +241,13 @@ final class HomeFeatureTests: XCTestCase { store.send(.messenger(.start)) + store.receive(.authCallbacks(.register)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } + + store.send(.authCallbacks(.unregister)) } func testNetworkMonitorStart() { @@ -491,4 +519,109 @@ final class HomeFeatureTests: XCTestCase { $0.contacts = nil } } + + func testAuthCallbacks() { + let store = TestStore( + initialState: HomeState(), + reducer: homeReducer, + environment: .unimplemented + ) + + let now = Date() + var didRegisterCallbacks: [AuthCallbacks] = [] + var didCancelAuthCallbacks = 0 + var dbContact: XXModels.Contact? + var dbDidSaveContact: [XXModels.Contact] = [] + + store.environment.mainQueue = .immediate + store.environment.bgQueue = .immediate + store.environment.now = { now } + store.environment.messenger.registerAuthCallbacks.run = { callbacks in + didRegisterCallbacks.append(callbacks) + return Cancellable { didCancelAuthCallbacks += 1 } + } + store.environment.dbManager.getDB.run = { + var db: Database = .failing + db.fetchContacts.run = { _ in [dbContact].compactMap { $0 } } + db.saveContact.run = { contact in + dbDidSaveContact.append(contact) + return contact + } + return db + } + + store.send(.authCallbacks(.register)) + + XCTAssertNoDifference(didRegisterCallbacks.count, 1) + + var contact = XXClient.Contact.unimplemented("data".data(using: .utf8)!) + contact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + contact.getFactsFromContact.run = { _ in + [ + Fact(type: .username, value: "username"), + Fact(type: .email, value: "email"), + Fact(type: .phone, value: "phone"), + ] + } + + dbContact = nil + dbDidSaveContact = [] + didRegisterCallbacks.first?.handle( + .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + store.receive(.authCallbacks(.handle( + .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ))) + XCTAssertNoDifference(dbDidSaveContact, [.init( + id: "id".data(using: .utf8)!, + marshaled: "data".data(using: .utf8)!, + username: "username", + email: "email", + phone: "phone", + authStatus: .verificationInProgress, + createdAt: now + )]) + + dbContact = .init(id: "id".data(using: .utf8)!) + dbDidSaveContact = [] + didRegisterCallbacks.first?.handle( + .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + store.receive(.authCallbacks(.handle( + .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ))) + XCTAssertNoDifference(dbDidSaveContact, []) + + dbContact = .init(id: "id".data(using: .utf8)!) + dbDidSaveContact = [] + didRegisterCallbacks.first?.handle( + .confirm(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + store.receive(.authCallbacks(.handle( + .confirm(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ))) + XCTAssertNoDifference(dbDidSaveContact, [.init( + id: "id".data(using: .utf8)!, + authStatus: .friend, + createdAt: dbContact!.createdAt + )]) + + dbContact = nil + dbDidSaveContact = [] + didRegisterCallbacks.first?.handle( + .reset(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + store.receive(.authCallbacks(.handle( + .reset(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) + ))) + XCTAssertNoDifference(dbDidSaveContact, []) + + store.send(.authCallbacks(.unregister)) + + XCTAssertNoDifference(didCancelAuthCallbacks, 1) + } } -- GitLab From 1b94869c21e941e57ba634fdfb715535e9ac6644 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Fri, 9 Sep 2022 12:35:29 +0200 Subject: [PATCH 3/8] Add AuthCallbackHandler --- Examples/xx-messenger/Package.swift | 1 + .../AuthCallbackHandler.swift | 49 ++++++++ .../AuthCallbackHandlerConfirm.swift | 31 +++++ .../AuthCallbackHandlerRequest.swift | 40 ++++++ .../AuthCallbackHandlerReset.swift | 31 +++++ .../AuthCallbackHandlerConfirmTests.swift | 54 +++++++++ .../AuthCallbackHandlerRequestTests.swift | 67 ++++++++++ .../AuthCallbackHandlerResetTests.swift | 54 +++++++++ .../AuthCallbackHandlerTests.swift | 114 ++++++++++++++++++ 9 files changed, 441 insertions(+) create mode 100644 Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandler.swift create mode 100644 Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerConfirm.swift create mode 100644 Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift create mode 100644 Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerReset.swift create mode 100644 Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerConfirmTests.swift create mode 100644 Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift create mode 100644 Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerResetTests.swift create mode 100644 Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerTests.swift diff --git a/Examples/xx-messenger/Package.swift b/Examples/xx-messenger/Package.swift index 70066bd2..57081f3e 100644 --- a/Examples/xx-messenger/Package.swift +++ b/Examples/xx-messenger/Package.swift @@ -57,6 +57,7 @@ let package = Package( .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"), .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), .product(name: "XXDatabase", package: "client-ios-db"), + .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), .product(name: "XXModels", package: "client-ios-db"), ], swiftSettings: swiftSettings diff --git a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandler.swift b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandler.swift new file mode 100644 index 00000000..c6e03cbe --- /dev/null +++ b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandler.swift @@ -0,0 +1,49 @@ +import Foundation +import XCTestDynamicOverlay +import XXClient +import XXMessengerClient +import XXModels + +public struct AuthCallbackHandler { + public typealias OnError = (Error) -> Void + + public var run: (@escaping OnError) -> Cancellable + + public func callAsFunction(onError: @escaping OnError) -> Cancellable { + run(onError) + } +} + +extension AuthCallbackHandler { + public static func live( + messenger: Messenger, + handleRequest: AuthCallbackHandlerRequest, + handleConfirm: AuthCallbackHandlerConfirm, + handleReset: AuthCallbackHandlerReset + ) -> AuthCallbackHandler { + AuthCallbackHandler { onError in + messenger.registerAuthCallbacks(.init { callback in + do { + switch callback { + case .request(let contact, _, _, _): + try handleRequest(contact) + + case .confirm(let contact, _, _, _): + try handleConfirm(contact) + + case .reset(let contact, _, _, _): + try handleReset(contact) + } + } catch { + onError(error) + } + }) + } + } +} + +extension AuthCallbackHandler { + public static let unimplemented = AuthCallbackHandler( + run: XCTUnimplemented("\(Self.self)", placeholder: Cancellable {}) + ) +} diff --git a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerConfirm.swift b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerConfirm.swift new file mode 100644 index 00000000..2aa6787f --- /dev/null +++ b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerConfirm.swift @@ -0,0 +1,31 @@ +import Foundation +import XCTestDynamicOverlay +import XXClient +import XXModels + +public struct AuthCallbackHandlerConfirm { + public var run: (XXClient.Contact) throws -> Void + + public func callAsFunction(_ contact: XXClient.Contact) throws { + try run(contact) + } +} + +extension AuthCallbackHandlerConfirm { + public static func live(db: DBManagerGetDB) -> AuthCallbackHandlerConfirm { + AuthCallbackHandlerConfirm { xxContact in + let id = try xxContact.getId() + guard var dbContact = try db().fetchContacts(.init(id: [id])).first else { + return + } + dbContact.authStatus = .friend + dbContact = try db().saveContact(dbContact) + } + } +} + +extension AuthCallbackHandlerConfirm { + public static let unimplemented = AuthCallbackHandlerConfirm( + run: XCTUnimplemented("\(Self.self)") + ) +} diff --git a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift new file mode 100644 index 00000000..1ec23923 --- /dev/null +++ b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift @@ -0,0 +1,40 @@ +import Foundation +import XCTestDynamicOverlay +import XXClient +import XXModels + +public struct AuthCallbackHandlerRequest { + public var run: (XXClient.Contact) throws -> Void + + public func callAsFunction(_ contact: XXClient.Contact) throws { + try run(contact) + } +} + +extension AuthCallbackHandlerRequest { + public static func live( + db: DBManagerGetDB, + now: @escaping () -> Date + ) -> AuthCallbackHandlerRequest { + AuthCallbackHandlerRequest { xxContact in + let id = try xxContact.getId() + guard try db().fetchContacts(.init(id: [id])).isEmpty else { + return + } + var dbContact = XXModels.Contact(id: id) + dbContact.marshaled = xxContact.data + dbContact.username = try xxContact.getFact(.username)?.value + dbContact.email = try xxContact.getFact(.email)?.value + dbContact.phone = try xxContact.getFact(.phone)?.value + dbContact.authStatus = .verificationInProgress + dbContact.createdAt = now() + dbContact = try db().saveContact(dbContact) + } + } +} + +extension AuthCallbackHandlerRequest { + public static let unimplemented = AuthCallbackHandlerRequest( + run: XCTUnimplemented("\(Self.self)") + ) +} diff --git a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerReset.swift b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerReset.swift new file mode 100644 index 00000000..729fe13e --- /dev/null +++ b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerReset.swift @@ -0,0 +1,31 @@ +import Foundation +import XCTestDynamicOverlay +import XXClient +import XXModels + +public struct AuthCallbackHandlerReset { + public var run: (XXClient.Contact) throws -> Void + + public func callAsFunction(_ contact: XXClient.Contact) throws { + try run(contact) + } +} + +extension AuthCallbackHandlerReset { + public static func live(db: DBManagerGetDB) -> AuthCallbackHandlerReset { + AuthCallbackHandlerReset { xxContact in + let id = try xxContact.getId() + guard var dbContact = try db().fetchContacts(.init(id: [id])).first else { + return + } + dbContact.authStatus = .stranger + dbContact = try db().saveContact(dbContact) + } + } +} + +extension AuthCallbackHandlerReset { + public static let unimplemented = AuthCallbackHandlerReset( + run: XCTUnimplemented("\(Self.self)") + ) +} diff --git a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerConfirmTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerConfirmTests.swift new file mode 100644 index 00000000..1a1b5f19 --- /dev/null +++ b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerConfirmTests.swift @@ -0,0 +1,54 @@ +import CustomDump +import XCTest +import XXModels +import XXClient +@testable import AppCore + +final class AuthCallbackHandlerConfirmTests: XCTestCase { + func testConfirm() throws { + var didFetchContacts: [XXModels.Contact.Query] = [] + var didSaveContact: [XXModels.Contact] = [] + + let dbContact = XXModels.Contact( + id: "id".data(using: .utf8)!, + authStatus: .requested + ) + let confirm = AuthCallbackHandlerConfirm.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { query in + didFetchContacts.append(query) + return [dbContact] + } + db.saveContact.run = { contact in + didSaveContact.append(contact) + return contact + } + return db + } + ) + var xxContact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + xxContact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + + try confirm(xxContact) + + XCTAssertNoDifference(didFetchContacts, [.init(id: ["id".data(using: .utf8)!])]) + var expectedSavedContact = dbContact + expectedSavedContact.authStatus = .friend + XCTAssertNoDifference(didSaveContact, [expectedSavedContact]) + } + + func testConfirmWhenContactNotInDatabase() throws { + let confirm = AuthCallbackHandlerConfirm.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { _ in [] } + return db + } + ) + var contact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + contact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + + try confirm(contact) + } +} diff --git a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift new file mode 100644 index 00000000..fb92a5b8 --- /dev/null +++ b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift @@ -0,0 +1,67 @@ +import CustomDump +import XCTest +import XXModels +import XXClient +import XCTestDynamicOverlay +@testable import AppCore + +final class AuthCallbackHandlerRequestTests: XCTestCase { + func testRequestFromNewContact() throws { + let now = Date() + var didFetchContacts: [XXModels.Contact.Query] = [] + var didSaveContact: [XXModels.Contact] = [] + + let request = AuthCallbackHandlerRequest.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { query in + didFetchContacts.append(query) + return [] + } + db.saveContact.run = { contact in + didSaveContact.append(contact) + return contact + } + return db + }, + now: { now } + ) + var xxContact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + xxContact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + xxContact.getFactsFromContact.run = { _ in + [ + Fact(type: .username, value: "username"), + Fact(type: .email, value: "email"), + Fact(type: .phone, value: "phone"), + ] + } + + try request(xxContact) + + XCTAssertNoDifference(didFetchContacts, [.init(id: ["id".data(using: .utf8)!])]) + XCTAssertNoDifference(didSaveContact, [.init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + username: "username", + email: "email", + phone: "phone", + authStatus: .verificationInProgress, + createdAt: now + )]) + } + + func testRequestWhenContactInDatabase() throws { + let request = AuthCallbackHandlerRequest.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { _ in [.init(id: "id".data(using: .utf8)!)] } + return db + }, + now: XCTUnimplemented("now", placeholder: Date()) + ) + var contact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + contact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + + try request(contact) + } +} diff --git a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerResetTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerResetTests.swift new file mode 100644 index 00000000..9a4407bf --- /dev/null +++ b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerResetTests.swift @@ -0,0 +1,54 @@ +import CustomDump +import XCTest +import XXModels +import XXClient +@testable import AppCore + +final class AuthCallbackHandlerResetTests: XCTestCase { + func testReset() throws { + var didFetchContacts: [XXModels.Contact.Query] = [] + var didSaveContact: [XXModels.Contact] = [] + + let dbContact = XXModels.Contact( + id: "id".data(using: .utf8)!, + authStatus: .friend + ) + let reset = AuthCallbackHandlerReset.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { query in + didFetchContacts.append(query) + return [dbContact] + } + db.saveContact.run = { contact in + didSaveContact.append(contact) + return contact + } + return db + } + ) + var xxContact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + xxContact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + + try reset(xxContact) + + XCTAssertNoDifference(didFetchContacts, [.init(id: ["id".data(using: .utf8)!])]) + var expectedSavedContact = dbContact + expectedSavedContact.authStatus = .stranger + XCTAssertNoDifference(didSaveContact, [expectedSavedContact]) + } + + func testResetWhenContactNotInDatabase() throws { + let reset = AuthCallbackHandlerReset.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { _ in [] } + return db + } + ) + var contact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + contact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + + try reset(contact) + } +} diff --git a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerTests.swift new file mode 100644 index 00000000..2eddbbb9 --- /dev/null +++ b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerTests.swift @@ -0,0 +1,114 @@ +import CustomDump +import XCTest +import XXClient +import XXMessengerClient +@testable import AppCore + +final class AuthCallbackHandlerTests: XCTestCase { + func testCallbackHandling() throws { + struct TestState: Equatable { + var didRegisterAuthCallbacks = 0 + var didCancelAuthCallbacks = 0 + var didHandleRequest: [Contact] = [] + var didHandleConfirm: [Contact] = [] + var didHandleReset: [Contact] = [] + } + var registeredAuthCallbacks: [AuthCallbacks] = [] + var state = TestState() + var expectedState = state + + var messenger: Messenger = .unimplemented + messenger.registerAuthCallbacks.run = { callbacks in + state.didRegisterAuthCallbacks += 1 + registeredAuthCallbacks.append(callbacks) + return Cancellable { state.didCancelAuthCallbacks += 1 } + } + + let handle = AuthCallbackHandler.live( + messenger: messenger, + handleRequest: .init { state.didHandleRequest.append($0) }, + handleConfirm: .init { state.didHandleConfirm.append($0) }, + handleReset: .init { state.didHandleReset.append($0) } + ) + + var cancellable: Any? = handle(onError: { error in + XCTFail("Unexpected error: \(error)") + }) + + expectedState.didRegisterAuthCallbacks += 1 + XCTAssertNoDifference(state, expectedState) + + let contact1 = XXClient.Contact.unimplemented("1".data(using: .utf8)!) + registeredAuthCallbacks.first?.handle( + .request(contact: contact1, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + expectedState.didHandleRequest.append(contact1) + XCTAssertNoDifference(state, expectedState) + + let contact2 = XXClient.Contact.unimplemented("2".data(using: .utf8)!) + registeredAuthCallbacks.first?.handle( + .confirm(contact: contact2, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + expectedState.didHandleConfirm.append(contact2) + XCTAssertNoDifference(state, expectedState) + + let contact3 = XXClient.Contact.unimplemented("3".data(using: .utf8)!) + registeredAuthCallbacks.first?.handle( + .reset(contact: contact3, receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + expectedState.didHandleReset.append(contact3) + XCTAssertNoDifference(state, expectedState) + + cancellable = nil + + expectedState.didCancelAuthCallbacks += 1 + XCTAssertNoDifference(state, expectedState) + + _ = cancellable + } + + func testCallbackHandlingFailure() { + enum Failure: Error, Equatable { + case request + case confirm + case reset + } + var registeredAuthCallbacks: [AuthCallbacks] = [] + var errors: [Error] = [] + + var messenger: Messenger = .unimplemented + messenger.registerAuthCallbacks.run = { callbacks in + registeredAuthCallbacks.append(callbacks) + return Cancellable {} + } + + let handle = AuthCallbackHandler.live( + messenger: messenger, + handleRequest: .init { _ in throw Failure.request }, + handleConfirm: .init { _ in throw Failure.confirm }, + handleReset: .init { _ in throw Failure.reset } + ) + + let cancellable = handle(onError: { errors.append($0) }) + + registeredAuthCallbacks.first?.handle( + .request(contact: .unimplemented(Data()), receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + registeredAuthCallbacks.first?.handle( + .confirm(contact: .unimplemented(Data()), receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + registeredAuthCallbacks.first?.handle( + .reset(contact: .unimplemented(Data()), receptionId: Data(), ephemeralId: 0, roundId: 0) + ) + + XCTAssertNoDifference( + errors.map { $0 as? Failure }, + [.request, .confirm, .reset] + ) + + _ = cancellable + } +} -- GitLab From 0f8d52eb0a2443bebf8ea059217be3f861ccd594 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Fri, 9 Sep 2022 13:00:20 +0200 Subject: [PATCH 4/8] Use AuthCallbackHandler in HomeFeature --- .../AppFeature/AppEnvironment+Live.swift | 8 +- .../Sources/HomeFeature/HomeFeature.swift | 74 +++------ .../Sources/HomeFeature/HomeView.swift | 23 ++- .../HomeFeatureTests/HomeFeatureTests.swift | 149 +++++------------- 4 files changed, 91 insertions(+), 163 deletions(-) diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift index 4092af82..c45c93ef 100644 --- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift +++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift @@ -16,6 +16,12 @@ extension AppEnvironment { let dbManager = DBManager.live() let messengerEnv = MessengerEnvironment.live() let messenger = Messenger.live(messengerEnv) + let authHandler = AuthCallbackHandler.live( + messenger: messenger, + handleRequest: .live(db: dbManager.getDB, now: Date.init), + handleConfirm: .live(db: dbManager.getDB), + handleReset: .live(db: dbManager.getDB) + ) let mainQueue = DispatchQueue.main.eraseToAnyScheduler() let bgQueue = DispatchQueue.global(qos: .background).eraseToAnyScheduler() @@ -53,9 +59,9 @@ extension AppEnvironment { HomeEnvironment( messenger: messenger, dbManager: dbManager, + authHandler: authHandler, mainQueue: mainQueue, bgQueue: bgQueue, - now: Date.init, register: { RegisterEnvironment( messenger: messenger, diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift index 985ef329..e28008f3 100644 --- a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift +++ b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift @@ -14,6 +14,7 @@ import XXModels public struct HomeState: Equatable { public init( failure: String? = nil, + authFailure: String? = nil, isNetworkHealthy: Bool? = nil, networkNodesReport: NodeRegistrationReport? = nil, isDeletingAccount: Bool = false, @@ -23,6 +24,7 @@ public struct HomeState: Equatable { userSearch: UserSearchState? = nil ) { self.failure = failure + self.authFailure = authFailure self.isNetworkHealthy = isNetworkHealthy self.isDeletingAccount = isDeletingAccount self.alert = alert @@ -32,6 +34,7 @@ public struct HomeState: Equatable { } public var failure: String? + public var authFailure: String? public var isNetworkHealthy: Bool? public var networkNodesReport: NodeRegistrationReport? public var isDeletingAccount: Bool @@ -49,10 +52,11 @@ public enum HomeAction: Equatable { case failure(NSError) } - public enum AuthCallbacks: Equatable { - case register - case unregister - case handle(XXClient.AuthCallbacks.Callback) + public enum AuthHandler: Equatable { + case start + case stop + case failure(NSError) + case failureDismissed } public enum NetworkMonitor: Equatable { @@ -70,7 +74,7 @@ public enum HomeAction: Equatable { } case messenger(Messenger) - case authCallbacks(AuthCallbacks) + case authHandler(AuthHandler) case networkMonitor(NetworkMonitor) case deleteAccount(DeleteAccount) case didDismissAlert @@ -88,18 +92,18 @@ public struct HomeEnvironment { public init( messenger: Messenger, dbManager: DBManager, + authHandler: AuthCallbackHandler, mainQueue: AnySchedulerOf<DispatchQueue>, bgQueue: AnySchedulerOf<DispatchQueue>, - now: @escaping () -> Date, register: @escaping () -> RegisterEnvironment, contacts: @escaping () -> ContactsEnvironment, userSearch: @escaping () -> UserSearchEnvironment ) { self.messenger = messenger self.dbManager = dbManager + self.authHandler = authHandler self.mainQueue = mainQueue self.bgQueue = bgQueue - self.now = now self.register = register self.contacts = contacts self.userSearch = userSearch @@ -107,9 +111,9 @@ public struct HomeEnvironment { public var messenger: Messenger public var dbManager: DBManager + public var authHandler: AuthCallbackHandler public var mainQueue: AnySchedulerOf<DispatchQueue> public var bgQueue: AnySchedulerOf<DispatchQueue> - public var now: () -> Date public var register: () -> RegisterEnvironment public var contacts: () -> ContactsEnvironment public var userSearch: () -> UserSearchEnvironment @@ -119,9 +123,9 @@ extension HomeEnvironment { public static let unimplemented = HomeEnvironment( messenger: .unimplemented, dbManager: .unimplemented, + authHandler: .unimplemented, mainQueue: .unimplemented, bgQueue: .unimplemented, - now: XCTUnimplemented("\(Self.self).now", placeholder: Date()), register: { .unimplemented }, contacts: { .unimplemented }, userSearch: { .unimplemented } @@ -137,7 +141,7 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment> switch action { case .messenger(.start): return .merge( - Effect(value: .authCallbacks(.register)), + Effect(value: .authHandler(.start)), Effect(value: .networkMonitor(.stop)), Effect.result { do { @@ -175,12 +179,11 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment> state.failure = error.localizedDescription return .none - case .authCallbacks(.register): + case .authHandler(.start): return Effect.run { subscriber in - let handler = AuthCallbacks { callback in - subscriber.send(.authCallbacks(.handle(callback))) - } - let cancellable = env.messenger.registerAuthCallbacks(handler) + let cancellable = env.authHandler(onError: { error in + subscriber.send(.authHandler(.failure(error as NSError))) + }) return AnyCancellable { cancellable.cancel() } } .subscribe(on: env.bgQueue) @@ -188,44 +191,15 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment> .eraseToEffect() .cancellable(id: AuthCallbacksEffectId.self, cancelInFlight: true) - case .authCallbacks(.unregister): + case .authHandler(.stop): return .cancel(id: AuthCallbacksEffectId.self) - case .authCallbacks(.handle(.request(let contact, _, _, _))): - return .fireAndForget { - let db = try env.dbManager.getDB() - let contactId = try contact.getId() - guard try db.fetchContacts(.init(id: [contactId])).isEmpty else { - return - } - var dbContact = XXModels.Contact(id: contactId) - dbContact.marshaled = contact.data - dbContact.username = try contact.getFact(.username)?.value - dbContact.email = try contact.getFact(.email)?.value - dbContact.phone = try contact.getFact(.phone)?.value - dbContact.authStatus = .verificationInProgress - dbContact.createdAt = env.now() - dbContact = try db.saveContact(dbContact) - } - .subscribe(on: env.bgQueue) - .receive(on: env.mainQueue) - .eraseToEffect() - - case .authCallbacks(.handle(.confirm(let contact, _, _, _))): - return .fireAndForget { - let db = try env.dbManager.getDB() - let contactId = try contact.getId() - guard var dbContact = try db.fetchContacts(.init(id: [contactId])).first else { - return - } - dbContact.authStatus = .friend - dbContact = try db.saveContact(dbContact) - } - .subscribe(on: env.bgQueue) - .receive(on: env.mainQueue) - .eraseToEffect() + case .authHandler(.failure(let error)): + state.authFailure = error.localizedDescription + return .none - case .authCallbacks(.handle(.reset(let contact, _, _, _))): + case .authHandler(.failureDismissed): + state.authFailure = nil return .none case .networkMonitor(.start): diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift index f1abfb2b..f6a96489 100644 --- a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift +++ b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift @@ -15,12 +15,14 @@ public struct HomeView: View { struct ViewState: Equatable { var failure: String? + var authFailure: String? var isNetworkHealthy: Bool? var networkNodesReport: NodeRegistrationReport? var isDeletingAccount: Bool init(state: HomeState) { failure = state.failure + authFailure = state.authFailure isNetworkHealthy = state.isNetworkHealthy isDeletingAccount = state.isDeletingAccount networkNodesReport = state.networkNodesReport @@ -31,21 +33,32 @@ public struct HomeView: View { WithViewStore(store, observe: ViewState.init) { viewStore in NavigationView { Form { - Section { - if let failure = viewStore.failure { + if let failure = viewStore.failure { + Section { Text(failure) Button { viewStore.send(.messenger(.start)) } label: { Text("Retry") } - } - } header: { - if viewStore.failure != nil { + } header: { Text("Error") } } + if let authFailure = viewStore.authFailure { + Section { + Text(authFailure) + Button { + viewStore.send(.authHandler(.failureDismissed)) + } label: { + Text("Dismiss") + } + } header: { + Text("Auth Error") + } + } + Section { HStack { Text("Health") diff --git a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift index 40cd5a2a..f3e5bcf8 100644 --- a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift +++ b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift @@ -1,3 +1,4 @@ +import AppCore import ComposableArchitecture import ContactsFeature import RegisterFeature @@ -21,7 +22,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) } store.environment.messenger.isConnected.run = { false } store.environment.messenger.connect.run = { messengerDidConnect += 1 } @@ -33,13 +34,13 @@ final class HomeFeatureTests: XCTestCase { XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000]) XCTAssertNoDifference(messengerDidConnect, 1) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.didStartUnregistered)) { $0.register = RegisterState() } - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testMessengerStartRegistered() { @@ -55,7 +56,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) } store.environment.messenger.isConnected.run = { false } store.environment.messenger.connect.run = { messengerDidConnect += 1 } @@ -78,14 +79,13 @@ final class HomeFeatureTests: XCTestCase { XCTAssertNoDifference(messengerDidConnect, 1) XCTAssertNoDifference(messengerDidLogIn, 1) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.didStartRegistered)) store.receive(.networkMonitor(.start)) store.send(.networkMonitor(.stop)) - - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testRegisterFinished() { @@ -102,7 +102,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) } store.environment.messenger.isConnected.run = { true } store.environment.messenger.isLoggedIn.run = { false } @@ -127,14 +127,13 @@ final class HomeFeatureTests: XCTestCase { XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000]) XCTAssertNoDifference(messengerDidLogIn, 1) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.didStartRegistered)) store.receive(.networkMonitor(.start)) store.send(.networkMonitor(.stop)) - - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testMessengerStartFailure() { @@ -149,18 +148,18 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in throw error } store.send(.messenger(.start)) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testMessengerStartConnectFailure() { @@ -175,20 +174,20 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in } store.environment.messenger.isConnected.run = { false } store.environment.messenger.connect.run = { throw error } store.send(.messenger(.start)) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testMessengerStartIsRegisteredFailure() { @@ -203,7 +202,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in } store.environment.messenger.isConnected.run = { true } store.environment.messenger.isLoggedIn.run = { false } @@ -211,13 +210,13 @@ final class HomeFeatureTests: XCTestCase { store.send(.messenger(.start)) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testMessengerStartLogInFailure() { @@ -232,7 +231,7 @@ final class HomeFeatureTests: XCTestCase { store.environment.bgQueue = .immediate store.environment.mainQueue = .immediate - store.environment.messenger.registerAuthCallbacks.run = { _ in Cancellable {} } + store.environment.authHandler.run = { _ in Cancellable {} } store.environment.messenger.start.run = { _ in } store.environment.messenger.isConnected.run = { true } store.environment.messenger.isLoggedIn.run = { false } @@ -241,13 +240,13 @@ final class HomeFeatureTests: XCTestCase { store.send(.messenger(.start)) - store.receive(.authCallbacks(.register)) + store.receive(.authHandler(.start)) store.receive(.networkMonitor(.stop)) store.receive(.messenger(.failure(error as NSError))) { $0.failure = error.localizedDescription } - store.send(.authCallbacks(.unregister)) + store.send(.authHandler(.stop)) } func testNetworkMonitorStart() { @@ -527,101 +526,37 @@ final class HomeFeatureTests: XCTestCase { environment: .unimplemented ) - let now = Date() - var didRegisterCallbacks: [AuthCallbacks] = [] - var didCancelAuthCallbacks = 0 - var dbContact: XXModels.Contact? - var dbDidSaveContact: [XXModels.Contact] = [] + var didRunAuthHandler = 0 + var didCancelAuthHandler = 0 + var authHandlerOnError: [AuthCallbackHandler.OnError] = [] store.environment.mainQueue = .immediate store.environment.bgQueue = .immediate - store.environment.now = { now } - store.environment.messenger.registerAuthCallbacks.run = { callbacks in - didRegisterCallbacks.append(callbacks) - return Cancellable { didCancelAuthCallbacks += 1 } - } - store.environment.dbManager.getDB.run = { - var db: Database = .failing - db.fetchContacts.run = { _ in [dbContact].compactMap { $0 } } - db.saveContact.run = { contact in - dbDidSaveContact.append(contact) - return contact - } - return db - } - - store.send(.authCallbacks(.register)) - - XCTAssertNoDifference(didRegisterCallbacks.count, 1) - - var contact = XXClient.Contact.unimplemented("data".data(using: .utf8)!) - contact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } - contact.getFactsFromContact.run = { _ in - [ - Fact(type: .username, value: "username"), - Fact(type: .email, value: "email"), - Fact(type: .phone, value: "phone"), - ] + store.environment.authHandler.run = { onError in + didRunAuthHandler += 1 + authHandlerOnError.append(onError) + return Cancellable { didCancelAuthHandler += 1 } } - dbContact = nil - dbDidSaveContact = [] - didRegisterCallbacks.first?.handle( - .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ) + store.send(.authHandler(.start)) - store.receive(.authCallbacks(.handle( - .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ))) - XCTAssertNoDifference(dbDidSaveContact, [.init( - id: "id".data(using: .utf8)!, - marshaled: "data".data(using: .utf8)!, - username: "username", - email: "email", - phone: "phone", - authStatus: .verificationInProgress, - createdAt: now - )]) - - dbContact = .init(id: "id".data(using: .utf8)!) - dbDidSaveContact = [] - didRegisterCallbacks.first?.handle( - .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ) + XCTAssertNoDifference(didRunAuthHandler, 1) - store.receive(.authCallbacks(.handle( - .request(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ))) - XCTAssertNoDifference(dbDidSaveContact, []) + struct AuthHandlerError: Error { var id: Int } + authHandlerOnError.first?(AuthHandlerError(id: 1)) - dbContact = .init(id: "id".data(using: .utf8)!) - dbDidSaveContact = [] - didRegisterCallbacks.first?.handle( - .confirm(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ) + store.receive(.authHandler(.failure(AuthHandlerError(id: 1) as NSError))) { + $0.authFailure = AuthHandlerError(id: 1).localizedDescription + } - store.receive(.authCallbacks(.handle( - .confirm(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ))) - XCTAssertNoDifference(dbDidSaveContact, [.init( - id: "id".data(using: .utf8)!, - authStatus: .friend, - createdAt: dbContact!.createdAt - )]) - - dbContact = nil - dbDidSaveContact = [] - didRegisterCallbacks.first?.handle( - .reset(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ) + store.send(.authHandler(.failureDismissed)) { + $0.authFailure = nil + } - store.receive(.authCallbacks(.handle( - .reset(contact: contact, receptionId: Data(), ephemeralId: 0, roundId: 0) - ))) - XCTAssertNoDifference(dbDidSaveContact, []) + store.send(.authHandler(.stop)) - store.send(.authCallbacks(.unregister)) + XCTAssertNoDifference(didCancelAuthHandler, 1) - XCTAssertNoDifference(didCancelAuthCallbacks, 1) + authHandlerOnError.first?(AuthHandlerError(id: 2)) } } -- GitLab From d0006cd916be314faae0381719a6fefa050b1144 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Fri, 9 Sep 2022 13:27:01 +0200 Subject: [PATCH 5/8] Add MessengerVerifyContact function --- .../Functions/MessengerVerifyContact.swift | 25 +++++++++++++++++++ .../Messenger/Messenger.swift | 7 ++++-- .../MessengerVerifyContactTests.swift | 16 ++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functions/MessengerVerifyContactTests.swift diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift new file mode 100644 index 00000000..3d3d40e3 --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift @@ -0,0 +1,25 @@ +import XCTestDynamicOverlay +import XXClient + +public struct MessengerVerifyContact { + public var run: (Contact) throws -> Bool + + public func callAsFunction(_ contact: Contact) throws -> Bool { + try run(contact) + } +} + +extension MessengerVerifyContact { + public static func live(_ env: MessengerEnvironment) -> MessengerVerifyContact { + MessengerVerifyContact { contact in + // TODO: + return false + } + } +} + +extension MessengerVerifyContact { + public static let unimplemented = MessengerVerifyContact( + run: XCTUnimplemented("\(Self.self)") + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift index cc48651c..e2d31f69 100644 --- a/Sources/XXMessengerClient/Messenger/Messenger.swift +++ b/Sources/XXMessengerClient/Messenger/Messenger.swift @@ -21,6 +21,7 @@ public struct Messenger { public var destroy: MessengerDestroy public var searchUsers: MessengerSearchUsers public var registerForNotifications: MessengerRegisterForNotifications + public var verifyContact: MessengerVerifyContact } extension Messenger { @@ -45,7 +46,8 @@ extension Messenger { waitForNodes: .live(env), destroy: .live(env), searchUsers: .live(env), - registerForNotifications: .live(env) + registerForNotifications: .live(env), + verifyContact: .live(env) ) } } @@ -71,6 +73,7 @@ extension Messenger { waitForNodes: .unimplemented, destroy: .unimplemented, searchUsers: .unimplemented, - registerForNotifications: .unimplemented + registerForNotifications: .unimplemented, + verifyContact: .unimplemented ) } diff --git a/Tests/XXMessengerClientTests/Messenger/Functions/MessengerVerifyContactTests.swift b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerVerifyContactTests.swift new file mode 100644 index 00000000..255a7220 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerVerifyContactTests.swift @@ -0,0 +1,16 @@ +import CustomDump +import XCTest +import XXClient +@testable import XXMessengerClient + +final class MessengerVerifyContactTests: XCTestCase { + func testVerify() throws { + var env: MessengerEnvironment = .unimplemented + let verify: MessengerVerifyContact = .live(env) + let contact = Contact.unimplemented("data".data(using: .utf8)!) + + let result = try verify(contact) + + XCTAssertNoDifference(result, false) + } +} -- GitLab From 7906115403fee75347f973e5b0f26452b033e052 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Fri, 9 Sep 2022 13:37:52 +0200 Subject: [PATCH 6/8] Implement verification in AuthCallbackHandlerRequest --- .../AuthCallbackHandlerRequest.swift | 12 ++ .../AppFeature/AppEnvironment+Live.swift | 6 +- .../AuthCallbackHandlerRequestTests.swift | 131 ++++++++++++++++-- 3 files changed, 137 insertions(+), 12 deletions(-) diff --git a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift index 1ec23923..e8f14806 100644 --- a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift +++ b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift @@ -1,6 +1,7 @@ import Foundation import XCTestDynamicOverlay import XXClient +import XXMessengerClient import XXModels public struct AuthCallbackHandlerRequest { @@ -14,6 +15,7 @@ public struct AuthCallbackHandlerRequest { extension AuthCallbackHandlerRequest { public static func live( db: DBManagerGetDB, + messenger: Messenger, now: @escaping () -> Date ) -> AuthCallbackHandlerRequest { AuthCallbackHandlerRequest { xxContact in @@ -29,6 +31,16 @@ extension AuthCallbackHandlerRequest { dbContact.authStatus = .verificationInProgress dbContact.createdAt = now() dbContact = try db().saveContact(dbContact) + + do { + let verified = try messenger.verifyContact(xxContact) + dbContact.authStatus = verified ? .verified : .verificationFailed + dbContact = try db().saveContact(dbContact) + } catch { + dbContact.authStatus = .verificationFailed + dbContact = try db().saveContact(dbContact) + throw error + } } } } diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift index c45c93ef..5267fcc3 100644 --- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift +++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift @@ -18,7 +18,11 @@ extension AppEnvironment { let messenger = Messenger.live(messengerEnv) let authHandler = AuthCallbackHandler.live( messenger: messenger, - handleRequest: .live(db: dbManager.getDB, now: Date.init), + handleRequest: .live( + db: dbManager.getDB, + messenger: messenger, + now: Date.init + ), handleConfirm: .live(db: dbManager.getDB), handleReset: .live(db: dbManager.getDB) ) diff --git a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift index fb92a5b8..07359d1f 100644 --- a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift +++ b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift @@ -1,16 +1,24 @@ import CustomDump import XCTest -import XXModels -import XXClient import XCTestDynamicOverlay +import XXClient +import XXMessengerClient +import XXModels @testable import AppCore final class AuthCallbackHandlerRequestTests: XCTestCase { func testRequestFromNewContact() throws { let now = Date() var didFetchContacts: [XXModels.Contact.Query] = [] + var didVerifyContact: [XXClient.Contact] = [] var didSaveContact: [XXModels.Contact] = [] + var messenger: Messenger = .unimplemented + messenger.verifyContact.run = { contact in + didVerifyContact.append(contact) + return true + } + let request = AuthCallbackHandlerRequest.live( db: .init { var db: Database = .failing @@ -24,6 +32,7 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { } return db }, + messenger: messenger, now: { now } ) var xxContact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) @@ -39,15 +48,26 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { try request(xxContact) XCTAssertNoDifference(didFetchContacts, [.init(id: ["id".data(using: .utf8)!])]) - XCTAssertNoDifference(didSaveContact, [.init( - id: "id".data(using: .utf8)!, - marshaled: "contact".data(using: .utf8)!, - username: "username", - email: "email", - phone: "phone", - authStatus: .verificationInProgress, - createdAt: now - )]) + XCTAssertNoDifference(didSaveContact, [ + .init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + username: "username", + email: "email", + phone: "phone", + authStatus: .verificationInProgress, + createdAt: now + ), + .init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + username: "username", + email: "email", + phone: "phone", + authStatus: .verified, + createdAt: now + ) + ]) } func testRequestWhenContactInDatabase() throws { @@ -57,6 +77,7 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { db.fetchContacts.run = { _ in [.init(id: "id".data(using: .utf8)!)] } return db }, + messenger: .unimplemented, now: XCTUnimplemented("now", placeholder: Date()) ) var contact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) @@ -64,4 +85,92 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { try request(contact) } + + func testRequestFromNewContactVerificationFalse() throws { + let now = Date() + var didSaveContact: [XXModels.Contact] = [] + + var messenger: Messenger = .unimplemented + messenger.verifyContact.run = { _ in false } + + let request = AuthCallbackHandlerRequest.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { query in return [] } + db.saveContact.run = { contact in + didSaveContact.append(contact) + return contact + } + return db + }, + messenger: messenger, + now: { now } + ) + var xxContact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + xxContact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + xxContact.getFactsFromContact.run = { _ in [] } + + try request(xxContact) + + XCTAssertNoDifference(didSaveContact, [ + .init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + authStatus: .verificationInProgress, + createdAt: now + ), + .init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + authStatus: .verificationFailed, + createdAt: now + ) + ]) + } + + func testRequestFromNewContactVerificationFailure() throws { + struct Failure: Error, Equatable {} + let failure = Failure() + let now = Date() + var didSaveContact: [XXModels.Contact] = [] + + var messenger: Messenger = .unimplemented + messenger.verifyContact.run = { _ in throw failure } + + let request = AuthCallbackHandlerRequest.live( + db: .init { + var db: Database = .failing + db.fetchContacts.run = { query in return [] } + db.saveContact.run = { contact in + didSaveContact.append(contact) + return contact + } + return db + }, + messenger: messenger, + now: { now } + ) + var xxContact = XXClient.Contact.unimplemented("contact".data(using: .utf8)!) + xxContact.getIdFromContact.run = { _ in "id".data(using: .utf8)! } + xxContact.getFactsFromContact.run = { _ in [] } + + XCTAssertThrowsError(try request(xxContact)) { error in + XCTAssertNoDifference(error as? Failure, failure) + } + + XCTAssertNoDifference(didSaveContact, [ + .init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + authStatus: .verificationInProgress, + createdAt: now + ), + .init( + id: "id".data(using: .utf8)!, + marshaled: "contact".data(using: .utf8)!, + authStatus: .verificationFailed, + createdAt: now + ) + ]) + } } -- GitLab From 81c28379194c8db1e8a110537edfe9fcadcc0140 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Fri, 9 Sep 2022 14:07:31 +0200 Subject: [PATCH 7/8] Wait for network and nodes before verifying --- .../AuthCallbackHandler/AuthCallbackHandlerRequest.swift | 2 ++ .../AuthCallbackHandlerRequestTests.swift | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift index e8f14806..d8ac3d18 100644 --- a/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift +++ b/Examples/xx-messenger/Sources/AppCore/AuthCallbackHandler/AuthCallbackHandlerRequest.swift @@ -33,6 +33,8 @@ extension AuthCallbackHandlerRequest { dbContact = try db().saveContact(dbContact) do { + try messenger.waitForNetwork() + try messenger.waitForNodes() let verified = try messenger.verifyContact(xxContact) dbContact.authStatus = verified ? .verified : .verificationFailed dbContact = try db().saveContact(dbContact) diff --git a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift index 07359d1f..65786884 100644 --- a/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift +++ b/Examples/xx-messenger/Tests/AppCoreTests/AuthCallbackHandler/AuthCallbackHandlerRequestTests.swift @@ -14,6 +14,8 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { var didSaveContact: [XXModels.Contact] = [] var messenger: Messenger = .unimplemented + messenger.waitForNetwork.run = { _ in } + messenger.waitForNodes.run = { _, _, _, _ in } messenger.verifyContact.run = { contact in didVerifyContact.append(contact) return true @@ -91,6 +93,8 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { var didSaveContact: [XXModels.Contact] = [] var messenger: Messenger = .unimplemented + messenger.waitForNetwork.run = { _ in } + messenger.waitForNodes.run = { _, _, _, _ in } messenger.verifyContact.run = { _ in false } let request = AuthCallbackHandlerRequest.live( @@ -135,6 +139,8 @@ final class AuthCallbackHandlerRequestTests: XCTestCase { var didSaveContact: [XXModels.Contact] = [] var messenger: Messenger = .unimplemented + messenger.waitForNetwork.run = { _ in } + messenger.waitForNodes.run = { _, _, _, _ in } messenger.verifyContact.run = { _ in throw failure } let request = AuthCallbackHandlerRequest.live( -- GitLab From 7fdbd1c6248f635ae42837c58737a4f73d28a713 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Fri, 9 Sep 2022 15:18:32 +0200 Subject: [PATCH 8/8] WIP --- .../Functions/MessengerVerifyContact.swift | 56 ++++++++++++++++++- .../Messenger/MessengerEnvironment.swift | 3 + 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift index 3d3d40e3..a7eb985d 100644 --- a/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift +++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerVerifyContact.swift @@ -1,7 +1,13 @@ +import Foundation import XCTestDynamicOverlay import XXClient public struct MessengerVerifyContact { + public enum Error: Swift.Error, Equatable { + case notConnected + case notLoggedIn + } + public var run: (Contact) throws -> Bool public func callAsFunction(_ contact: Contact) throws -> Bool { @@ -12,8 +18,54 @@ public struct MessengerVerifyContact { extension MessengerVerifyContact { public static func live(_ env: MessengerEnvironment) -> MessengerVerifyContact { MessengerVerifyContact { contact in - // TODO: - return false + guard let e2e = env.e2e() else { + throw Error.notConnected + } + guard let ud = env.ud() else { + throw Error.notLoggedIn + } + let facts = try contact.getFacts() + let verifiedContact: Contact? + if facts.isEmpty { + var lookupResult: Result<Contact, NSError>! + let semaphore = DispatchSemaphore(value: 0) + _ = try env.lookupUD( + e2eId: e2e.getId(), + udContact: try ud.getContact(), + lookupId: try contact.getId(), + callback: .init { result in + lookupResult = result + semaphore.signal() + } + ) + semaphore.wait() + verifiedContact = try lookupResult.get() + } else { + var searchResult: Result<[Contact], NSError>! + let semaphore = DispatchSemaphore(value: 0) + _ = try env.searchUD( + e2eId: e2e.getId(), + udContact: try ud.getContact(), + facts: facts, + singleRequestParamsJSON: env.getSingleUseParams(), + callback: .init { result in + searchResult = result + semaphore.signal() + } + ) + semaphore.wait() + verifiedContact = try searchResult.get().first + } + + guard let verifiedContact = verifiedContact else { + return false + } + + return try e2e.verifyOwnership( + received: contact, + verified: verifiedContact, + e2eId: e2e.getId() + ) } } } diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift index 85e53d0b..9c483774 100644 --- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift +++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift @@ -15,6 +15,7 @@ public struct MessengerEnvironment { public var isRegisteredWithUD: IsRegisteredWithUD public var loadCMix: LoadCMix public var login: Login + public var lookupUD: LookupUD public var ndfEnvironment: NDFEnvironment public var newCMix: NewCMix public var newOrLoadUd: NewOrLoadUd @@ -50,6 +51,7 @@ extension MessengerEnvironment { isRegisteredWithUD: .live, loadCMix: .live, login: .live, + lookupUD: .live, ndfEnvironment: .mainnet, newCMix: .live, newOrLoadUd: .live, @@ -80,6 +82,7 @@ extension MessengerEnvironment { isRegisteredWithUD: .unimplemented, loadCMix: .unimplemented, login: .unimplemented, + lookupUD: .unimplemented, ndfEnvironment: .unimplemented, newCMix: .unimplemented, newOrLoadUd: .unimplemented, -- GitLab