我是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死信。 任何帮助都非常感谢。
答案 0 :(得分:2)
首先,在您的WebSocket方法中,您需要使用提供的ActorRef
而不是sender
。 sender
可能是层次结构中的其他内容。
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
}
...
}