Skip to content
Snippets Groups Projects
Commit 341dae1a authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Listen for messages in HomeFeature

parent 978e4ffd
Branches
Tags
2 merge requests!102Release 1.0.0,!87Messenger example - chat
This commit is part of merge request !87. Comments created here will be created in the context of that merge request.
......@@ -96,6 +96,10 @@ extension AppEnvironment {
messenger: messenger,
dbManager: dbManager,
authHandler: authHandler,
messageListener: .live(
messenger: messenger,
db: dbManager.getDB
),
mainQueue: mainQueue,
bgQueue: bgQueue,
register: {
......
......@@ -15,6 +15,7 @@ public struct HomeState: Equatable {
public init(
failure: String? = nil,
authFailure: String? = nil,
messageListenerFailure: String? = nil,
isNetworkHealthy: Bool? = nil,
networkNodesReport: NodeRegistrationReport? = nil,
isDeletingAccount: Bool = false,
......@@ -25,6 +26,7 @@ public struct HomeState: Equatable {
) {
self.failure = failure
self.authFailure = authFailure
self.messageListenerFailure = messageListenerFailure
self.isNetworkHealthy = isNetworkHealthy
self.isDeletingAccount = isDeletingAccount
self.alert = alert
......@@ -35,6 +37,7 @@ public struct HomeState: Equatable {
public var failure: String?
public var authFailure: String?
public var messageListenerFailure: String?
public var isNetworkHealthy: Bool?
public var networkNodesReport: NodeRegistrationReport?
public var isDeletingAccount: Bool
......@@ -59,6 +62,13 @@ public enum HomeAction: Equatable {
case failureDismissed
}
public enum MessageListener: Equatable {
case start
case stop
case failure(NSError)
case failureDismissed
}
public enum NetworkMonitor: Equatable {
case start
case stop
......@@ -75,6 +85,7 @@ public enum HomeAction: Equatable {
case messenger(Messenger)
case authHandler(AuthHandler)
case messageListener(MessageListener)
case networkMonitor(NetworkMonitor)
case deleteAccount(DeleteAccount)
case didDismissAlert
......@@ -93,6 +104,7 @@ public struct HomeEnvironment {
messenger: Messenger,
dbManager: DBManager,
authHandler: AuthCallbackHandler,
messageListener: MessageListenerHandler,
mainQueue: AnySchedulerOf<DispatchQueue>,
bgQueue: AnySchedulerOf<DispatchQueue>,
register: @escaping () -> RegisterEnvironment,
......@@ -102,6 +114,7 @@ public struct HomeEnvironment {
self.messenger = messenger
self.dbManager = dbManager
self.authHandler = authHandler
self.messageListener = messageListener
self.mainQueue = mainQueue
self.bgQueue = bgQueue
self.register = register
......@@ -112,6 +125,7 @@ public struct HomeEnvironment {
public var messenger: Messenger
public var dbManager: DBManager
public var authHandler: AuthCallbackHandler
public var messageListener: MessageListenerHandler
public var mainQueue: AnySchedulerOf<DispatchQueue>
public var bgQueue: AnySchedulerOf<DispatchQueue>
public var register: () -> RegisterEnvironment
......@@ -124,6 +138,7 @@ extension HomeEnvironment {
messenger: .unimplemented,
dbManager: .unimplemented,
authHandler: .unimplemented,
messageListener: .unimplemented,
mainQueue: .unimplemented,
bgQueue: .unimplemented,
register: { .unimplemented },
......@@ -137,11 +152,13 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
enum NetworkHealthEffectId {}
enum NetworkNodesEffectId {}
enum AuthCallbacksEffectId {}
enum MessageListenerEffectId {}
switch action {
case .messenger(.start):
return .merge(
Effect(value: .authHandler(.start)),
Effect(value: .messageListener(.start)),
Effect(value: .networkMonitor(.stop)),
Effect.result {
do {
......@@ -203,6 +220,29 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
state.authFailure = nil
return .none
case .messageListener(.start):
return Effect.run { subscriber in
let cancellable = env.messageListener(onError: { error in
subscriber.send(.messageListener(.failure(error as NSError)))
})
return AnyCancellable { cancellable.cancel() }
}
.subscribe(on: env.bgQueue)
.receive(on: env.mainQueue)
.eraseToEffect()
.cancellable(id: MessageListenerEffectId.self, cancelInFlight: true)
case .messageListener(.stop):
return .cancel(id: MessageListenerEffectId.self)
case .messageListener(.failure(let error)):
state.messageListenerFailure = error.localizedDescription
return .none
case .messageListener(.failureDismissed):
state.messageListenerFailure = nil
return .none
case .networkMonitor(.start):
return .merge(
Effect.run { subscriber in
......
......@@ -16,6 +16,7 @@ public struct HomeView: View {
struct ViewState: Equatable {
var failure: String?
var authFailure: String?
var messageListenerFailure: String?
var isNetworkHealthy: Bool?
var networkNodesReport: NodeRegistrationReport?
var isDeletingAccount: Bool
......@@ -23,6 +24,7 @@ public struct HomeView: View {
init(state: HomeState) {
failure = state.failure
authFailure = state.authFailure
messageListenerFailure = state.messageListenerFailure
isNetworkHealthy = state.isNetworkHealthy
isDeletingAccount = state.isDeletingAccount
networkNodesReport = state.networkNodesReport
......@@ -59,6 +61,19 @@ public struct HomeView: View {
}
}
if let messageListenerFailure = viewStore.messageListenerFailure {
Section {
Text(messageListenerFailure)
Button {
viewStore.send(.messageListener(.failureDismissed))
} label: {
Text("Dismiss")
}
} header: {
Text("Message Listener Error")
}
}
Section {
HStack {
Text("Health")
......
......@@ -24,6 +24,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
store.environment.messenger.isConnected.run = { false }
store.environment.messenger.connect.run = { messengerDidConnect += 1 }
......@@ -38,12 +39,14 @@ final class HomeFeatureTests: XCTestCase {
XCTAssertNoDifference(messengerDidListenForMessages, 1)
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.didStartUnregistered)) {
$0.register = RegisterState()
}
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testMessengerStartRegistered() {
......@@ -61,6 +64,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
store.environment.messenger.isConnected.run = { false }
store.environment.messenger.connect.run = { messengerDidConnect += 1 }
......@@ -86,12 +90,14 @@ final class HomeFeatureTests: XCTestCase {
XCTAssertNoDifference(messengerDidLogIn, 1)
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.didStartRegistered))
store.receive(.networkMonitor(.start))
store.send(.networkMonitor(.stop))
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testRegisterFinished() {
......@@ -109,6 +115,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
store.environment.messenger.isConnected.run = { true }
store.environment.messenger.isLoggedIn.run = { false }
......@@ -134,12 +141,14 @@ final class HomeFeatureTests: XCTestCase {
XCTAssertNoDifference(messengerDidLogIn, 1)
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.didStartRegistered))
store.receive(.networkMonitor(.start))
store.send(.networkMonitor(.stop))
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testMessengerStartFailure() {
......@@ -155,17 +164,20 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in throw error }
store.send(.messenger(.start))
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testMessengerStartConnectFailure() {
......@@ -181,6 +193,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in }
store.environment.messenger.isConnected.run = { false }
store.environment.messenger.connect.run = { throw error }
......@@ -188,12 +201,14 @@ final class HomeFeatureTests: XCTestCase {
store.send(.messenger(.start))
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testMessengerStartIsRegisteredFailure() {
......@@ -209,6 +224,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in }
store.environment.messenger.isConnected.run = { true }
store.environment.messenger.isLoggedIn.run = { false }
......@@ -217,12 +233,14 @@ final class HomeFeatureTests: XCTestCase {
store.send(.messenger(.start))
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testMessengerStartLogInFailure() {
......@@ -238,6 +256,7 @@ final class HomeFeatureTests: XCTestCase {
store.environment.bgQueue = .immediate
store.environment.mainQueue = .immediate
store.environment.authHandler.run = { _ in Cancellable {} }
store.environment.messageListener.run = { _ in Cancellable {} }
store.environment.messenger.start.run = { _ in }
store.environment.messenger.isConnected.run = { true }
store.environment.messenger.isLoggedIn.run = { false }
......@@ -247,12 +266,14 @@ final class HomeFeatureTests: XCTestCase {
store.send(.messenger(.start))
store.receive(.authHandler(.start))
store.receive(.messageListener(.start))
store.receive(.networkMonitor(.stop))
store.receive(.messenger(.failure(error as NSError))) {
$0.failure = error.localizedDescription
}
store.send(.authHandler(.stop))
store.send(.messageListener(.stop))
}
func testNetworkMonitorStart() {
......@@ -565,4 +586,45 @@ final class HomeFeatureTests: XCTestCase {
authHandlerOnError.first?(AuthHandlerError(id: 2))
}
func testMessageListener() {
let store = TestStore(
initialState: HomeState(),
reducer: homeReducer,
environment: .unimplemented
)
var didRunMessageListener = 0
var didCancelMessageListener = 0
var messageListenerOnError: [MessageListenerHandler.OnError] = []
store.environment.mainQueue = .immediate
store.environment.bgQueue = .immediate
store.environment.messageListener.run = { onError in
didRunMessageListener += 1
messageListenerOnError.append(onError)
return Cancellable { didCancelMessageListener += 1 }
}
store.send(.messageListener(.start))
XCTAssertNoDifference(didRunMessageListener, 1)
struct MessageListenerError: Error { var id: Int }
messageListenerOnError.first?(MessageListenerError(id: 1))
store.receive(.messageListener(.failure(MessageListenerError(id: 1) as NSError))) {
$0.messageListenerFailure = MessageListenerError(id: 1).localizedDescription
}
store.send(.messageListener(.failureDismissed)) {
$0.messageListenerFailure = nil
}
store.send(.messageListener(.stop))
XCTAssertNoDifference(didCancelMessageListener, 1)
messageListenerOnError.first?(MessageListenerError(id: 2))
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment