Cet article présente rapidement comment, grâce aux APIs de Twitter, Node.Js et un peu d’html5 (websocket) on peut facilement en quelques lignes de codes monitorer une partie du flux twitter.

Le code présente une application que j’ai mise en ligne sur http://t.mkz.me/. Le code ne marche que si le navigateur supporte les WebSocket (Chrome 5 et +, Firefox 4, IE 9 et Safari 5 je crois, pas sûr ;-) )

Comment ça marche ?

Grace à twitter-node, une bibliothèque node.js, on va se connecter à un flux en streaming de Twitter, en particulier maintenant au flux ‘filter’ auquel on va demander tous les tweets inclus dans une zone géographie donnée. Ensuite, pour chaque websocket ouverte sur le node.js (via la bibliothèque node-websocket-server, que j’ai déjà utilisé dans un précédent article, par des clients (notre navigateur par l’intermédiaire d’un script javascript).

Comment le mettre en place:

On choppe la dernière version de node.js:

$ wget http://nodejs.org/dist/node-v0.2.5.tar.gz
$ tar xfz node-v0.2.5.tar.gz
$ cd node-v0.2.5
$ ./configure ; make ; cd ..
[...]

Mais aussi de node-websocket-server et de twitter-node.

$ git clone https://github.com/miksago/node-websocket-server.git
[...]
$ git clone https://github.com/technoweenie/twitter-node.git
[...]

$ export NODE_PATH=$(pwd)/node-websocket-server/lib:$(pwd)/twitter-node/lib
$

A ce moment, on a besoin du code du serveur. On remprend rapidement l’exemple donné par twitter-node et on l’adapte pour utiliser node-websocket-server. Ca nous donne grosso-modo (Notez qu’il faut modifier le login/password…). Dans l’exemple suivant, on va tracker les tweets postés avec des informations de geoloc aux USA, mais on pourrait aussi utiliser des mots (Le faire sur justin bieber est tout simplement royal à suivre):

// server.js
var TwitterNode = require('twitter-node').TwitterNode;
var ws          = require('ws/server');
var http        = require('http');
var sys         = require('sys');

var twit = new TwitterNode({
  user: 'twitter login',
  password: 'twitter password',
  // http://www.findlatitudeandlongitude.com/
  // SW,NE (long, lat, long, lat)
  // France:
  // locations: [ 1.40, 48.2, 3.56, 49.3 ]
  // Europe:
  //locations: [ -12, 36.1, 27.3, 62.44 ]
  // USA:
  locations: [ -170, 24.3, -44, 71 ]
  // on peut aussi tracker des mots:
  //  track: ['bieber', 'justin', 'justinbieber']
});

// L'action est 'filter'. On peut aussi mettre 'sample', etc.
twit.action = 'filter';

twit.addListener('error', function(error) {
  console.log(error.message);
  sys.puts(error.message);
});

// server http pour la websocket
var httpServer = http.createServer(function(req, res){});

// websocket
var server = ws.createServer({
  debug: false
}, httpServer);

server.addListener("connection", function(socket){

    // Fonction qui va nous servir pour envoyer chaque tweet:
    var func = function(tweet) {
        try {
            socket.write(JSON.stringify(tweet));
        }
        catch (e) {
            sys.puts("Socket write error");
        }
    };

    // Evenement qui va avoir lieu a chaque reception d'un tweet.
    twit.addListener('tweet', func);

    socket.addListener("end", function () {
        sys.puts("socket end");
        twit.removeListener('tweet', func);
        socket.end();
    });
});

// On lance le serveur. On notera qu'on le lance sur le port 8001.
server.listen(8001);

// On lance le flux
twit.stream();

sys.puts("Hi world.");

On n’a qu’à le lancer dans le shell:

$ ./node-v0.2.5/node server.js
Hi world.

A ce moment, il nous manque juste le code du client. Un peu d’HTML, on choppe jquery au passage et ça nous donne:

<!-- index.php -->
<html>
<head>
<script src="jquery-1.4.4.min.js" type="text/javascript"></script>
<script type="text/javascript">

$(document).ready(function(){
    // La websocket que l'on stocke "globalement"
    var ws;
    var num_tweet;

    if ("WebSocket" in window) {
        // Ou connecter la websocket (serveur node.js)
        ws = new WebSocket("ws://t.mkz.me:8001/service");

        ws.onopen = function() {};

        ws.onmessage = function (evt) {
            // Quand on recoit un message du serveur...:
            var received_msg = evt.data;
            var tweet = JSON.parse(evt.data);
            var content = tweet.text;
            num_tweet = num_tweet + 1;

            // A chaque tweet on l'affiche:
            if( ! tweet.retweeted_status )
            {
                $('#flux ul').prepend('<li><b>' + tweet.user.screen_name + '</b>: ' + content + '</li>');
                $('#flux ul li').slice(30).remove();
            }
            else
            {
                $('#rt ul').prepend('<li><b>' + tweet.user.screen_name + '</b>: ' + content + '</li>');
                $('#rt ul li').slice(10).remove();
            }

            $('#counter').text( num_tweet + ' tweets' );
        };

        ws.onclose = function() {};
    } else {
        // Pas de support WebSocket.
        $('#flux').append('You need a browser with websocket');
    }
});
</script>
</head>
<body>

<h2>Last tweet</h2>
<span id='counter'></span>
<div id='flux'>
<ul></ul>
</div>

<h2>Last RT</h2>
<div id='rt'>
<ul></ul>
</div>

</body>
</html>

Et voilà le résultat: http://t.mkz.me/.