Websocket在Play 2.5中处理ByteString和String

时间:2017-04-22 16:18:01

标签: scala playframework akka playframework-2.5

Play Framework和Scala的新手。我试图在播放中使用websockets编写文件上传。我发现可以使用ByteString完成。但面临的问题是我无法将响应消息保留为String

def upload = WebSocket.accept[ByteString, String] { request =>
  ActorFlow.actorRef(out => UploadActor.props(out))
}

我得到的例外情况如下,

play.sbt.PlayExceptions$CompilationException: Compilation error[could not find implicit value for parameter transformer: play.api.mvc.WebSocket.MessageFlowTransformer[akka.util.ByteString,String]]
  at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27)
  at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27)
  at scala.Option.map(Option.scala:145)
  at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:49)
  at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:44)
  at scala.Option.map(Option.scala:145)
  at play.sbt.run.PlayReload$.taskFailureHandler(PlayReload.scala:44)
  at play.sbt.run.PlayReload$.compileFailure(PlayReload.scala:40)
  at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17)
  at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17)

处理websocket的Actor如下,

class UploadActor(out: ActorRef) extends Actor{
  out ! "Hello"

  def receive = {
    case msg: ByteString => {
      val p = new PrintWriter(new File("/tmp/newFile.mp4"))
      p.print(msg.asByteBuffer)
      p.flush()
      out ! "file received"
    }
    case msg: String => out ! ("Got it "+ msg)
  } 
}

2 个答案:

答案 0 :(得分:1)

Playframework WebSocket支持依赖于Akka Streams,因此表示一个通用的WebSocket消息流为Flow类型MessageMessage。输入和输出参数的任何其他组合都需要隐式提供为MessageFlowTransformer[In, Out]

现在,Playframework提供了一些变压器 - 例如MessageFlowTransformer[String, String]MessageFlowTransformer[ByteString, ByteString]等。有关完整列表,请查看source code

如果您希望ByteStringString,则需要在范围内提供自己的变压器。它看起来如下:

implicit val byteStringToStringMessageFlowTransformer: MessageFlowTransformer[ByteString, String] = {
      new MessageFlowTransformer[ByteString, String] {
        def transform(flow: Flow[ByteString, String, _]) = {
          AkkaStreams.bypassWith[Message, ByteString, Message](Flow[Message] collect {
            case BinaryMessage(data) => Left(data)
            case TextMessage(_) =>
              Right(CloseMessage(
                Some(CloseCodes.Unacceptable),
                "This WebSocket only supports binary frames"))
          })(flow map TextMessage.apply)
        }
      }
    }

docs中的更多信息。

答案 1 :(得分:0)

Play 2.5 Scala WebSocket实际上已经进行了重构:

https://www.playframework.com/documentation/2.8.x/StreamsMigration25#Migrating-Scala-WebSockets

您现在可以使用play.api.http.websocket.Message发送和接收各种类型的Websocket框架:

WebSocket.accept[Message, Message] { request =>
  ActorFlow.actorRef { out =>
    WebSocketActor.props(out)
  }
}

有关BinaryMessageTextMessage等,请参见the sealed trait Message