Rohan Sircar
3 years ago
1 changed files with 84 additions and 0 deletions
@ -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) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue