I made something similar a while back, i used websockets to push the updates to the browser and Akka actors to handle the status listener. The controller can then request a stream (Enumerator) from an actor and return it as a websocket.
2) Websocket is the most efficient but not compatible with older browsers, if you need better browser compatibility then use comet
I've modified the code to show a very simple example
Controller:
object Application extends Controller {
implicit val timeout = Timeout(1 second)
val cb = new ConfigurationBuilder()
cb.setDebugEnabled(true)
.setOAuthConsumerKey("")
.setOAuthConsumerSecret("")
.setOAuthAccessToken("")
.setOAuthAccessTokenSecret("")
val twitterListener = Akka.system.actorOf(TwitterListener.props(cb.build()))
def join = WebSocket.async[JsValue] { request =>
(twitterListener ? RequestStream()).mapTo[Connected].map {
case Connected(stream) => (Iteratee.ignore, stream)
}
}
}
Actor:
object TwitterListener {
case class RequestStream()
case class Connected(numerator: Enumerator[JsValue])
def props(conf: Configuration) = Props(new TwitterListener(conf))
}
/**
* Twitter Stream Listener
*
* @param config Twitter4j Configuration
*/
class TwitterListener(config: Configuration) extends Actor {
import TwitterListener._
val listener = new StatusListener() {
val (enum, channel) = Concurrent.broadcast[JsValue]
def onStatus(status: Status) {
channel.push(Json.obj(
"msg" -> status.getText,
"user" -> status.getUser.getName,
"timestamp" -> DateTime.now.toString("yyyy-MM-dd HH:mm:ss")
))
}
def onDeletionNotice(statusDeletionNotice: StatusDeletionNotice) {
}
def onTrackLimitationNotice(numberOfLimitedStatuses: Int) {
}
def onException(ex: Exception) {
ex.printStackTrace()
}
def onScrubGeo(userId: Long, upToStatusId: Long) = {
}
def onStallWarning(warning: StallWarning) = {
}
}
override def preStart() = {
val query = new FilterQuery(0, Array(), Array("birthday"))
val twitterStream = new TwitterStreamFactory(config).getInstance
twitterStream.addListener(listener)
twitterStream.filter(query)
}
def receive = {
case RequestStream() => sender ! Connected(listener.enum)
}
}