Scala Play Websocket - 使用一个演员来发送两个:Array [Byte]和String消息

时间:2015-08-19 08:50:57

标签: scala playframework websocket

我有播放websockets动作:

def socket = WebSocket.acceptWithActor[String, Array[Byte]] { request => out =>
    Props(new WebSocketInActor(out))
}

通常我需要向浏览器发送大型原始数据数组。但有时我需要发送一些小的字符串数据。在浏览器中,我可以检测到文本格式的数据或原始的ArrayBuffer。 如果我创建发送String的actor,我可以发送字符串消息,如果我创建使用Array [Byte]发送的actor,我可以发送原始数组。这两种情况我都不需要更改客户端代码。那么,我如何强制Play使用两个发送方法与一个演员?

1 个答案:

答案 0 :(得分:4)

啊,那些答案就是在你发布关于SO的问题之后发出的。通过参考和源代码查看,我发现有mixedFrame FrameFromatter:https://github.com/playframework/playframework/blob/2.4.x/framework/src/play/src/main/scala/play/api/mvc/WebSocket.scala#L75

所以你只需说你会用[String,Array [Byte]]回复,如果你想发送字符串使用Left(somestring),或者使用Right [somearray]。

  class WebSocketInActor(out: ActorRef) extends Actor {
    override def preStart() = {
      println("User connected")
      val s = "Hello"
      out ! Left(s)
      out ! Right(s.getBytes("utf8"))
    }
    override def postStop() = {
      println("User discconnected")
    }
    def receive = {
      case msg: String => {
      }
      case _ =>
    }
  }

  def socket = WebSocket.acceptWithActor[String, Either[String, Array[Byte]]] { request => out =>
    Props(new WebSocketInActor(out))
  }

更新:

或者你可以更进一步,创建自己的帧格式化器

  sealed trait WSMessage
  case class StringMessage(s: String) extends WSMessage
  case class BinaryMessage(a: Array[Byte]) extends WSMessage
  case class JsonMessage(js: JsValue) extends WSMessage

  implicit object myFrameFormatter extends BasicFrameFormatter[WSMessage] {
    private val textFrameClass = classOf[TextFrame]
    private val binaryFrameClass = classOf[BinaryFrame]

    def toFrame(message: WSMessage): BasicFrame = message match {
      case StringMessage(s) => TextFrame(s)
      case BinaryMessage(a) => BinaryFrame(a)
      case JsonMessage(js) => TextFrame(Json.stringify(js))
    }
    def fromFrame(frame: BasicFrame): WSMessage = frame match {
      case TextFrame(s) => StringMessage(s)
      case BinaryFrame(a) => BinaryMessage(a)
    }
    def fromFrameDefined(clazz: Class[_]): Boolean = clazz match {
      case `textFrameClass` => true
      case `binaryFrameClass` => true
      case _ => false // shouldn't be reachable
    }
  }

  class WebSocketInActor(out: ActorRef) extends Actor {
    override def preStart() = {
      println("User connected")
      val s = "Hello"
      val a:Array[Byte] = Array(100, 50, 30).map(_.toByte)
      out ! StringMessage(s)
      out ! JsonMessage(Json.obj("txt" -> s, "array" -> a))
      out ! BinaryMessage(a)
    }
    override def postStop() = {
      println("User discconnected")
    }
    def receive = {
      case msg: String => {
      }
      case _ =>
    }
  }

  def socket = WebSocket.acceptWithActor[String, WSMessage] { request => out =>
    Props(new WebSocketInActor(out))
  }