Scala Playframework和Twitter流媒体API

Scala Playframework和Twitter流媒体API,scala,twitter,playframework,twitter-streaming-api,playframework-2.5,Scala,Twitter,Playframework,Twitter Streaming Api,Playframework 2.5,如何从Twitter流式API读取响应数据-发布状态/过滤器? 我已经建立了连接,收到200个状态码,但我不知道如何阅读推文。我只想在他们来的时候打印推文 ws.url(url) .sign(OAuthCalculator(consumerKey, requestToken)) .withMethod("POST") .stream() .map { response => if(response.headers.status == 200) println(response.

如何从Twitter流式API读取响应数据-发布状态/过滤器? 我已经建立了连接,收到200个状态码,但我不知道如何阅读推文。我只想在他们来的时候打印推文

ws.url(url)
.sign(OAuthCalculator(consumerKey, requestToken))
.withMethod("POST")
.stream()
.map { response =>
  if(response.headers.status == 200)
    println(response.body)
} 
编辑:我找到了这个解决方案

ws.url(url)
.sign(OAuthCalculator(consumerKey, requestToken))
.withMethod("POST")
.stream()
.map { response => 
  if(response.headers.status == 200){
    response.body
      .scan("")((acc, curr) => if (acc.contains("\r\n")) curr.utf8String else acc + curr.utf8String)
      .filter(_.contains("\r\n"))
      .map(json => Try(parse(json).extract[Tweet]))
      .runForeach {
        case Success(tweet) =>
          println("-----")
          println(tweet.text)
        case Failure(e) =>
          println("-----")
          println(e.getStackTrace)
      }
  }
}
调用
stream()。然后,您必须使用akka习惯用法来转换其中的
ByteString
块。比如:

val stream = ws.url(url)
  .sign(OAuthCalculator(consumerKey, requestToken))
  .withMethod("POST")
  .stream()

stream flatMap { res =>
  res.body.runWith(Sink.foreach[ByteString] { bytes =>
    println(bytes.utf8String)
  })
}
注意,我没有测试上面的代码(但它基于的流式响应部分加上来自的接收器描述)


还要注意,这将在其自己的行上打印每个块,我不确定twitterapi是否会返回每个块的完整json blob。如果要在打印块之前累积块,可能需要使用
接收器。折叠

流式WS请求的响应主体是Akka字节流。由于TwitterAPI响应是新行分隔的(通常),您可以使用它将它们拆分为字节块,将这些块解析为JSON,然后对它们执行您想要的操作。像这样的方法应该会奏效:

import akka.stream.scaladsl.Framing
import scala.util.{Success, Try}
import akka.util.ByteString
import play.api.libs.json.{JsSuccess, Json, Reads}
import play.api.libs.oauth.{ConsumerKey, OAuthCalculator, RequestToken}

case class Tweet(id: Long, text: String)
object Tweet {
  implicit val reads: Reads[Tweet] = Json.reads[Tweet]
}

def twitter = Action.async { implicit request =>
  ws.url("https://stream.twitter.com/1.1/statuses/filter.json?track=Rio2016")
      .sign(OAuthCalculator(consumerKey, requestToken))
      .withMethod("POST")
      .stream().flatMap { response =>
    response.body
      // Split up the byte stream into delimited chunks. Note
      // that the chunks are quite big
      .via(Framing.delimiter(ByteString.fromString("\n"), 20000))
      // Parse the chunks into JSON, and then to a Tweet.
      // A better parsing strategy would be to account for all
      // the different possible responses, but here we just
      // collect those that match a Tweet.
      .map(bytes => Try(Json.parse(bytes.toArray).validate[Tweet]))
      .collect {
        case Success(JsSuccess(tweet, _)) => tweet.text
      }
      // Print out each chunk
      .runForeach(println).map { _ =>
        Ok("done")
    }
  }
}

注意:要具体化流,需要将隐式
物化器
注入控制器

谢谢你的解释,有可能以后再联系吗?我计划有多个跟踪不同单词的请求,我希望在将来的某个时间密切特定的连接?看看Akka文档中的a。一个想法是:创建一个共享kill开关,然后使用
source.via(killSwitch.flow)
将其添加到流中。在killswitch上运行
shutdown()
应该会关闭连接。因此,我已经通过(sharedKillSwitch.flow)将我的WS-stream请求添加到源(stream(request))。但在killswitch上运行shutdown()时,连接仍然打开