Scala 合并和广播,构建(简单的)Akka图
Akka文档非常丰富,有很多教程。但要么它们过时了,要么它们只涵盖了基本内容(或者,也许我就是找不到合适的) 我想创建一个websocket应用程序,在服务器端有多个客户端和多个源。因为我不想从一开始就不知所措,所以我想迈出一小步,逐步增加我正在构建的软件的复杂性 在玩弄了一些简单的流之后,我现在想从一个更复杂的图开始 我想要的是: 两个源,一个用于将“keepAlive”消息从服务器推送到客户端(目前只有一个),另一个用于实际推送有用数据 现在我有了第一个:Scala 合并和广播,构建(简单的)Akka图,scala,akka,Scala,Akka,Akka文档非常丰富,有很多教程。但要么它们过时了,要么它们只涵盖了基本内容(或者,也许我就是找不到合适的) 我想创建一个websocket应用程序,在服务器端有多个客户端和多个源。因为我不想从一开始就不知所措,所以我想迈出一小步,逐步增加我正在构建的软件的复杂性 在玩弄了一些简单的流之后,我现在想从一个更复杂的图开始 我想要的是: 两个源,一个用于将“keepAlive”消息从服务器推送到客户端(目前只有一个),另一个用于实际推送有用数据 现在我有了第一个: val tickingSource
val tickingSource: Source[Array[Byte], Cancellable] =
Source.tick(initialDelay = 1 second, interval = 10 seconds, tick = NotUsed)
.zipWithIndex
.map{ case (_, counter) => SomeMessage().toByteArray}
其中,SomeMessage
是protobuf类型
因为我找不到添加演员作为源的最新方法,所以我在第二个源中尝试了以下方法:
val secondSource = Source(1 to 1000)
val secondSourceConverter = Flow[Int].map(x => BigInteger.valueOf(x).toByteArray)
我对图表的尝试:
val g: RunnableGraph[NotUsed] = RunnableGraph.fromGraph(GraphDSL.create()
{
implicit builder =>
import GraphDSL.Implicits._
val sourceMerge = builder.add(Merge[Array[Byte]](2).named("sourceMerge"))
val x = Source(1 to 1000)
val y = Flow[Int].map(x => BigInteger.valueOf(x).toByteArray)
val out = Sink.ignore
tickingSource ~> sourceMerge ~> out
x ~> y ~> sourceMerge
ClosedShape
})
现在
g
属于RunnableGraph[NotUsed]
类型,而对于我的websocket,它应该是RunnableGraph[Array[Byte]]
。我想知道:我是否已经做了一些完全错误的事情?我不确定您希望如何处理传入的消息,但这里有一个简单的示例。希望它能帮助你
path("ws") {
extractUpgradeToWebSocket { upgrade =>
complete {
import scala.concurrent.duration._
val tickSource = Source.tick(1.second, 1.second, TextMessage("ping"))
val messagesSource = Source.queue(10, OverflowStrategy.backpressure)
messagesSource.mapMaterializedValue { queue =>
//do something with out queue
//like myHandler ! RegisterOutQueue(queue)
}
val sink = Sink.ignore
val source = tickSource.merge(messagesSource)
upgrade.handleMessagesWithSinkSource(
inSink = sink,
outSource = source
)
}
}
您需要将
secondSourceConverter
传递到GraphDSL.create
中,如下面的示例所示。在这里,他们导入了2个接收器,但这是相同的技术
RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((_, _)) { implicit builder =>
(topHS, bottomHS) =>
import GraphDSL.Implicits._
val broadcast = builder.add(Broadcast[Int](2))
Source.single(1) ~> broadcast.in
broadcast.out(0) ~> sharedDoubler ~> topHS.in
broadcast.out(1) ~> sharedDoubler ~> bottomHS.in
ClosedShape
})
您的图形属于
RunnableGraph[NotUsed]
类型,因为您正在使用Sink.ignore
。您可能需要一个RunnableGraph[Future[Array[Byte]]]
而不是RunnableGraph[Array[Byte]]
:
val byteSink = Sink.fold[Array[Byte], Array[Byte]](Array[Byte]())(_ ++ _)
val g = RunnableGraph.fromGraph(GraphDSL.create(byteSink) { implicit builder => bSink =>
import GraphDSL.Implicits._
val sourceMerge = builder.add(Merge[Array[Byte]](2))
tickingSource ~> sourceMerge ~> bSink.in
secondSource ~> secondSourceConverter ~> sourceMerge
ClosedShape
})
// RunnableGraph[Future[Array[Byte]]]
Source.queue帮助我替换了我的参与者源。@kardapoltsev如何将对源的引用传递给参与者?你的答案与此无关。他在询问如何构建一个图表,你在展示如何使用Akka HTTP。实际上,
mapMaterializedValue
返回一个新的源代码。但是非常感谢:)仍然可以得到一个RunnableGraph[(可取消,不使用)]
:(请发布一个示例。