play2让一个Enumeratee转换为另一个Promise中的一个Promise

时间:2012-05-21 16:00:17

标签: scala playframework playframework-2.0 iterate

我正试图在Play 2中使用Iteratees来传输彗星结果。我有把手从回调中创建一个枚举器,从地图创建一个枚举器。 我的问题是使用Enumeratee.map,这需要一个接受纯输入并返回纯输出的函数(例如doc中的String转换为Int)。我想做的是采取纯粹的输入并返回结果的承诺。 毕竟,枚举器向一个枚举者提供promises,一个枚举器将一个枚举器转换为另一个枚举器,因此应该有一种方法可以生成一个映射到promises的枚举器。

现在,让我举一个例子来说明这一点。假设我有一个http请求,其中包含要在我的数据库中查询的ID列表。假设这些id表示数据库表中的行,并且请求对这些行执行一组(长)计算,然后返回一组表示计算的json对象。 由于我一直在阻止要做的事情,所以一次流式传输一个ID会很酷,所以我希望有一个枚举管道:

  1. 查询数据库中的一行(返回行的承诺)
  2. 对行进行长时间计算(接受一行并返回计算的承诺)
  3. 将长计算转换为JSON
  4. &安培;>这是由Play 2提供的Comet enumeratee
  5. 1有点容易,我可以构造一个带有fromCallback的枚举器,它将返回查询结果的承诺。 3也很简单,因为它是一个简单的Enumeratee.map

    但是我无法理解如何实现第2步的枚举的applyOn。我可以理解我已经构建了一个新的iteratee,它从“内部”迭代中获得了承诺,flatMap the long计算并返回新的承诺。我没有得到的是如何在给出奇怪的applyOn签名的情况下做出这个:def applyOn[A](it: Iteratee[To, A]): Iteratee[From, Iteratee[To, A]]

    有人可以帮我吗?

    由于

2 个答案:

答案 0 :(得分:3)

在主Enumeratee.mapM [E]上有一个方法,它取f:E =>承诺[NE]并返回Enumeratee [E,NE]

https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/scala/play/api/libs/iteratee/Enumeratee.scala#L150

答案 1 :(得分:1)

applyOn的签名更有意义,当您认为枚举者与enumerator |>> (enumeratee &> iteratee)中的右侧迭代者结合时。 iteratee的类型为Iteratee[E, A],枚举器需要Iteratee[Promise[E], Iteratee[E, A],以便可以提取内部迭代。因此,applyOn必须为Iteratee[E, A]并返回Iteratee[Promise[E], Iteratee[E, A]

以下是实施的概要。它定义了一个步进函数,它接受输入并返回预期结果。然后以递归方式逐步执行promise元素。

import play.api.libs.concurrent._
import play.api.libs.iteratee._

def unpromise[E]: Enumeratee[Promise[E], E] = new Enumeratee[Promise[E], E] {
  def applyOn[A](inner: Iteratee[E, A]): Iteratee[Promise[E], Iteratee[E, A]] = {
    def step(input: Input[Promise[E]], i: Iteratee[E, A]): Iteratee[Promise[E], Iteratee[E, A]] = {
      input match {
        case Input.EOF => Done(i, Input.EOF)
        case Input.Empty => Cont(step(_, i))
        case Input.El(pe) =>
          val pe2 = pe.map(e => i.feed(Input.El(e))).flatMap(identity)
          val i2 = Iteratee.flatten(pe2)
          i2.pureFlatFold(
            (a, e2) => Done(i2, Input.Empty),
            k => Cont(step(_, i2)),
            (msg, e2) => Done(i2, Input.Empty))
      }
    }
    // should check that inner is not done or error - skipped for clarity
    Cont(step(_, inner))
  }
}

我正在放弃e2,因此可能会有更多代码来确保某些输入不会丢失。