2016-12-01 12 views
5

私はJSクライアント用のWebソケットを通じて公開したいと思っている単純なマルチプレイヤーゲームのスケーラに取り組んでいます。Akka HTTP Websocket、アクター内部の接続を特定する方法

は、ここでこれはWebSocketのサーバーからメッセージを受信する必要があり、私の俳優のコードを簡略化されて

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) 
    } 
} 

私WebsocketServerクラスです。

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を受け取りますメッセージ?
  • どのメッセージから俳優にメッセージが届いたのかを特定しますか?

答えて

2

接続俳優とマップするには、keyまたはidのようなものが必要です。

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) 
    } 

あなたの俳優では、リストの代わりにマップに接続を保存することができます。これはまた、削除する方が効率的です。

+1

私はある種の仕組みを探していましたが、今までで最も簡単な解決策は考えていませんでした。 –

2

この質問は既に回答済みです。そこにいるJavaの人々のために、ここにJavaのバージョンがあります:

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); 
} 
} 
関連する問題