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

indigo.platform.networking.WebSockets.scala Maven / Gradle / Ivy

The newest version!
package indigo.platform.networking

import indigo.platform.events.GlobalEventStream
import indigo.shared.IndigoLogger
import indigo.shared.events._
import indigo.shared.networking.WebSocketConfig
import indigo.shared.networking.WebSocketEvent
import indigo.shared.networking.WebSocketId
import indigo.shared.networking.WebSocketReadyState
import indigo.shared.networking.WebSocketReadyState.CLOSED
import indigo.shared.networking.WebSocketReadyState.CLOSING
import org.scalajs.dom

object WebSockets:

  private val connections: scalajs.js.Dictionary[dom.WebSocket] = scalajs.js.Dictionary.empty
  private val configs: scalajs.js.Dictionary[WebSocketConfig]   = scalajs.js.Dictionary.empty

  def processSendEvent(event: WebSocketEvent & NetworkSendEvent, globalEventStream: GlobalEventStream): Unit =
    try
      event match {
        case WebSocketEvent.ConnectOnly(config) =>
          reEstablishConnection(insertUpdateConfig(config), None, globalEventStream)
          ()

        case WebSocketEvent.Open(message, config) =>
          reEstablishConnection(insertUpdateConfig(config), Option(message), globalEventStream)
          ()

        case WebSocketEvent.Send(message, config) =>
          reEstablishConnection(insertUpdateConfig(config), None, globalEventStream).foreach { socket =>
            socket.send(message)
          }
      }
    catch {
      case e: Throwable =>
        globalEventStream.pushGlobalEvent(WebSocketEvent.Error(event.giveId, e.getMessage))
    }

  private def insertUpdateConfig(config: WebSocketConfig): WebSocketConfig = {
    val maybeConfig = configs.get(config.id.id)

    maybeConfig
      .flatMap { c =>
        if (c == config) Option(c)
        else {
          configs.remove(config.id.id)
          configs.put(config.id.id, config)
        }
      }
      .getOrElse(config)
  }

  private def reEstablishConnection(
      config: WebSocketConfig,
      onOpenSendMessage: Option[String],
      globalEventStream: GlobalEventStream
  ): Option[dom.WebSocket] =
    connections
      .get(config.id.id)
      .flatMap { conn =>
        WebSocketReadyState.fromInt(conn.readyState) match {
          case CLOSING | CLOSED =>
            newConnection(config, onOpenSendMessage, globalEventStream).flatMap { newConn =>
              connections.remove(config.id.id)
              connections.put(config.id.id, newConn)
            }

          case _ =>
            Option(conn)
        }
      }
      .orElse {
        newConnection(config, onOpenSendMessage, globalEventStream).flatMap { newConn =>
          connections.remove(config.id.id)
          connections.put(config.id.id, newConn)
        }
      }

  private def newConnection(
      config: WebSocketConfig,
      onOpenSendMessage: Option[String],
      globalEventStream: GlobalEventStream
  ): Option[dom.WebSocket] =
    try {
      val socket = new dom.WebSocket(config.address)

      socket.onmessage = (e: dom.MessageEvent) =>
        globalEventStream.pushGlobalEvent(WebSocketEvent.Receive(config.id, e.data.toString))

      socket.onopen = (_: dom.Event) => onOpenSendMessage.foreach(msg => socket.send(msg))

      socket.onerror = (_: dom.Event) =>
        globalEventStream.pushGlobalEvent(WebSocketEvent.Error(config.id, "Web socket connection error"))

      socket.onclose = (_: dom.CloseEvent) => globalEventStream.pushGlobalEvent(WebSocketEvent.Close(config.id))

      Option(socket)
    } catch {
      case e: Throwable =>
        IndigoLogger.info("Error trying to set up a websocket: " + e.getMessage)
        None
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy