Skip to content

Commit 322c9cf

Browse files
authored
Merge pull request #1 from SwiftRex/MiddlewareIO
Update SwiftRex to use Middleware IO
2 parents fdd13ce + e136fd2 commit 322c9cf

File tree

4 files changed

+166
-216
lines changed

4 files changed

+166
-216
lines changed

Package.resolved

Lines changed: 20 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.2
1+
// swift-tools-version:5.4
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -15,7 +15,7 @@ let package = Package(
1515
.library(name: "GatedMiddleware", targets: ["GatedMiddleware"])
1616
],
1717
dependencies: [
18-
.package(url: "https://github.com/SwiftRex/SwiftRex.git", from: "0.7.0")
18+
.package(url: "https://github.com/SwiftRex/SwiftRex.git", from: "0.8.8")
1919
],
2020
targets: [
2121
.target(name: "GatedMiddleware", dependencies: [.product(name: "CombineRex", package: "SwiftRex")]),

Sources/GatedMiddleware/GatedMiddleware.swift

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,13 @@ extension Gate {
9292
/// trigger inner middleware before and after the reducer, and after the reducer that value will be already set to `bypass`, so you can stop timers
9393
/// and async tasks. An action that changes the state from `bypass` to `active`, will not trigger the inner middleware before the reducer nor after
9494
/// it, so you may want to send a second action to start the middleware timers again, because the gated middleware can't do that for you.
95-
public final class GatedMiddleware<M: Middleware>: Middleware {
95+
public final class GatedMiddleware<M: MiddlewareProtocol>: MiddlewareProtocol {
9696
public typealias InputActionType = M.InputActionType
9797
public typealias OutputActionType = M.OutputActionType
9898
public typealias StateType = M.StateType
9999

100100
private let middleware: M
101101
private let gate: Gate<InputActionType, OutputActionType, StateType>
102-
private var getState: GetState<StateType>?
103102

104103
/// GatedMiddleware by action init with Closure variant
105104
/// - Parameters:
@@ -170,27 +169,6 @@ public final class GatedMiddleware<M: Middleware>: Middleware {
170169
self.init(middleware: middleware, stateMap: { $0[keyPath: state] })
171170
}
172171

173-
/// Middleware setup. This function will be called before actions are handled to the middleware, so you can configure your middleware with the
174-
/// given parameters. You can hold any of them if you plan to read the state or dispatch new actions.
175-
/// You can initialize and start timers or async tasks in here or in the `handle(action:next)` function, but never before this function is called,
176-
/// otherwise the middleware would not yet be running from a store.
177-
/// Because no actions are delivered to this middleware before the `receiveContext(getState:output:)` is called, you can safely keep implicit
178-
/// unwrapped versions of `getState` and `output` as properties of your concrete middleware, and set them from the arguments of this function.
179-
///
180-
/// This will be always forwarded to the inner middleware regardless of its gate state, another reason for you to never start side-effects on this
181-
/// event. However, this is proxied by the gated middleware, and output will only be forwarded to the store in case the gate state is active.
182-
///
183-
/// - Parameters:
184-
/// - getState: a closure that allows the middleware to read the current state at any point in time
185-
/// - output: an action handler that allows the middleware to dispatch new actions at any point in time
186-
public func receiveContext(getState: @escaping GetState<M.StateType>, output: AnyActionHandler<M.OutputActionType>) {
187-
self.getState = getState
188-
middleware.receiveContext(getState: getState, output: .init { [weak self] outputAction, source in
189-
guard let self = self, self.gate.shouldDispatchAction(outputAction, getState()) else { return }
190-
output.dispatch(outputAction, from: source)
191-
})
192-
}
193-
194172
/// Handles the incoming actions and may or not start async tasks, check the latest state at any point or dispatch additional actions.
195173
/// This is also a good place for analytics, tracking, logging and telemetry. You can schedule tasks to run after the reducer changed the global
196174
/// state if you want, and/or execute things before the reducer.
@@ -215,17 +193,30 @@ public final class GatedMiddleware<M: Middleware>: Middleware {
215193
/// - Parameters:
216194
/// - action: the action to be handled
217195
/// - dispatcher: information about the action source, representing the entity that created and dispatched the action
218-
/// - afterReducer: it can be set to perform any operation after the reducer has changed the global state. If the function ends before you set
219-
/// this in/out parameter, `afterReducer` will default to `.doNothing()`.
220-
public func handle(action: M.InputActionType, from dispatcher: ActionSource, afterReducer: inout AfterReducer) {
221-
guard let state = self.getState?(),
222-
gate.shouldHandleAction(action, state) else { return }
196+
/// - state: read the most up-to-date state at any point
197+
/// - Returns: IO closure, where side-effects should be put, and from where actions can be dispatched. In the Gated Middleware this will not
198+
/// do anything in case the predicate is not satisfied, or it will forward the action to the inner middleware in case the predicate
199+
/// is true.
200+
public func handle(action: M.InputActionType, from dispatcher: ActionSource, state: @escaping GetState<M.StateType>) -> IO<M.OutputActionType> {
201+
print(action)
202+
dump(state())
203+
guard gate.shouldHandleAction(action, state()) else { return .pure() }
204+
205+
return middleware.handle(action: action, from: dispatcher, state: state)
206+
.flatMap { [weak self] actionFromInnerMiddlewareAsResponse in
207+
guard let self = self,
208+
self.gate.shouldHandleAction(action, state()),
209+
self.gate.shouldDispatchAction(actionFromInnerMiddlewareAsResponse.action, state())
210+
else { return .pure() }
223211

224-
middleware.handle(action: action, from: dispatcher, afterReducer: &afterReducer)
212+
return IO { output in
213+
output.dispatch(actionFromInnerMiddlewareAsResponse)
214+
}
215+
}
225216
}
226217
}
227218

228-
extension Middleware {
219+
extension MiddlewareProtocol {
229220
/// Gated middleware is a middleware that holds an inner middleware that could be either active or not.
230221
///
231222
/// This creates a GatedMiddleware by action:
@@ -441,7 +432,7 @@ extension Middleware {
441432
}
442433
}
443434

444-
extension Middleware {
435+
extension MiddlewareProtocol {
445436
/// Gated middleware is a middleware that holds an inner middleware that could be either active or not.
446437
///
447438
/// This creates a GatedMiddleware by state:

0 commit comments

Comments
 (0)