使用websockets的客户端和服务器之间的私有通信播放2.3.x.

时间:2014-10-20 23:57:36

标签: scala websocket playframework-2.0 akka

我是scala的新手,无法使用websocket向客户端发送私信。

这是我的控制器:

object Client extends Controller {
  def socket(uuid: String) = WebSocket.acceptWithActor[String, String] { request =>
    out => ClientWebSocket.props(uuid)
  }
 // Test Method to send message to websocket connected client
  def sendMessage(guid: String) = Action { implicit request =>
    val system = ActorSystem("default")
    val out = system.actorOf(Props(classOf[ClientWebSocket], guid))
    out ! SendUpdate("Message Recieved")
    Ok
  }
}

这是我的演员班:

object ClientWebSocket {
  def props(uuid: String) = Props(new ClientWebSocket(uuid))
  case class SendUpdate(msg:String)

}

class ClientWebSocket(uuid: String) extends Actor {
  import ClientWebSocket._

  def receive = {
    case SendUpdate(msg:String) =>
      sender ! "Message is " + msg
  }
}

当我用uuid客户端调用sendMessage时,我遇到了遇到错误的akka​​死信。 任何帮助都非常感谢。

2 个答案:

答案 0 :(得分:2)

首先,在您的WebSocket方法中,您需要使用提供的ActorRef而不是sendersender可能是层次结构中的其他内容。

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
  import ClientWebSocket._

  def receive = {
    case SendUpdate(msg: String) =>
      out ! s"Message is $msg"
  }
}

其次,您正在sendMessage收到死信,因为您正在回复您的控制器,不幸的是,该控制器不是演员。

问题在于你无法掌握ActorRef,因为你不知道演员的名字,所以你不能使用ActorSelection。因此,您需要对自己的应用程序进行WebSocket调用,从Web浏览器/ JavaScript调用它,或者通过操作进行操作以获取演员。

修改

您的ClientWebSocket可以注册(例如在preStart通过ActorSelection或通过ActorRef作为道具参数)与另一个保持Map[String, ActorRef]引用的参与者注册所有的websockets,然后使用死亡监视器监视它们。那个演员然后将你的SendUpdate转发给正确的websocket演员。由于您只能在acceptWithActor中返回道具,因此您无法形成真正的层次结构。

答案 1 :(得分:0)

out参数是一个ActorRef,您将使用它向客户端发送消息,因此您需要将它保存在您的Actor中。

object Client extends Controller {
  def socket(uuid: String) = WebSocket.acceptWithActor[String, String] { request =>
    // out is an actor to what the outbound messages should go to respond to remote client
    out => ClientWebSocket.props(uuid, out)
  }
}

您的ClientWebSocket演员如下:

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor ...

伴侣对象如下

object ClientWebSocket {
  def props(uuid: String, out: ActorRef) = Props(classOf[ClientWebSocket], uuid, out)
}

在ClientWenSocket中,您可以使用CentralWebSocketControl Actor注册/取消注册Actor:

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
  @throws[Exception](classOf[Exception])
  override def preStart(): Unit = {
    super.preStart()
    CentralWebSocketControl.instance ! RegisterMe(uuid)
  }

  @throws[Exception](classOf[Exception])
  override def postStop(): Unit = {
    CentralWebSocketControl.instance ! UnregisterMe(uuid)
    super.postStop()
  }
}

CentralWebSocketControl Actor可以是:

class CentralWebSocketControl extends Actor {

  val clientActors = scala.collection.mutable.HashMap[String, ActorRef]()

  override def receive: Actor.Receive = {
    case RegisterMe(uuid) =>
      clientActors += uuid -> sender()
    case UnregisterMe(uuid) =>
      clientActors -= uuid    
  }
}

object CentralWebSocketControl {
  val instance = Akka.system.actorOf(Props(classOf[CentralWebSocketControl]), name = "CentralWebSocketControl")
} 

要将消息发送到由uuid标识的给定ClientWebSocket,您可以向CentralWebSocketControl发送消息,该消息可以将消息委托给已注册的ClientWebSocket。

class CentralWebSocketControl extends Actor {

  val clientActors = scala.collection.mutable.HashMap[String, ActorRef]()

  override def receive: Actor.Receive = {
    ...    
    case SendUpdateTo(uuid: String, msg: String) =>
      clientActors.get(uuid) match {
        case Some(actor) =>
          actor ! SendUpdate(msg)
        case None =>
          ???
      }
  }
}

最后

class ClientWebSocket(uuid: String, out: ActorRef) extends Actor {
  override def receive: Receive = {
    case SendUpdate(msg) =>
      out ! msg
  }
  ...    
}