websocket的一个演员在播放框架与多种消息类型 -​​ scala

时间:2017-11-01 22:44:56

标签: scala playframework websocket akka

我一直在尝试在scala中的play framework 2.5上使用websocket。 现在,我想交换多种消息类型。

但是,当客户端通过websocket发送json时,我会收到以下错误。

我是否必须选择不同的方式来交换多种消息类型?

缺少某些东西还是有更简单的方法?

[error] a.a.OneForOneStrategy - {"sort":"post", "to":"receiver","message":"Test"} (of class play.api.libs.json.JsObject)
scala.MatchError: {"sort":"post", "to":"receiver","message":"Test"} (of class play.api.libs.json.JsObject)
        at controllers.MessageController$MessageActor$$anonfun$receive$1.applyOrElse(MessageController.scala:72)
        at akka.actor.Actor$class.aroundReceive(Actor.scala:514)
        at controllers.MessageController$MessageActor.aroundReceive(MessageController.scala:63)
        at akka.actor.ActorCell.receiveMessage(ActorCell.scala:527)
        at akka.actor.ActorCell.invoke(ActorCell.scala:496)
        at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
        at akka.dispatch.Mailbox.run(Mailbox.scala:224)
        at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
        at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
        at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)

models.scala

abstract class WSMessageIn()

// Classes for input
case class PostMessage(
  sort: String = "post",
  to: String,
  ...
  message: Option[String] = None
) extends WSMessageIn

object PostMessage {
  implicit val postMessageFormat = Json.format[PostMessage]
}

case class MessageFromIn(
  sort: String = "receive",
  from: String,
  ...
  message: Option[String] = None
) extends WSMessageIn

object MessageFromIn {
  implicit val messageFromInFormat = Json.format[MessageFromIn]
}

object WSMessageIn {
  implicit def json2object(value: JsValue): WSMessageIn = {
    (value \ "sort").as[String] match {
      case "post" => value.as[PostMessage]
      case "receive" => value.as[MessageFromIn]
    }
  }

  implicit def object2json(in: WSMessageIn): JsValue = {
    in match {
      case in: PostMessage => Json.toJson(in)
      case in: MessageFromIn => Json.toJson(in)
    }
  }
}

MessageController.scala

class MessageController @Inject() (
  silhouette: Silhouette[DefaultEnv],
  ..
  implicit val system: ActorSystem,
  implicit val materializer: Materializer)
  extends Controller {

  class MessageActor(out: ActorRef) extends Actor {

    override def receive = {
      case message: JsValue =>
        message match { // !!The error occurs here
          case message: PostMessage =>
            ...
          case message: MessageFromIn =>
            ...
        }
    }
  }

  object MessageActor {
    def props(out: ActorRef) = Props(new MessageActor(out))
  }

  implicit val messageFlowTransformer = MessageFlowTransformer.jsonMessageFlowTransformer[JsValue, JsValue]

  def socket() = WebSocket.acceptOrResult[JsValue, JsValue] { request =>
    implicit val req = Request(request, AnyContentAsEmpty)
    silhouette.SecuredRequestHandler { securedRequest =>
      Future.successful(HandlerResult(Ok, Some(securedRequest.identity)))
    }.map {
      case HandlerResult(r, Some(user)) => Right(ActorFlow.actorRef(out => MessageActor.props(out)))
      case HandlerResult(r, None) => Left(r)
    }
  }
}

1 个答案:

答案 0 :(得分:0)

原样:WebSocket.acceptOrResult[JsValue, JsValue]您希望您的websocket接收JsValue

这似乎与MessageActor中的代码匹配:

override def receive = {
  case message: JsValue => // ...
}

但是,如果没有您的干预,您不应期望从JsValue转换为WSMessageIn

你能做的只是:

override def receive = {
  case message: JsValue =>
    WSMessageIn.json2object(message) match {
      case message: PostMessage =>
        ...
      case message: MessageFromIn =>
        ...
    }
}

您可能期望进行隐式转换,您可以通过向编译器提示(即说出您期望的内容)来获取它:

override def receive = {
  case message: JsValue =>
    (message: WSMessageIn) match {
      case message: PostMessage =>
        ...
      case message: MessageFromIn =>
        ...
    }
}

注意:您可以将abstract class WSMessageIn()变为:sealed trait WSMessageIn