繁体   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?

我正在玩 Akka Stream/Http 并试图弄清楚如何在 websocket 服务器中执行以下操作(希望不使用 Actor 模式):

1.客户端初始连接请求,握手后,服务器会监听客户端的初始Message ,格式为json
2. 服务器收到TextMessage.Strict后,如果有效,它将丰富Message以构建“谓词”(例如过滤器映射),然后服务器将使用该“谓词”构建Source[Message, _]

我尝试使用handleMessagesWithSinkSource但在我看来这个 API 的意图是独立生成SinkSource (请参阅路由/ws )。 我也尝试使用handleWebSocketMessages (请参阅路由ws/filter ),但对我来说,Flow 中的 Sink(inlet) 和 Source(outlet) 之间没有连接。 我理解Sink在这里应该如何工作一定是错误的:

我的路线:

              (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`...


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 

建立连接后,我希望用户通过以下过滤器发送:

{
 productId: 1,
 city: New York
}

然后服务器应该继续从后端(数据库)实时推送数据流(事件),并将更详细的产品信息返回给用户客户端:

{
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
}
...

Actor是否绝对需要处理这个问题? 如果是这样,任何指导都会非常有帮助!

更新简而言之,如何根据用户的消息发出事件驱动的服务器推送源?

此外,也许我对如何构建新的Source[Message, _]感到困惑? 我知道Flow是不可变的,但应该是一种基于输入( Flow.fromSinkAndSource ?)的切换方式。 因为 Akka 只有指令 api 像: handleWebSocketMessages(flow: Flow[Message, Message, _])它只消耗输入消息,但不产生新的Source ,而对于handleMessagesWithSinkSource(sink, source)接收器和源没有与我的逻辑联系。 我仍在努力思考如何使它工作..

虽然不是很明显,但Flow[Message, Message, _]足以实现大多数协议。 请记住, Flow可以通过statefulMapConcatflatMapConcat Flow甚至可以在没有直接接收到要回复的输入的情况下通过诸如extrapolatemerge之类的功能与某些滴答声源开始发出内容。

在你的情况下:

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