I'm working on simple mulitplayer game in scala that I would like to expose through websockets for JS clients.
Here is my WebsocketServer class
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)
}
}
This is simplified code of my actor that should receive messages from websocket server.
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?
}
}
}
So far so good, currently I'm able to respond with simple WelcomeMessage to a client however I still don't know how to:
CloseConnection
message?I think you need to have some sort of key
or id
to map with your connection actor.
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)
}
then in your actor you can store the connections in a Map instead of List, which also happen to be more efficient to be remove.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With