Akka HTTP Websocket,如何识别actor内部的连接

Nor*_*icz 6 scala akka-stream akka-http

我正在研究scala中的简单多人游戏,我想通过websockets为JS客户端公开.

这是我的WebsocketServer类

class WebsocketServer(actorRef: ActorRef, protocol: Protocol, system: ActorSystem, materializer: ActorMaterializer) extends Directives {

    val route = get {
      pathEndOrSingleSlash {
        handleWebSocketMessages(websocketFlow)
      }
    }

    def websocketFlow: Flow[Message, Message, Any] =
      Flow[Message]
        .map {
          case TextMessage.Strict(textMessage) => protocol.hydrate(textMessage)
        }
        .via(actorFlow)
        .map(event => TextMessage.Strict(protocol.serialize(event)))


    def actorFlow : Flow[Protocol.Message, Protocol.Event, Any] = {
      val sink =
        Flow[Protocol.Message]
          .to(Sink.actorRef[Protocol.Message](actorRef, Protocol.CloseConnection()))

      val source =
        Source.actorRef[Protocol.Event](1, OverflowStrategy.fail)
          .mapMaterializedValue(actor => actorRef ! Protocol.OpenConnection(actor))

      Flow.fromSinkAndSource(sink, source)
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的actor的简化代码,它应该从websocket服务器接收消息.

class GameActor() extends Actor {

  private var connections: List[ActorRef] = List()

  override def receive: Receive = {

    case message: Protocol.OpenConnection => {
      this.connections = message.connection :: this.connections
      message.connection ! Protocol.ConnectionEstablished()
    }

    case message: Protocol.CloseConnection => {
      // how can I remove actor from this.connections ?
    }

    case message: Protocol.DoSomething => {
      // how can I identify from which connection this message came in?
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一直很好,目前我能够用简单的WelcomeMessage响应客户端但是我仍然不知道如何:

  • 当actor接收CloseConnection消息时,从连接列表中删除actor ?
  • 确定哪个连接消息来自演员?

Qin*_*wei 3

我认为你需要有某种keyid与你的连接演员进行映射。

def websocketFlow: Flow[Message, Message, Any] =
  val randomKey = Random.nextInt()
      Flow[Message]
        .map {
          case TextMessage.Strict(textMessage) => protocol.hydrate(textMessage)
        }
        .via(actorFlow(randomKey))
        .map(event => TextMessage.Strict(protocol.serialize(event)))


    def actorFlow(flowID: Int) : Flow[Protocol.Message, Protocol.Event, Any] = {
      val sink =
        Flow[Protocol.Message]
          .to(Sink.actorRef[Protocol.Message](actorRef, Protocol.CloseConnection(flowID)))

      val source =
        Source.actorRef[Protocol.Event](1, OverflowStrategy.fail)
          .mapMaterializedValue(actor => actorRef ! Protocol.OpenConnection(actor, flowID))

      Flow.fromSinkAndSource(sink, source)
    }
Run Code Online (Sandbox Code Playgroud)

然后在你的演员中,你可以将连接存储在地图而不是列表中,这也恰好可以更有效地删除。