All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sttp.client4.WebSocketImpl.scala Maven / Gradle / Ivy

The newest version!
package sttp.client4

import org.scalajs.dom.{WebSocket => JSWebSocket}
import sttp.client4.WebSocketImpl.OpenState
import sttp.client4.internal.JSSimpleQueue
import sttp.client4.internal.ws.WebSocketEvent
import sttp.model.Headers
import sttp.monad.MonadError
import sttp.monad.syntax._
import sttp.ws.{WebSocket, WebSocketClosed, WebSocketFrame}

import scala.scalajs.js.typedarray.{ArrayBuffer, _}

private[client4] class WebSocketImpl[F[_]] private (
    ws: JSWebSocket,
    queue: JSSimpleQueue[F, WebSocketEvent],
    implicit val monad: MonadError[F]
) extends WebSocket[F] {

  override def receive(): F[WebSocketFrame] = {

    def _receive(e: WebSocketEvent): F[WebSocketFrame] = e match {
      case WebSocketEvent.Open() =>
        queue.poll.flatMap(_receive)
      case WebSocketEvent.Frame(c: WebSocketFrame.Close) =>
        queue.offer(WebSocketEvent.Error(WebSocketClosed(Some(c))))
        monad.unit(c)
      case e @ WebSocketEvent.Error(t: Exception) =>
        queue.offer(e)
        monad.error(t)
      case WebSocketEvent.Error(t)                 => throw t
      case WebSocketEvent.Frame(f: WebSocketFrame) => monad.unit(f)
    }

    queue.poll.flatMap(_receive)
  }

  override def send(f: WebSocketFrame, isContinuation: Boolean): F[Unit] =
    f match {
      case WebSocketFrame.Text(payload, _, _) => monad.unit(ws.send(payload))
      case WebSocketFrame.Binary(payload, _, _) =>
        val ab: ArrayBuffer = payload.toTypedArray.buffer
        monad.unit(ws.send(ab))
      case WebSocketFrame.Close(statusCode, reasonText) =>
        isOpen().flatMap(open => if (open) monad.unit(ws.close(statusCode, reasonText)) else ().unit)
      case _: WebSocketFrame.Ping => monad.error(new UnsupportedOperationException("Ping is not supported in browsers"))
      case _: WebSocketFrame.Pong => monad.error(new UnsupportedOperationException("Pong is not supported in browsers"))
    }

  override def isOpen(): F[Boolean] = monad.eval(ws.readyState == OpenState)

  override lazy val upgradeHeaders: Headers = Headers(Nil)
}

object WebSocketImpl {
  def newJSCoupledWebSocket[F[_]](
      ws: JSWebSocket,
      queue: JSSimpleQueue[F, WebSocketEvent]
  )(implicit monad: MonadError[F]): sttp.ws.WebSocket[F] =
    new WebSocketImpl[F](ws, queue, monad)

  val OpenState = 1
  val BinaryType = "arraybuffer"
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy