-
-
Save yurique/69f9c245959bf1ae20d1cbc3df3f1cd9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package app.tulz.http.ws | |
import com.raquo.laminar.api.L._ | |
import io.circe.{Decoder, Encoder} | |
import io.circe.parser._ | |
import io.circe.syntax._ | |
import org.scalajs.dom | |
import org.scalajs.dom.raw.{ErrorEvent, WebSocket} | |
import cats.syntax.option._ | |
import scala.util.Try | |
sealed trait WebSocketEvent[+T] | |
object WebSocketEvent { | |
case object Connected extends WebSocketEvent[Nothing] | |
case object Closed extends WebSocketEvent[Nothing] | |
final case class Error(message: String) extends WebSocketEvent[Nothing] | |
final case class Message[T](message: T) extends WebSocketEvent[T] | |
} | |
object JsonWebSocket { | |
def forUrl[Receive: Decoder, Send: Encoder](url: String)(implicit owner: Owner): (EventStream[WebSocketEvent[Receive]], Observer[Send], () => Unit) = { | |
val receiveBus = new EventBus[WebSocketEvent[Receive]]() | |
val sendBus = new EventBus[Send] | |
Try { | |
println(s"connecting to ws: $url") | |
val ws = new WebSocket(url) | |
var subscription: Option[Subscription] = Option.empty | |
ws.onopen = { event ⇒ | |
receiveBus.writer.onNext(WebSocketEvent.Connected) | |
subscription = sendBus.events.foreach(e => ws.send(e.asJson.noSpaces)).some | |
} | |
ws.onerror = { event ⇒ | |
receiveBus.writer.onNext(WebSocketEvent.Error(event.asInstanceOf[ErrorEvent].message)) | |
} | |
ws.onmessage = { event ⇒ | |
decode[Receive](event.data.toString) match { | |
case Right(message) => | |
receiveBus.writer.onNext(WebSocketEvent.Message(message)) | |
case Left(error) => | |
receiveBus.writer.onNext(WebSocketEvent.Error(error.getMessage)) | |
} | |
} | |
ws.onclose = { event ⇒ | |
receiveBus.writer.onNext(WebSocketEvent.Closed) | |
subscription.foreach(_.kill()) | |
subscription = None | |
} | |
( | |
receiveBus.events, | |
sendBus.writer, | |
() => { | |
receiveBus.writer.onNext(WebSocketEvent.Closed) | |
ws.close() | |
} | |
) | |
}.fold({ error => | |
println(error) | |
receiveBus.writer.onNext(WebSocketEvent.Error(error.getMessage)) | |
( | |
receiveBus.events, | |
sendBus.writer, | |
() => () | |
) | |
}, identity) | |
} | |
def forPath[Receive: Decoder, Send: Encoder](path: String)(implicit owner: Owner): (EventStream[WebSocketEvent[Receive]], Observer[Send], () => Unit) = { | |
val wsProtocol = if (dom.document.location.protocol == "https:") "wss" else "ws" | |
forUrl(s"$wsProtocol://${dom.document.location.host}$path") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment