[英]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
. 但是,为了获得未来,我必须实现流程,为此必须连接
Source
和Sink
。 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
. 我找到了使用
SourceRef
和SinkRef
的解决方案。 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.