I have Play websockets action:
def socket = WebSocket.acceptWithActor[String, Array[Byte]] { request => out => Props(new WebSocketInActor(out)) }
Generally I need to send to browser large raw arrays of data. But sometimes I need to send some small string data. In browser I can detect is data in text format or raw ArrayBuffer. If I create actor that sends String, I can send string messages, If I create actor that sends with Array[Byte], I can send raw arrays. Both situations I don't need to change client code. So, how can I force Play to use both sending methods with one out actor?
1 Answers
Answers 1
Ah, those answers that comes just after you post question on SO. Looking through reference and sourcecode, I found that there is mixedFrame FrameFromatter: https://github.com/playframework/playframework/blob/2.4.x/framework/src/play/src/main/scala/play/api/mvc/WebSocket.scala#L75
So you just need to say that you will respond with Either[String, Array[Byte]] and if you want to send string use Left(somestring) or else use 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)) }
UPDATE:
Or you can go one step further and create your own frame formatter
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)) }
0 comments:
Post a Comment