You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
1.8 KiB
73 lines
1.8 KiB
package nova.monadic_sfx.util.reactive
|
|
|
|
import cats.effect.Sync
|
|
import monix.bio.Task
|
|
import monix.execution.Scheduler
|
|
import monix.reactive.Observable
|
|
import monix.reactive.OverflowStrategy
|
|
import monix.reactive.subjects.ConcurrentSubject
|
|
|
|
object Store {
|
|
def createL[A, M](
|
|
initialAction: A,
|
|
initialState: M,
|
|
reducer: Reducer[A, M],
|
|
middlewares: Seq[Middleware[A, M]] = Seq.empty,
|
|
overflowStrategy: OverflowStrategy.Synchronous[A] =
|
|
OverflowStrategy.DropOld(50)
|
|
) =
|
|
Task.deferAction { implicit s =>
|
|
Task {
|
|
val subject = ConcurrentSubject.publish[A](overflowStrategy)
|
|
|
|
val fold: ((A, M), A) => (A, M) = {
|
|
case ((_, state), action) => {
|
|
val (newState, effects) = reducer(state, action)
|
|
|
|
effects.subscribe(subject.onNext _)
|
|
|
|
action -> newState
|
|
}
|
|
}
|
|
|
|
val obs = subject
|
|
.scan[(A, M)](initialAction -> initialState)(fold)
|
|
.behavior(initialAction -> initialState)
|
|
.refCount
|
|
|
|
val res = middlewares.view.reverse.foldLeft(obs) {
|
|
case (obs, middleware) => middleware(obs)
|
|
}
|
|
|
|
MonixProSubject.from(
|
|
subject,
|
|
res
|
|
)
|
|
}
|
|
}
|
|
|
|
def create[F[_], A, M](
|
|
initialAction: A,
|
|
initialState: M,
|
|
reducer: Reducer[A, M]
|
|
)(implicit s: Scheduler, F: Sync[F]): F[Observable[(A, M)]] =
|
|
F.delay {
|
|
val subject = ConcurrentSubject.publish[A]
|
|
|
|
val fold: ((A, M), A) => (A, M) = {
|
|
case ((_, state), action) => {
|
|
val (newState, effects) = reducer(state, action)
|
|
|
|
effects.subscribe(subject.onNext _)
|
|
|
|
action -> newState
|
|
}
|
|
}
|
|
|
|
subject
|
|
.scan[(A, M)](initialAction -> initialState)(fold)
|
|
.behavior(initialAction -> initialState)
|
|
.refCount
|
|
}
|
|
|
|
}
|