在游戏框架中理解Iteratee

时间:2016-01-09 15:22:58

标签: scala playframework

以下是Play书中的Reactive Web Apps的示例:

package controllers

import play.api._
import play.api.libs.iteratee.Iteratee
import play.api.libs.oauth.{OAuthCalculator, RequestToken, ConsumerKey}
import play.api.Play.current
import play.api.libs.ws.WS
import play.api.mvc._


import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

class Application extends Controller {

  val loggingIteratee = Iteratee.foreach[Array[Byte]] {
    array => Logger.info(array.map(_.toChar).mkString)
  }

  def tweets = Action.async {
    val credentials: Option[(ConsumerKey, RequestToken)] = for {
      apiKey <- Play.configuration.getString("twitter.apiKey")
      apiSecret <- Play.configuration.getString("twitter.apiSecret")
      token <- Play.configuration.getString("twitter.token")
      tokenSecret <- Play.configuration.getString("twitter.tokenSecret")
    } yield (
      ConsumerKey(apiKey, apiSecret),
      RequestToken(token, tokenSecret)
      )
    credentials.map {
      case (consumerKey, requestToken) => WS.url("https://stream.twitter.com/1.1/statuses/filter.json")
          .sign(OAuthCalculator(consumerKey, requestToken))
          .withQueryString("track" -> "cat")
          .get {
            response =>
              Logger.info("Status: " + response.status)
              loggingIteratee
          }
          .map(response => Ok("Stream closed"))
    } getOrElse {
      Future {
        InternalServerError("Twitter credentials missing")
      }
    }
  }

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

}

我很难理解悬挂线:

loggingIteratee

在这种情况下,它似乎记录了关于来自twitter的猫的帖子。但它是如何实现的呢?我们没有传递任何东西。

1 个答案:

答案 0 :(得分:1)

get方法需要响应Iteratee的函数,然后在内部使用它。见文档:

https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.ws.WSRequestHolder

和源代码(此处:https://github.com/playframework/playframework/blob/2.3.x/framework/src/play-ws/src/main/scala/play/api/libs/ws/WS.scala

/**
 * performs a get
 * @param consumer that's handling the response
 */
def get[A](consumer: WSResponseHeaders => Iteratee[Array[Byte], A])(implicit ec: ExecutionContext): Future[Iteratee[Array[Byte], A]] = {
  getStream().flatMap {
    case (response, enumerator) =>
      enumerator(consumer(response))
  }
}

因此它基本上通过此Iteratee

放置每个响应