我正在使用akka-streams来设置客户端Web套接字。我正在尝试将设置封装在具有以下签名的方法中:
def createConnectedWebSocket(url: String): Flow[Message, Message, _]
很明显如何创建Web套接字流但尚未连接:
val webSocketFlow: Flow[Message, Message, Future[WebSocketUpgradeResponse]] =
Http().webSocketClientFlow(WebSocketRequest(url))
我首先想要Await
升级响应,然后返回套接字流。但是,为了获得未来,我必须实现流程,因此我必须连接Source
和Sink
。但这应该是其他一些适配器类的责任,例如,对json对象进行序列化和反序列化并公开Flow[JsValue, JsValue, _]
的类。当连接丢失时,它不应该担心连接和重新连接(一旦我设法编写它,这种行为将成为我的方法的更精细版本的一部分)。它应该只需处理一个简单的Flow
。
我设法通过使用集线器来实现我想要的一部分:
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()
所以现在我有一个Source
和一个Sink
我可以合并到Flow
并返回它。问题是,我对集线器功能不感兴趣。当我将Source
连接到生成的Flow
并关闭它时,应该将其传播到套接字,即套接字应该关闭。使用MergeHub
时,它会保持打开状态,以便能够接受新来源。
这可能吗?我想我可以弥合与自定义演员的差距,但感觉我在这里重新发明了一些可能已经以另一种形式实现的东西。
答案 0 :(得分:0)
我找到了使用SourceRef
和SinkRef
的解决方案。虽然它们用于弥合两台机器之间的差距,但也可以在这里使用它们。
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))
正在定义await()
,例如:
def await[T, F <: T](f: Future[F]): T = Await.result(f, 3.seconds)
话虽这么说,我认为实际上更好,至少在我的情况下,不提前实现套接字。这样使用它的人也可以负责重新连接。我现在正在传递一个流工厂,它根据需要创建Web套接字Flow
的新实例(可能只实现了一次)。