Akka文档很多,有很多教程。但要么它们已经过时,要么它们只涵盖基础知识(或者,我可能根本找不到合适的基础)。
我想要创建的是一个websocket应用程序,它在服务器端具有多个客户端和多个源。由于我不想从头开始,我想做出一些步骤,逐步增加我正在构建的软件的复杂性。
在完成了一些简单的流程后,我想先从一个更复杂的图开始。
我想要的是:
两个来源,一个将“keepAlive”消息从服务器推送到客户端(目前只有一个),另一个推送实际推送有用数据的消息。
现在第一个我有这个:
val tickingSource: Source[Array[Byte], Cancellable] =
Source.tick(initialDelay = 1 second, interval = 10 seconds, tick = NotUsed)
.zipWithIndex
.map{ case (_, counter) => SomeMessage().toByteArray}
其中SomeMessage
是protobuf类型。
因为我找不到将actor添加为源的最新方法,所以我尝试了以下第二个来源:
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]]
。我想知道:我已经做了一些完全错误的事情吗?
答案 0 :(得分:1)
您需要将secondSourceConverter
传递给GraphDSL.create
,例如以下来自docs的示例。在这里他们导入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
})
答案 1 :(得分:1)
您的图表属于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]]]
答案 2 :(得分:0)
我不确定您希望如何处理传入的消息,但这是一个简单的示例。希望它能帮到你。
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
)
}
}