使用akka-http库创建服务器让我有些迷茫。我需要建立的联系如下:
鉴于:
这是我的websocket端点:
path("socket") {
handleWebSocketMessages(listen())
}
这里是listen()
方法:
// stores offers to broadcast to all clients
private var offers: List[TextMessage => Unit] = List()
def listen(): Flow[Message, Message, NotUsed] = {
val inbound: Sink[Message, Any] = Sink.foreach(m => /* handle the message */) // (*)
val outbound: Source[Message, SourceQueueWithComplete[Message]] =
Source.queue[Message](16, OverflowStrategy.fail)
Flow.fromSinkAndSourceMat(inbound, outbound)((_, outboundMat) => {
offers ::= outboundMat.offer
NotUsed
})
}
def sendText(text: String): Unit = {
for (connection <- offers) connection(TextMessage.Strict(text))
}
使用这种方法,我可以注册多个客户端并使用sendText(text: String)
方法来回答它们。但是,有一个大问题:评估了它的命令后,如何仅回答特定的客户端。 (请参见(*)
)
[让我烦恼的另一件事是offers
是一个变量,以纯FP方式进行编程时这似乎是错误的,但我可以接受,如果其余的都可以工作]
编辑:
为了详细说明,我基本上需要能够实现如下所示的方法:
def onMessageReceived(m: Message, answer: TextMessage => Unit): Unit = {
val response: TextMessage = handleMessage(m)
answer(response)
}
但是我无法弄清楚在我的websocket流中该方法的调用位置。
答案 0 :(得分:0)
我不确定这是否可行,但这似乎行得通:
var actors: List[ActorRef] = Nil
private def wsFlow(implicit materializer: ActorMaterializer): Flow[ws.Message, ws.Message, NotUsed] = {
val (actor, source) = Source.actorRef[String](10, akka.stream.OverflowStrategy.dropTail)
.toMat(BroadcastHub.sink[String])(Keep.both)
.run()
actors = actor :: actors
val wsHandler: Flow[ws.Message, ws.Message, NotUsed] =
Flow[ws.Message]
.merge(source)
.map {
case TextMessage.Strict(tm) => handleMessage(actor, tm)
case _ => TextMessage.Strict("Ignored message!")
}
wsHandler
}
def broadcast(msg: String): Unit = {
actors.foreach(_ ! TextMessage.Strict(msg))
}