Akka-stream并将处理委托给演员

时间:2016-02-05 05:33:46

标签: akka akka-stream akka-http

我有以下情况,我试图将处理委托给演员。我想要发生的是,每当我的流处理消息时,它都会将它发送给actor,并且actor会将其大写并将其作为响应写入流中。

所以我应该能够连接到端口8000,键入" hello",让流程将它发送给actor,并让actor将它发布回流中,这样它就可以了回复给我大写。演员本身非常基本,来自docs中的ActorPublisher示例。

我知道这段代码不起作用,我清理了我的实验以使其编译。现在,它只是两个独立的流。我尝试合并源或接收器,但没有用。

object Sample  {
  def main(args: Array[String]): Unit = {
    implicit val system = ActorSystem("sample")
    implicit val materializer = ActorMaterializer()

    val connections: Source[IncomingConnection, 
        Future[ServerBinding]] = Tcp().bind("localhost", 8000)
    val filter = Source.actorPublisher[ByteString](Props[Filter])

    val filterRef = Flow[ByteString]
      .to(Sink.ignore)
      .runWith(filter)

    connections runForeach { conn =>
      val echo = Flow[ByteString] .map {


        // would like to send 'p' to the actor, 
        // and have it publish to the stream
        case p:ByteString => filterRef ! p
      }
    }
  }
}

// this actor is supposed to simply uppercase all 
// input and write it to the stream
class Filter extends ActorPublisher[ByteString] with Actor
{
  var buf = Vector.empty[ByteString]
  val delay = 0

  def receive = {
    case p: ByteString =>
      if (buf.isEmpty && totalDemand > 0)
        onNext(p)
      else {
        buf :+= ByteString(p.utf8String.toUpperCase)
        deliverBuf()
      }
    case Request(_) =>
      deliverBuf()
    case Cancel =>
      context.stop(self)
  }


   @tailrec final def deliverBuf(): Unit =
    if (totalDemand > 0) {
      if (totalDemand <= Int.MaxValue) {
        val (use, keep) = buf.splitAt(totalDemand.toInt)
        buf = keep
        use foreach onNext
      } else {
        val (use, keep) = buf.splitAt(Int.MaxValue)
        buf = keep
        use foreach onNext
        deliverBuf()
      }
    }
}

1 个答案:

答案 0 :(得分:1)

我之前也遇到过这个问题,以一种迂回的方式解决了这个问题,希望你能用这种方式解决问题。本质上,它涉及创建一个接收器,立即将它获得的消息转发给src actor。

当然,你可以使用直接流程(注释掉它),但我想这不是本练习的重点:)

object Sample  {
  def main(args: Array[String]): Unit = {
    implicit val system = ActorSystem("sample")
    implicit val materializer = ActorMaterializer()

    val connections: Source[IncomingConnection,
      Future[ServerBinding]] = Tcp().bind("localhost", 8000)

    def filterProps = Props[Filter]

    connections runForeach { conn =>
      val actorRef = system.actorOf(filterProps)
      val snk = Sink.foreach[ByteString]{s => actorRef ! s}
      val src = Source.fromPublisher(ActorPublisher[ByteString](actorRef))
      conn.handleWith(Flow.fromSinkAndSource(snk, src))

//      conn.handleWith(Flow[ByteString].map(s => ByteString(s.utf8String.toUpperCase())))
    }
  }
}

// this actor is supposed to simply uppercase all
// input and write it to the stream
class Filter extends ActorPublisher[ByteString]
{
  import akka.stream.actor.ActorPublisherMessage._
  var buf = mutable.Queue.empty[String]
  val delay = 0

  def receive = {
    case p: ByteString =>
      buf += p.utf8String.toUpperCase
      deliverBuf()
    case Request(n) =>
      deliverBuf()
    case Cancel =>
      context.stop(self)
  }

  def deliverBuf(): Unit = {
    while (totalDemand > 0 && buf.nonEmpty) {
      val s = ByteString(buf.dequeue() + "\n")
      onNext(s)
    }
  }