|
|
package nova.monadic_sfx.util.reactive.store
import java.time.LocalDateTime
import io.circe.Encoder import io.odin.Logger import monix.bio.Task import monix.eval.Coeval 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[Store[A, M]] = Task.deferAction { implicit s => Task { val subject = ConcurrentSubject.publish[A](overflowStrategy)
val fold: ((A, M), A) => Coeval[(A, M)] = { case ((_, state), action) => Coeval { val (newState, effects) = reducer(state, action)
effects.subscribe(subject.onNext _)
action -> newState } }
val obs = Observable.suspend( subject .scanEval0F[Coeval, (A, M)]( Coeval.pure(initialAction -> initialState) )(fold) .behavior(initialAction -> initialState) .refCount )
val res = middlewares.foldLeft(obs) { case (obs, middleware) => middleware(obs) }
MonixProSubject.from( subject, res ) } }
def createJsonL[A: Encoder, M]( initialAction: A, initialState: M, reducer: Reducer[A, M], storeName: String, logger: Logger[Task], middlewares: Seq[Middleware[A, M]] = Seq.empty, overflowStrategy: OverflowStrategy.Synchronous[A] = OverflowStrategy.DropOld(50) ): Task[Store[A, M]] = Task.deferAction { implicit s => Task { val subject = ConcurrentSubject.publish[A](overflowStrategy)
val fold: ((A, M), A) => Task[(A, M)] = { case ((_, state), action) => Task { val (newState, effects) = reducer(state, action)
effects.subscribe(subject.onNext _)
action -> newState } }
val obs = subject .doOnNextF(action => Task(LocalDateTime.now()).flatMap(curTime => logger.debug( StoreInfo(storeName, action, curTime) ) ) ) // .doOnNextF(action => Coeval(println(action)))
.scanEvalF[Task, (A, M)](Task.pure(initialAction -> initialState))( fold ) .behavior(initialAction -> initialState) .refCount
// val res = middlewares.foldLeft(obs) {
// case (obs, middleware) => middleware(obs)
// }
MonixProSubject.from( subject, obs ) } }
}
|