Added WebSocket observable class
This commit is contained in:
parent
537e1abc29
commit
937a104615
84
src/main/scala/outwatchapp/util/reactive/WebSocket.scala
Normal file
84
src/main/scala/outwatchapp/util/reactive/WebSocket.scala
Normal file
@ -0,0 +1,84 @@
|
||||
package outwatchapp.util.reactive
|
||||
|
||||
import org.scalajs.dom.{raw => sjsdr}
|
||||
import io.circe.Decoder
|
||||
import io.circe.Encoder
|
||||
import io.circe.Printer
|
||||
import io.circe.generic.JsonCodec
|
||||
import io.circe.parser._
|
||||
import io.circe.syntax._
|
||||
import monix.bio.Task
|
||||
import monix.execution.Ack
|
||||
import monix.execution.Cancelable
|
||||
import monix.reactive.Observable
|
||||
import monix.reactive.Observer
|
||||
import monix.reactive.OverflowStrategy
|
||||
import outwatchapp.util.reactive.MonixProSubject
|
||||
import org.scalajs.dom.raw.Event
|
||||
import org.scalajs.dom.raw.MessageEvent
|
||||
import scala.concurrent.Future
|
||||
|
||||
class WebSocketImpl[T: Encoder: Decoder](
|
||||
ws: sjsdr.WebSocket,
|
||||
overflowStrategy: OverflowStrategy.Synchronous[T]
|
||||
) {
|
||||
val printer = Printer.noSpaces
|
||||
|
||||
lazy val source: Task[Observable[T]] =
|
||||
Task.deferAction(implicit s =>
|
||||
for {
|
||||
obs <- Task(
|
||||
Observable
|
||||
.create[T](overflowStrategy) { sub =>
|
||||
ws.onmessage = (e: MessageEvent) =>
|
||||
e.data match {
|
||||
case s: String =>
|
||||
decode[T](s).map(sub.onNext).left.foreach(println)
|
||||
case other => println(other)
|
||||
}
|
||||
ws.onerror = (e: Event) =>
|
||||
sub.onError(new Exception(s"Error in WebSocket: $e"))
|
||||
Cancelable(() => ws.close())
|
||||
}
|
||||
.publish
|
||||
.refCount
|
||||
)
|
||||
_ <- Task(obs.subscribe(Observer.empty))
|
||||
} yield obs
|
||||
)
|
||||
|
||||
lazy val sink: Task[Observer[T]] =
|
||||
Task(
|
||||
new Observer[T] {
|
||||
override def onNext(elem: T): Future[Ack] = {
|
||||
val msg = printer.print(elem.asJson)
|
||||
ws.send(msg)
|
||||
Future.successful(Ack.Continue)
|
||||
}
|
||||
override def onError(ex: Throwable): Unit = println(ex)
|
||||
override def onComplete(): Unit = ()
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
object WebSocket {
|
||||
sealed trait Error
|
||||
final case object Error extends Error
|
||||
// val w = new sjsdr.Worker("/worker.js").asInstanceOf[Worker]
|
||||
|
||||
// type MonixWebWorker[T] = MonixProSubject[T, T]
|
||||
|
||||
def apply[T <: Product: Encoder: Decoder](
|
||||
path: String,
|
||||
overflowStrategy: OverflowStrategy.Synchronous[T] =
|
||||
OverflowStrategy.DropOld(50)
|
||||
): Task[WebSocket[T]] = for {
|
||||
websocket <- Task(new sjsdr.WebSocket(path))
|
||||
impl = new WebSocketImpl[T](websocket, overflowStrategy)
|
||||
source <- impl.source
|
||||
sink <- impl.sink
|
||||
} yield MonixProSubject.from(sink, source)
|
||||
}
|
||||
|
||||
@JsonCodec
|
||||
case class WebsocketData(data: Long)
|
Loading…
Reference in New Issue
Block a user