简体   繁体   English

Akka HTTP WebSocket Server 构建消息处理流时如何根据 Sink 内容声明 Source?

[英]Akka HTTP WebSocket Server How to declare Source based on Sink content when building Flow for message handlement?

I am playing around with Akka Stream/Http and trying to figure out how to do the following thing in a websocket server (hopefully without using Actor pattern):我正在玩 Akka Stream/Http 并试图弄清楚如何在 websocket 服务器中执行以下操作(希望不使用 Actor 模式):

1. At initial connection request from client, after the handshake, server will listen to client's initial Message in json format. 1.客户端初始连接请求,握手后,服务器会监听客户端的初始Message ,格式为json
2. After server received the TextMessage.Strict and if valid it will enrich the Message to build a "Predicate" (eg. a filter map), Then the server will use that "Predicate" to build a Source[Message, _] . 2. 服务器收到TextMessage.Strict后,如果有效,它将丰富Message以构建“谓词”(例如过滤器映射),然后服务器将使用该“谓词”构建Source[Message, _]

I tried using handleMessagesWithSinkSource but it seems to me this API's intend is for out-generating Sink and Source independently(see route /ws ).我尝试使用handleMessagesWithSinkSource但在我看来这个 API 的意图是独立生成SinkSource (请参阅路由/ws )。 I also tried using handleWebSocketMessages (see route ws/filter ), but to me there is no connection between Sink(inlet) and Source(outlet) in the Flow.我也尝试使用handleWebSocketMessages (请参阅路由ws/filter ),但对我来说,Flow 中的 Sink(inlet) 和 Source(outlet) 之间没有连接。 I must be wrong in understanding how Sink should work here:我理解Sink在这里应该如何工作一定是错误的:

my route:我的路线:

              (path("ws") & get & pathEndOrSingleSlash) {
                extractUpgradeToWebSocket { upgrade =>
                  complete(upgrade.handleMessagesWithSinkSource(Sink.ignore,
                    getSourceAll)
                } // this route is working fine, pushing all event Messages to client once connected 
              } ~
              (path("ws" / "filter") & get & pathEndOrSingleSlash) {
                handleWebSocketMessages(getSourceFiltered) 
              } // this route I cannot figure out a way to build `Flow` dynamically based on `Sink`...


idea of getSourceAll and getSourceFiltered getSourceAllgetSourceFiltered的想法

val getSourceAll: Source[Message, NotUsed] = ??? // Stream source genereating Messages based on backend event

val getSourceFiltered: Flow[Message, Message, _] = ??? // the outgoing Source should push Server event messages based on client's "Predicate" message 

After the connection being established, I would expect user send over filter like:建立连接后,我希望用户通过以下过滤器发送:

{
 productId: 1,
 city: New York
}

Then the server should keep pushing data stream(event) in realtime from backend(database) with more detailed product info back to user client:然后服务器应该继续从后端(数据库)实时推送数据流(事件),并将更详细的产品信息返回给用户客户端:

{
orderId: 1122,
productId: 1,
productName: Coke,
vendor: ABC,
city: New York
timestamp: 2019-11-13 09:30:00
}
{
orderId: 3322,
productId: 1,
productName: Coke,
vendor: EFG,
city: New York
timestamp: 2019-11-13 09:31:00
}
...

Is Actor absolutely required to handle this? Actor是否绝对需要处理这个问题? if so, any guidance would be really helpful!如果是这样,任何指导都会非常有帮助!

Update In short, how can I emit an event-driven server-push Source based on user's Message?更新简而言之,如何根据用户的消息发出事件驱动的服务器推送源?

Additionally, maybe I am confused on how to build a new Source[Message, _] ?此外,也许我对如何构建新的Source[Message, _]感到困惑? I know Flow is immutable but should be a way to switch based on input( Flow.fromSinkAndSource ?).我知道Flow是不可变的,但应该是一种基于输入( Flow.fromSinkAndSource ?)的切换方式。 Because Akka only has directive api like: handleWebSocketMessages(flow: Flow[Message, Message, _]) which only consume the input message, but not produce a new Source and as for handleMessagesWithSinkSource(sink, source) the sink and source does not have logical connection to me.因为 Akka 只有指令 api 像: handleWebSocketMessages(flow: Flow[Message, Message, _])它只消耗输入消息,但不产生新的Source ,而对于handleMessagesWithSinkSource(sink, source)接收器和源没有与我的逻辑联系。 I am still trying to wrap my head around how to make it work..我仍在努力思考如何使它工作..

Although it isn't immediately obvious, Flow[Message, Message, _] is enough for implementing most protocols.虽然不是很明显,但Flow[Message, Message, _]足以实现大多数协议。 Remember that a Flow can build up almost arbitrary amounts of state via functions like statefulMapConcat or flatMapConcat .请记住, Flow可以通过statefulMapConcatflatMapConcat A Flow can even start emitting stuff without having directly received an input to reply to via functions like extrapolate or merge -ing with some ticking source. Flow甚至可以在没有直接接收到要回复的输入的情况下通过诸如extrapolatemerge之类的功能与某些滴答声源开始发出内容。

In your case:在你的情况下:

val getSourceFiltered: Flow[Message, Message, _] = Flow[Message]
  .take(1)  // you only care about the first thing that the client sends 
  .flatMapConcat {
    case TextMessage.Strict(txtMsg: String) =>

      // Here is where you parse and make your filter using the message the client message
      val clientFilter: Message => Boolean = makeFilter(txtMsg)
      getSourceAll.filter(clientFilter)


    case _ => Source.single(TextMessage("Expected a single strict JSON message"))
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM