我想在Akka Streams Websocket和支持反压的Actor之间实现集成。
我的websocket协议支持:
由于事件模式,我不能使用简单的Flow
,而是需要分为Sink
和Source
,以便我可以在不通过WS接收消息的情况下发送事件至少我是这样理解的。
将来,WS上收到的请求将通过grpc转发到某个服务,并且当该服务响应时,该响应也将通过WS返回。理想情况下,我希望在整个链中都产生背压。
我目前的简单Ping / Pong协议实现看起来像这样,但
offer
方法的错误情况下该怎么做flatMapConcat
时是否要使用TextMessage.textStream
TextMessage
如果有人可以查看我的代码并告诉我在这里我可以做得更好,我将非常感激。
def wsFlow:Flow[Message, Message, NotUsed] = {
// the actor that is used to handle a single WS
val ws:ActorRef = system.actorOf(WebSocketActor.props())
// used to send messages via the WS to the client
val wsSender:Source[Message, NotUsed] =
Source
.queue(bufferSize = 500, overflowStrategy = OverflowStrategy.backpressure)
.map { response:Response =>
response match {
case pr:PingResponse => TextMessage(pr.toJson.compactPrint)
}
}
.mapMaterializedValue { wsQueue =>
// the wsQueue is used to send messages to the client
ws ! WsConnect(wsQueue)
NotUsed // dont expose the wsQueue, change materialized value to NotUsed
}
// used to receive messages via the WS from the client
val wsHandler:Sink[Message, NotUsed] =
Flow[Message]
.flatMapConcat {
case tm:TextMessage => tm.textStream
case bm:BinaryMessage =>
// ignore binary messages but drain content to avoid the stream being clogged
bm.dataStream.runWith(Sink.ignore)
Source.empty
}
.map(text => JsonParser(text).convertTo[Request])
.to(Sink.actorRef(ws, WsDisconnect))
Flow.fromSinkAndSource(wsHandler, wsSender)
}
class WebSocketActor(implicit ec:ExecutionContext) extends Actor {
private var wsQueue:Option[SourceQueueWithComplete[Response]] = None
override def receive: Receive = {
case WsConnect(ref) => wsQueue = Some(ref)
case WsDisconnect =>
wsQueue.foreach(_.complete())
wsQueue = None
case ping:PingRequest =>
val response = PingResponse(200, ping.clientRequestId, Version(1))
wsOffer(response)
}
private def wsOffer(msg:Response):Unit = wsQueue.foreach(queue => {
queue.offer(msg).foreach {
case QueueOfferResult.Enqueued ⇒ ()
case QueueOfferResult.Dropped ⇒ ???
case QueueOfferResult.Failure(ex) ⇒ ???
case QueueOfferResult.QueueClosed ⇒ ???
}
})
}