tweetcast/nodejs-bis/tweetcast.js
changeset 404 89968844eb7d
parent 403 dd1686ae5506
child 405 6626b728b142
equal deleted inserted replaced
403:dd1686ae5506 404:89968844eb7d
     1 READ_OLD_TWEETS = true;
       
     2 RECORD_NEW_TWEETS = true;
       
     3 var conf_file = flagOption('-c', 'conf.js');
       
     4 console.log('Reading Configuration from ' + conf_file);
       
     5 var fs = require('fs');
       
     6 eval(fs.readFileSync(conf_file,'utf8'));
       
     7 
       
     8 tweet_file = flagOption('-f', (typeof tweet_file == "undefined" ? 'tweets.txt' : tweet_file ));
       
     9 tracking_keyword = flagOption('-t', (typeof tracking_keywords == "undefined" ? null : tracking_keywords.join(",") ));
       
    10 user_pass = flagOption('-u', (typeof user_pass == "undefined" ? null : user_pass ));
       
    11 
       
    12 if (!user_pass) {
       
    13     console.log("You must provide user credentials in " + conf_file + " or on the command-line, e.g. node tweetcast.js -u user:pass")
       
    14     process.exit();
       
    15 }
       
    16 if (!tracking_keyword) {
       
    17     console.log("You must provide keyword(s) in " + conf_file + " or on the command-line, e.g. node tweetcast.js -t Bieber")
       
    18     process.exit();
       
    19 }
       
    20 
       
    21 console.log("Tracking keyword "+tracking_keyword);
       
    22 
       
    23 var http = require('http'),
       
    24     https = require('https'),
       
    25     socketio = require('socket.io'),
       
    26     app = http.createServer(httpHandler),
       
    27     io = socketio.listen(app)
       
    28     tweets = [],
       
    29     tweet_ids = [],
       
    30     keys_to_delete = [
       
    31         'in_reply_to_screen_name',
       
    32         'in_reply_to_user_id',
       
    33         'retweeted',
       
    34         'place',
       
    35         'geo',
       
    36         'source',
       
    37         'contributors',
       
    38         'coordinates',
       
    39         'retweet_count',
       
    40         'favorited',
       
    41         'truncated',
       
    42         'possibly_sensitive'
       
    43     ],
       
    44     user_keys_to_delete = [
       
    45         'default_profile_image',
       
    46         'show_all_inline_media',
       
    47         'contributors_enabled',
       
    48         'profile_sidebar_fill_color',
       
    49         'created_at',
       
    50         'lang',
       
    51         'time_zone',
       
    52         'profile_sidebar_border_color',
       
    53         'follow_request_sent',
       
    54         'profile_background_image_url',
       
    55         'profile_background_image_url_https',
       
    56         'followers_count',
       
    57         'description',
       
    58         'url',
       
    59         'geo_enabled',
       
    60         'profile_use_background_image',
       
    61         'default_profile',
       
    62         'following',
       
    63         'profile_text_color',
       
    64         'is_translator',
       
    65         'favourites_count',
       
    66         'listed_count',
       
    67         'friends_count',
       
    68         'profile_link_color',
       
    69         'protected',
       
    70         'location',
       
    71         'notifications',
       
    72         'profile_image_url_https',
       
    73         'statuses_count',
       
    74         'verified',
       
    75         'profile_background_color',
       
    76         'profile_background_tile',
       
    77         'utc_offset'
       
    78     ],
       
    79     content_types = {
       
    80         css : "text/css; charset=utf-8",
       
    81         html : "text/html; charset=utf-8",
       
    82         js : "text/javascript; charset=utf-8",
       
    83         png : "image/png"
       
    84     };
       
    85 
       
    86 function httpHandler(req, res) {
       
    87     console.log("HTTP Request for URL "+req.url);
       
    88     var url = req.url.split('?')[0];
       
    89     url = ( url == "/config.js" ? conf_file : __dirname + "/client" + url + ( url[url.length - 1] == "/" ? "index.html" : "" ) );
       
    90     var ext = url.split('.').slice(-1)[0].toLowerCase();
       
    91     fs.readFile( url, function(err, data) {
       
    92         if (err) {
       
    93             console.log("Error 404");
       
    94             res.writeHead(404);
       
    95             return res.end('File not found');
       
    96         }
       
    97         res.writeHead(200, {
       
    98             "Content-Type" : ( content_types[ext] ? content_types[ext] : 'text/plain' )
       
    99         });
       
   100         res.end(data);
       
   101     });
       
   102 }
       
   103 
       
   104 function flagOption(flag, defaultValue) {
       
   105     var flagPos = process.argv.indexOf(flag);
       
   106     return ( flagPos != -1 && flagPos < process.argv.length - 1) ? process.argv[flagPos + 1] : defaultValue;
       
   107 }
       
   108 
       
   109 function addToList(tweet) {
       
   110     if (tweet_ids.indexOf(tweet.id) != -1) {
       
   111         console.log("Error: Tweet already in list");
       
   112         return false;
       
   113     }
       
   114     tweets.push(tweet);
       
   115     tweet_ids.push(tweet.id);
       
   116     return true;
       
   117 }
       
   118 
       
   119 function textids(object) {
       
   120     for (var key in object) {
       
   121         // Workaround for Unicode bug in socket.io.
       
   122         
       
   123         if (typeof object[key] == "string") {
       
   124             var tmp = '';
       
   125             for (var i = 0; i < object[key].length; i++) {
       
   126                 tmp += ( object[key].charCodeAt(i) < 128 ? object[key].charAt(i) : "&#" + object[key].charCodeAt(i) + ";" );
       
   127             }
       
   128             object[key] = tmp;
       
   129         }
       
   130         if (key.substr(-2) == 'id') {
       
   131             object[key] = object[key + '_str'];
       
   132             delete object[key + '_str'];
       
   133         }
       
   134     }
       
   135 }
       
   136 
       
   137 function readTweetsFromFile(file_name) {
       
   138     console.log("Trying to read tweets from " + file_name);
       
   139     try {
       
   140         var oldtweets = fs.readFileSync(file_name, 'utf8').split('\n');
       
   141         var tweetscopied = 0;
       
   142         for (var i in oldtweets) {
       
   143             if (oldtweets[i].length > 0) {
       
   144                 addToList(JSON.parse(oldtweets[i]));
       
   145                 tweetscopied++;
       
   146             }
       
   147         }
       
   148         console.log(tweetscopied + " tweets copied");
       
   149     }
       
   150     catch (err) {
       
   151         console.log("Error opening "+file_name);
       
   152     }
       
   153 }
       
   154 
       
   155 function requestTweets() {
       
   156     console.log("Fetching tweets from https://stream.twitter.com/1/statuses/filter.json")
       
   157     var writestream = null;
       
   158     var req = https.request({
       
   159         host: "stream.twitter.com",
       
   160         path: "/1/statuses/filter.json",
       
   161         method: "POST",
       
   162         headers: {
       
   163             'Authorization': 'Basic ' + new Buffer( user_pass ).toString('base64'),
       
   164             'Content-Type': 'application/x-www-form-urlencoded'
       
   165         }
       
   166     }, function(res) {
       
   167         writestream = fs.createWriteStream( tweet_file, { flags: 'a+', encoding: 'utf-8' } );
       
   168         console.log('Response received, status : ' + res.statusCode);
       
   169         res.setEncoding('utf8');
       
   170         res.on('data', function(chunk) {
       
   171             var newdata = chunk.split('\r\n'),
       
   172                 tweetpos = tweets.length;
       
   173             try {
       
   174                 for (var i in newdata) {
       
   175                     if (newdata[i].length > 0) {
       
   176                         var tweet = JSON.parse(newdata[i]);
       
   177                         textids(tweet);
       
   178                         for (var j in keys_to_delete) {
       
   179                             delete tweet[keys_to_delete[j]];
       
   180                         }
       
   181                         textids(tweet.user);
       
   182                         for (var j in user_keys_to_delete) {
       
   183                             delete tweet.user[user_keys_to_delete[j]];
       
   184                         }
       
   185                         if (tweet.retweeted_status) {
       
   186                             textids(tweet.retweeted_status);
       
   187                             for (var j in keys_to_delete) {
       
   188                                 delete tweet.retweeted_status[keys_to_delete[j]];
       
   189                             }
       
   190                         }
       
   191                     /*    tweet.date_value = Date.parse(tweet.created_at); */
       
   192                         if (addToList(tweet)) {
       
   193                             writestream.write(JSON.stringify(tweet)+'\n');
       
   194                         }
       
   195                     }
       
   196                 }
       
   197                 io.sockets.emit('update', {
       
   198                         "new_tweets" : tweets.slice(tweetpos)
       
   199                     });
       
   200                 console.log("New tweets received. We now have", tweets.length, "tweets in memory");
       
   201             }
       
   202             catch(err) {
       
   203                 console.log(err.message);
       
   204             }
       
   205         });
       
   206     });
       
   207     
       
   208     req.write('track=' + encodeURIComponent( ( tracking_keyword ) ) );
       
   209     req.end();
       
   210 }
       
   211 
       
   212 app.listen(app_port);
       
   213 console.log("Listening on port: "+app_port);
       
   214 
       
   215 if (READ_OLD_TWEETS) {
       
   216     readTweetsFromFile(tweet_file);
       
   217 } else {
       
   218     console.log("Reading old tweets disabled !");
       
   219 }
       
   220 
       
   221 if (RECORD_NEW_TWEETS) {
       
   222     requestTweets();
       
   223 } else {
       
   224     console.log("Recording new tweets disabled !");
       
   225 }
       
   226 
       
   227 io.set('log level', 0);
       
   228 io.sockets.on('connection', function(socket) {
       
   229     console.log("New connection from "+socket.handshake.address.address);
       
   230     socket.emit('initial_data', {
       
   231         "tweets" : tweets
       
   232     });
       
   233 });