Skip to content

Instantly share code, notes, and snippets.

@nicmarti
Created April 8, 2014 16:59
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nicmarti/10156051 to your computer and use it in GitHub Desktop.
Save nicmarti/10156051 to your computer and use it in GitHub Desktop.
/*
* The MIT License (MIT)
*
* Copyright (c) 2013 Association du Paris Java User Group.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package controllers
import scala.concurrent._
import ExecutionContext.Implicits.global
import play.api.libs.iteratee._
import play.api.libs.json._
import play.api.libs.functional.syntax._
import play.api.libs.json.Reads._
import play.api.libs.ws._
import play.api.libs.oauth._
import play.api.mvc._
import play.api.libs._
import play.api.libs.iteratee._
import play.Play
import java.net.URLEncoder
import play.api.libs.oauth.OAuth
import play.api.libs.oauth.ServiceInfo
import play.api.libs.oauth.RequestToken
import play.api.libs.oauth.OAuthCalculator
import play.api.libs.oauth.ConsumerKey
/**
* Tweet wall, using new Twitter Stream API.
*
* Created by nmartignole on 03/04/2014.
*/
object Tweetwall extends Controller {
val cfg = Play.application.configuration
// Set your Twitter key in your application.conf
val KEY = ConsumerKey(cfg.getString("twitter.consumerKey"), cfg.getString("twitter.consumerSecret"))
val TWITTER = OAuth(ServiceInfo(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize", KEY),
use10a = false)
def index = Action {
implicit request =>
request.session.get("token").map {
token: String =>
Ok(views.html.Tweetwall.wallDevoxxFR2014()) // yes ma biche, c'est pour Devoxx France
}.getOrElse {
Redirect(routes.Tweetwall.authenticate)
}
}
def authenticate = Action {
implicit request =>
request.queryString.get("oauth_verifier").flatMap(_.headOption).map {
verifier =>
val tokenPair = sessionTokenPair(request).get
// We got the verifier; now get the access token, store it and back to index
TWITTER.retrieveAccessToken(tokenPair, verifier) match {
case Right(t) => {
// We received the unauthorized tokens in the OAuth object - store it before we proceed
Redirect(routes.Tweetwall.index).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
}
}.getOrElse(
TWITTER.retrieveRequestToken(routes.Tweetwall.authenticate.absoluteURL()) match {
case Right(t) => {
// We received the unauthorized tokens in the OAuth object - store it before we proceed
Redirect(TWITTER.redirectUrl(t.token)).withSession("token" -> t.token, "secret" -> t.secret)
}
case Left(e) => throw e
})
}
// Ce code, tres simple quand on le voit comme ça, fait revenir l'etre aimé, repousser les cheveux et aussi
// peut streamer directement Twitter
def watchTweets(keywords: String) = Action {
implicit request =>
val (tweetsOut, tweetChanel) = Concurrent.broadcast[JsValue]
// See Twitter parameters doc https://dev.twitter.com/docs/streaming-apis/parameters
WS.url(s"https://stream.twitter.com/1.1/statuses/filter.json?stall_warnings=true&filter_level=none&track=" + URLEncoder.encode(keywords, "UTF-8"))
.withRequestTimeout(-1) // Connected forever
.sign(OAuthCalculator(KEY, sessionTokenPair.get))
.withHeaders("Connection" -> "keep-alive")
.postAndRetrieveStream("")(headers => Iteratee.foreach[Array[Byte]] {
ba =>
val msg = new String(ba, "UTF-8")
val tweet = Json.parse(msg)
tweetChanel.push(tweet)
}).flatMap(_.run)
// Je suis plus un fan d'Event-Source, bien que cela marche pas avec IE
// Voir la référence ici http://caniuse.com/#feat=eventsource
Ok.feed(tweetsOut &> EventSource()).as("text/event-stream")
}
def sessionTokenPair(implicit request: RequestHeader): Option[RequestToken] = {
for {
token <- request.session.get("token")
secret <- request.session.get("secret")
} yield {
RequestToken(token, secret)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment