Added odin logging + store middleware

This commit is contained in:
Rohan Sircar 2020-12-30 22:47:29 +05:30
parent f294ab7009
commit d455175044
5 changed files with 68 additions and 20 deletions

View File

@ -33,7 +33,9 @@ libraryDependencies ++= Seq(
// "io.circe" %%% "circe-config" % "0.8.0",
"org.akka-js" %%% "shocon" % "1.0.0",
"com.beachape" %%% "enumeratum-circe" % "1.6.1",
"com.github.valskalla" %%% "odin-core" % "0.7.0+95-ab4381ae+20201227-1831-SNAPSHOT"
"com.github.valskalla" %%% "odin-core" % "0.7.0+95-ab4381ae+20201227-1831-SNAPSHOT",
"io.github.cquiroz" %%% "scala-java-time" % "2.1.0",
"io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.1.0"
// "com.clovellytech" %%% "outwatch-router" % "0.0.9+7-5be0b1a2+20201227-2019-SNAPSHOT"
)

View File

@ -4,10 +4,10 @@ import scala.concurrent.duration._
import colibri.ext.monix._
import com.softwaremill.macwire._
import io.odin.consoleLogger
import monix.bio.Task
import monix.eval.Coeval
import monix.reactive.Observable
import outwatchapp.ui.components.todo.TodoListStore
import org.scalajs.dom.raw.Element
import outwatch._
import outwatch.dsl._
@ -15,10 +15,11 @@ import outwatch.router._
import outwatchapp.components.CounterDemo
import outwatchapp.components.RequestDemo
import outwatchapp.components.todo.ChartjsDemo
import outwatchapp.pages.HomePage
import outwatchapp.util.reactive.WorkerData
import outwatchapp.util.reactive.WebWorker
import outwatchapp.components.todo.FusejsDemo
import outwatchapp.pages.HomePage
import outwatchapp.ui.components.todo.TodoListStore
import outwatchapp.util.reactive.WebWorker
import outwatchapp.util.reactive.WorkerData
class MainApp(el: Element)(implicit
backend: AppTypes.Backend,
@ -34,7 +35,7 @@ class MainApp(el: Element)(implicit
for {
counterDemo <- CounterDemo()
chartDemo <- ChartjsDemo()
todoStore <- TodoListStore()
todoStore <- TodoListStore(consoleLogger[Task]())
requestDemo <- RequestDemo(todoStore)
demoWorker <- WebWorker[WorkerData]("/worker.js")
} yield {

View File

@ -14,7 +14,7 @@ import scalajs.js
@JSImport("bootstrap/dist/css/bootstrap.min.css", JSImport.Namespace)
@js.native
object BootstrapBundleCss extends js.Object
@JSImport("bootstrap", JSImport.Namespace)
@JSImport("bootstrap/dist/js/bootstrap.bundle.min.js", JSImport.Namespace)
@js.native
object BootstrapBundleJs extends js.Object

View File

@ -1,15 +1,18 @@
package nova.monadic_sfx.ui.components.todo
package outwatchapp.ui.components.todo
import scala.scalajs.js.annotation.JSExportAll
import cats.kernel.Eq
import com.softwaremill.quicklens._
import io.circe.generic.JsonCodec
import io.odin.Logger
import monix.bio.Task
import nova.monadic_sfx.util.reactive.store.Reducer
import nova.monadic_sfx.util.reactive.store.Store
import outwatchapp.util.reactive.store.Middlewares.actionLoggerMiddleware
import outwatchapp.util.reactive.store.Reducer
import outwatchapp.util.reactive.store.Store
@JSExportAll
@JsonCodec
case class Todo(id: Int, content: String)
object Todo {
implicit val eqForTodo = Eq.fromUniversalEquals[Todo]
@ -37,18 +40,16 @@ object TodoListStore {
implicit val eqForState = Eq.fromUniversalEquals[State]
}
def reducer()(
def reducer(logger: Logger[Task])(
state: State,
action: Action
): (State, Option[Task[Action]]) =
action match {
case Init => (state, None)
case Add(content) =>
println("hello")
val nextAction = Some(for {
// do some validation
// _ <- logger.debug(s"Received $content")
_ <- Task(println(s"Received $content"))
res <- Task.pure(InternalAdd(content))
} yield res)
(state, nextAction)
@ -68,19 +69,21 @@ object TodoListStore {
.using(_ :+ Todo(state.counter, content))
.modify(_.counter)
.using(_ + 1)
(nextState, Some(Task.pure(End)))
(nextState, Some(logger.debug(s"Received $content") >> Task.pure(End)))
case End => (state, None)
}
def apply(): Task[Store[Action, State]] =
def apply(logger: Logger[Task]): Task[Store[Action, State]] =
Task.deferAction(implicit s =>
for {
logMware <- actionLoggerMiddleware[Action, State](logger, "TodoStore")
store <-
Store
.createL[Action, State](
Init,
State(Vector.empty[Todo], 0),
Reducer.withOptionalEffects(reducer() _)
Reducer.withOptionalEffects(reducer(logger) _),
Seq(logMware)
)
} yield store
)

View File

@ -2,11 +2,17 @@ package outwatchapp.util.reactive.store
import java.time.LocalDateTime
import io.circe.Encoder
import io.circe.Printer
import io.circe.generic.JsonCodec
// object Middleware {
// def apply[A,M,T](ob: Observable[(A,M)], cb: (A,M) => T): Observable[(A,M)] = ob
// }
import io.circe.syntax._
import io.odin.Logger
import io.odin.LoggerMessage
import io.odin.formatter.options.PositionFormat
import io.odin.formatter.options.ThrowableFormat
import io.odin.meta.Render
import monix.bio.Task
import monix.reactive.Observable
@JsonCodec
final case class StoreInfo[A](
@ -17,6 +23,42 @@ final case class StoreInfo[A](
object StoreInfo {
val printer = Printer.noSpaces
implicit def render[T: Encoder]: Render[StoreInfo[T]] =
new Render[StoreInfo[T]] {
override def render(m: StoreInfo[T]): String = printer.print(m.asJson)
}
}
object Middlewares {}
object Middlewares {
val format = create(ThrowableFormat.Default, PositionFormat.Full)
def create(
throwableFormat: ThrowableFormat,
positionFormat: PositionFormat
): io.odin.formatter.Formatter = (msg: LoggerMessage) => msg.message.value
def actionStateLoggerMiddleware[A, M](
logger: Logger[Task]
): Task[Middleware[A, M]] =
Task.deferAction(implicit s =>
Task((obs: Observable[(A, M)]) =>
obs.doOnNextF { case (a, m) =>
logger.debug(s"Received action $a with state $m")
}
)
)
def actionLoggerMiddleware[A: Encoder, M](
logger: Logger[Task],
name: String
): Task[Middleware[A, M]] =
Task.deferAction(implicit s =>
Task((obs: Observable[(A, M)]) =>
obs.doOnNextF { case (a, _) =>
Task(LocalDateTime.now())
.flatMap(curTime => logger.debug(StoreInfo(name, a, curTime)))
}
)
)
}