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.

77 lines
2.3 KiB

3 years ago
  1. package outwatchapp.util.reactive
  2. import io.circe.Decoder
  3. import io.circe.Encoder
  4. import io.circe.Printer
  5. import io.circe.parser._
  6. import io.circe.syntax._
  7. import monix.execution.Ack
  8. import monix.execution.Cancelable
  9. import monix.execution.cancelables.SingleAssignCancelable
  10. import monix.reactive.Observable
  11. import monix.reactive.Observer
  12. import monix.reactive.OverflowStrategy
  13. import org.scalajs.dom.raw.MessageEvent
  14. import org.scalajs.dom.webworkers.DedicatedWorkerGlobalScope
  15. import scala.concurrent.Future
  16. import outwatchapp.util.reactive.Exceptions.WrongTypeException
  17. // @js.native
  18. // @JSGlobalScope
  19. // object WorkerGlobal extends DedicatedWorkerGlobalScope
  20. // class DedicatedWorkerImpl[T: Encoder: Decoder](wg: DedicatedWorkerGlobalScope) {
  21. // def run = Task.deferAction(implicit s =>
  22. // for {
  23. // _ <- Task.unit
  24. // sub <- Task(ConcurrentSubject.publish[T])
  25. // } yield ()
  26. // )
  27. // }
  28. object DedicatedWorker {
  29. def source[T: Decoder](wg: DedicatedWorkerGlobalScope) =
  30. Observable.create[T](OverflowStrategy.DropOld(50)) { sub =>
  31. val c = SingleAssignCancelable()
  32. def onmessageFn(event: MessageEvent): Unit = {
  33. event.data match {
  34. case s: String =>
  35. decode[T](s)
  36. .map { res =>
  37. if (sub.onNext(res) == Ack.Stop) c.cancel()
  38. res
  39. }
  40. .left
  41. .foreach(err =>
  42. sub.onError(
  43. new Exception(s"Failed to decode $s. Error was $err")
  44. )
  45. )
  46. case other =>
  47. sub.onError(WrongTypeException(s"Received wrong type: $other"))
  48. }
  49. }
  50. wg.onmessage = onmessageFn _
  51. c := Cancelable(() => wg.onmessage = _ => ())
  52. }
  53. def sink[T: Encoder](wg: DedicatedWorkerGlobalScope) =
  54. new Observer[T] {
  55. val printer = Printer.noSpaces
  56. override def onNext(elem: T): Future[Ack] = {
  57. // wg.onoffline
  58. wg.postMessage(printer.print(elem.asJson))
  59. Ack.Continue
  60. }
  61. override def onError(ex: Throwable): Unit = ex.printStackTrace()
  62. override def onComplete(): Unit = println("Worker observer completed")
  63. }
  64. def apply[T: Encoder: Decoder](
  65. wg: DedicatedWorkerGlobalScope
  66. ): DedicatedWorker[T] = MonixProSubject.from(sink(wg), source(wg))
  67. }