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.

104 lines
3.0 KiB

  1. import org.scalatest.funsuite.AnyFunSuite
  2. import monix.catnap.ConcurrentQueue
  3. import monix.eval.Task
  4. import monix.reactive.Observable
  5. import scala.concurrent.duration._
  6. class ObservableTest extends AnyFunSuite {
  7. import monix.execution.Scheduler.Implicits.global
  8. test("observable state machine") {
  9. (for {
  10. _ <- Task.unit
  11. sm <- MonixStateMachine()
  12. _ <-
  13. Task
  14. .parSequence(
  15. List(
  16. sm.source
  17. .doOnNext(item => Task(println(s"Task 1: Got $item")))
  18. .completedL,
  19. sm.source
  20. .doOnNext(item => Task(println(s"Task 2: Got $item")))
  21. .completedL,
  22. sm.tell(MonixStateMachine.Start) >>
  23. Observable
  24. // .interval(1.second)
  25. .interval(500.millis)
  26. .doOnNext(_ => sm.tell(MonixStateMachine.Incr))
  27. .takeUntil(Observable.unit.delayExecution(5.seconds))
  28. .completedL >>
  29. sm.tell(MonixStateMachine.Stop) >>
  30. sm.tell(MonixStateMachine.Incr)
  31. )
  32. )
  33. .void
  34. .start
  35. .bracket(_ => Task.sleep(8.seconds))(_.cancel)
  36. } yield ()).runSyncUnsafe(10.seconds)
  37. }
  38. }
  39. class MonixStateMachine(
  40. queue: ConcurrentQueue[Task, MonixStateMachine.Command],
  41. val source: Observable[(MonixStateMachine.State, MonixStateMachine.Data)]
  42. ) {
  43. import MonixStateMachine._
  44. def tell(item: Command) = queue.offer(item)
  45. }
  46. object MonixStateMachine {
  47. sealed trait State
  48. case object Idle extends State
  49. case object Active extends State
  50. sealed trait Command
  51. case object Incr extends Command
  52. case object Start extends Command
  53. case object Stop extends Command
  54. case class Data(num: Int)
  55. private def source(queue: ConcurrentQueue[Task, Command]) =
  56. Task.deferAction(implicit s =>
  57. Task(
  58. Observable
  59. .repeatEvalF(queue.poll)
  60. .scan((Idle: State, Data(0))) {
  61. case ((state, data), command) =>
  62. state match {
  63. case Idle =>
  64. println("Entered idle")
  65. command match {
  66. case Incr =>
  67. println("Not active ")
  68. (Idle, data)
  69. case Start => (Active, data)
  70. case Stop =>
  71. println("Already stopped")
  72. (Idle, data)
  73. }
  74. case Active =>
  75. println("Entered Active")
  76. command match {
  77. case Incr => (Active, data.copy(num = data.num + 1))
  78. case Start =>
  79. println("Already started")
  80. (Active, data)
  81. case Stop => (Idle, data)
  82. }
  83. }
  84. }
  85. .publish
  86. .refCount
  87. )
  88. )
  89. def apply() =
  90. for {
  91. queue <- ConcurrentQueue.bounded[Task, Command](10)
  92. source <- source(queue)
  93. } yield new MonixStateMachine(queue, source)
  94. }