简体   繁体   English

在连接源和接收器之前,等待客户端websocket流连接

[英]Waiting for a client websocket flow to connect before connecting source and sink

I'm using akka-streams to set up a client web socket. 我正在使用akka-streams设置客户端Web套接字。 I'm trying to encapsulate the setup in a method with the following signature: 我正在尝试将安装程序封装在具有以下签名的方法中:

def createConnectedWebSocket(url: String): Flow[Message, Message, _]

It is clear how to create the web socket flow but it is not connected yet: 很明显如何创建Web套接字流,但尚未连接:

val webSocketFlow: Flow[Message, Message, Future[WebSocketUpgradeResponse]] =
    Http().webSocketClientFlow(WebSocketRequest(url))

I first want to Await the upgrade response future and then return the socket flow. 我首先要Await将来的升级响应,然后返回套接字流。 However, in order to get the future, I have to materialize the flow and for that I have to connect a Source and a Sink . 但是,为了获得未来,我必须实现流程,为此必须连接SourceSink But this should be the responsibility of some other adapter class, for instance one that serializes and deserializes json objects and exposes a Flow[JsValue, JsValue, _] . 但这应该由其他适配器类负责,例如,一个适配器类对json对象进行序列化和反序列化,并公开Flow[JsValue, JsValue, _] It should not have to worry about connecting and maybe reconnecting when the connection is lost (this behaviour will be part of a more elaborate version of my method once I manage to write it). 它不必担心连接丢失时可能进行连接,甚至可以重新连接(一旦我设法编写该行为,它将成为我方法的更详细版本的一部分)。 It should only have to deal with a simple Flow . 它只需要处理一个简单的Flow

I managed to achieve part of what I want by using hubs: 通过使用集线器,我设法实现了我想要的一部分:

val mergeHubSource = MergeHub.source[Message](perProducerBufferSize = 16)
val broadcastHubSink = BroadcastHub.sink[Message](bufferSize = 16)

val ((messageSink, upgradeResponse), messageSource) =
  mergeHubSource
    .viaMat(webSocketFlow)(Keep.both)
    .toMat(broadcastHubSink)(Keep.both)
    .run()

So now I have a Source and a Sink that I can combine to a Flow and return it. 所以现在我有了一个Source和一个Sink ,可以将它们组合成一个Flow并返回它。 The problem is, that I am not interested in the hub functionality. 问题是,我对集线器功能不感兴趣。 When I connect a Source to the resulting Flow and close it, this should be propagated to the socket, ie, the socket should close. 当我将Source连接到生成的Flow并将其关闭时,应将其传播到套接字,即套接字应该关闭。 When using a MergeHub it remains open in order to be able to accept new sources. 使用MergeHub它保持打开状态以便能够接受新资源。

Is this possible? 这可能吗? I think I could bridge the gap with custom actors but it feels like I'm reinventing something here that is likely already implemented in another form. 我认为我可以弥合自定义角色之间的鸿沟,但感觉就像我在这里重塑可能已经以另一种形式实现的东西。

I found a solution using SourceRef and SinkRef . 我找到了使用SourceRefSinkRef的解决方案。 Although they are meant to be used to bridge the gap between two machines, they can be used here as well. 尽管它们旨在弥补两台机器之间的差距,但也可以在这里使用它们。

val webSocketFlow: Flow[Message, Message, Future[WebSocketUpgradeResponse]] =
    Http().webSocketClientFlow(WebSocketRequest(someUrl))

val (sinkRefFuture, sourceRefFuture) =
  StreamRefs.sinkRef[In]()
    .viaMat(f)(Keep.left)
    .toMat(StreamRefs.sourceRef[Out]())(Keep.both)
    .run()

val flow = Flow.fromSinkAndSource(await(sinkRefFuture), await(sourceRefFuture))

with await() being defined for instance like this: 像这样定义await()

def await[T, F <: T](f: Future[F]): T = Await.result(f, 3.seconds)

That being said, I figured that it is actually better, at least in my case, not to materialize the socket in advance. 话虽这么说,但我认为,至少在我看来,最好不要预先实现套接字。 This way whoever uses it can also take care of reconnecting. 这样,无论使用它的人,都可以重新连接。 I'm now passing around a flow factory that creates new instances of the web socket Flow (may only me materialized once) on demand. 我现在正在绕过一个流工厂,该工厂可以根据需要创建Web套接字Flow新实例(可能只实现一次)。

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

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