首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Akka HTTP Websocket,如何识别参与者内部的连接

Akka HTTP Websocket,如何识别参与者内部的连接
EN

Stack Overflow用户
提问于 2016-12-01 11:03:14
回答 2查看 1.6K关注 0票数 7

我正在scala中开发简单的多玩家游戏,我想通过websockets客户端来公开这个游戏。

这是我的WebsocketServer课

代码语言:javascript
复制
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)
    }
}

这是我的参与者的简化代码,应该从websocket服务器接收消息。

代码语言:javascript
复制
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?
    }
  }
}

到目前为止,我还可以用简单的WelcomeMessage对客户端进行响应,但是我仍然不知道如何:

  • 每当参与者收到CloseConnection消息时,从连接列表中删除参与者?
  • 确定哪条连接消息来自于参与者?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-01 20:44:22

我认为您需要使用某种keyid来映射连接参与者。

代码语言:javascript
复制
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)
    }

然后,在您的参与者中,您可以将连接存储在Map中,而不是List中,而列表也恰好更有效地被删除。

票数 3
EN

Stack Overflow用户

发布于 2017-10-25 19:59:15

这个问题已经回答了。对于外面的Java人来说,下面是java版本:

代码语言:javascript
复制
public class WebsocketRoutes extends AllDirectives {

private final ActorSystem actorSystem;
private final ActorRef connectionManager;

public WebsocketRoutes(final ActorSystem actorSystem, final ActorRef connectionManager) {
    this.actorSystem = actorSystem;
    this.connectionManager = connectionManager;
}

public Route handleWebsocket() {
    return path(PathMatchers.segment(compile("router_v\\d+")).slash(PathMatchers.segment("websocket")).slash(PathMatchers.segment(compile("[^\\\\/\\s]+"))), (version, routerId) ->
            handleWebSocketMessages(createWebsocketFlow(routerId))
    );
}

private Flow<Message, Message, NotUsed> createWebsocketFlow(final String routerId) {

    final ActorRef connection = actorSystem.actorOf(WebsocketConnectionActor.props(connectionManager));

    final Source<Message, NotUsed> source = Source.<RouterWireMessage.Outbound>actorRef(5, OverflowStrategy.fail())
            .map((outbound) -> (Message) TextMessage.create(new String(outbound.message, "utf-8")))
            .throttle(5, FiniteDuration.create(1, TimeUnit.SECONDS), 10, ThrottleMode.shaping())
            .mapMaterializedValue(destinationRef -> {
                connection.tell(new RouterConnected(routerId, destinationRef), ActorRef.noSender());
                return NotUsed.getInstance();
            });

    final Sink<Message, NotUsed> sink = Flow.<Message>create()
            .map((inbound) -> new RouterWireMessage.Inbound(inbound.asTextMessage().getStrictText().getBytes()))
            .throttle(5, FiniteDuration.create(1, TimeUnit.SECONDS), 10, ThrottleMode.shaping())
            .to(Sink.actorRef(connection, PoisonPill.getInstance()));

    return Flow.fromSinkAndSource(sink, source);
}
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40908964

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档