Archive

Posts Tagged ‘node.js’

twitter-node https fix

November 1st, 2011 No comments
nodejs twitter-node

nodejs twitter-node

twitter streaming api

twitter streaming api

Como muchos sabran, hace un tiempo el steaming api de twitter solo funciona con https.

Para nodejs existe el modulo twitter-node, que permitia consumir este streaming, pero dejo de funcionar por el tema del https.

Aca adjunto el index.js de ese modulo (el codigo js que lo hace funcionar) fixeado para que trabajo con https.

Como fix extra, también deje habilitado el debug (propiedad que existía pero no hacia nada).

 

//Fixed by Cesar Casas (lortmorris@gmail.com)
var https         = require('https'),
    query        = require('querystring'),
    Parser       = require('./parser'),
    EventEmitter = require('events').EventEmitter,
    Buffer       = require('buffer').Buffer;

// process.mixin is gone, a function for replacement
function extend(a, b) {
  Object.keys(b).forEach(function (key) {
    a[key] = b[key];
  });
  return a;
}

// Creates a streaming connection with twitter, and pushes any incoming
// statuses to a tweet event.
//
// options - optional Object that specifies custom configuration values.
//
// Valid option keys:
//
// port      - Integer of proxy port
// host      - String or ip address of the proxy server.  Defaults to 'stream.twitter.com'.
// path      - String of the base path for the request.
// action    - String part of the URL that specifies what to query for.
// track     - Array of keywords to filter.  See track()
// following - Array of userIDs to filter.  See follow()
// locations - Array of lat/long tuples.  See location()
// params    - Extra HTTP params Object to send with the request.
// user      - String Twitter login name or email.
// password  - String Twitter password.
//
// Returns TwitterNode instance.
var TwitterNode = exports.TwitterNode = function(options) {
  EventEmitter.call(this);
  if(!options) options = {};
  var self           = this;
  this.port          = options.port      || 80;
  this.host          = options.host      || 'stream.twitter.com';
  this.path          = options.path      || '/1/statuses/';
  this.action        = options.action    || 'filter';
  this.trackKeywords = options.track     || [];
  this.following     = options.follow    || [];
  this.locations     = options.locations || [];
  this.params        = options.params    || {};
  this.user          = options.user;
  this.password      = options.password;
  this.headers       = { "User-Agent": 'Twitter-Node' };
  this.debug         = options.debug || false;
  this.parser        = new Parser();
  this.parser.addListener('object', processJSONObject(this));
  this.parser.addListener('error', function (error) {
    self.emit('error', new Error('TwitterNode parser error: ' + error.message));
  });
  if (options.headers) {
    extend(this.headers, options.headers);
  }
}

TwitterNode.prototype = Object.create(EventEmitter.prototype);

// Track the following keyword.  If called multiple times, all words are sent
// as a comma-separated parameter to Twitter.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#track
//
// word - String word to track.
//
// Returns nothing.
TwitterNode.prototype.track = function track(word) {
  this.trackKeywords.push(word);
  return this;
};

// Follow the given twitter user (specified by their userID, not screen name)
// If called multiple times, all userIDs are sent as a comma-separated
// parameter to Twitter.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#follow
//
// userID - Integer userID to track.
//
// Returns nothing.
TwitterNode.prototype.follow = function follow(userId) {
  this.following.push(userId);
  return this;
};

// Match tweets in the given bounding box.
//
// See: http://apiwiki.twitter.com/Streaming-API-Documentation#locations
//
// Example: location(-122.75, 36.8, -121.75, 37.8) // SF
//
// lng1, lat1 - southwest corner of the bounding box.
// lng2, lat2 - northeast corner.
//
// Returns nothing.
TwitterNode.prototype.location = function location(lng1, lat1, lng2, lat2) {
  this.locations.push(lng1, lat1, lng2, lat2)
  return this;
};

TwitterNode.prototype.stream = function stream() {
  if (this._clientResponse && this._clientResponse.connection) {
    this._clientResponse.socket.end();
  }

  if (this.action === 'filter' && this.buildParams() === '') return;

	var headers = extend({}, this.headers),
      twit    = this,
      request;

  headers['Host'] = this.host;

  if (this.user) {
    headers['Authorization'] = basicAuth(this.user, this.password);
  }

var options = {
  host: this.host,
  port: this.port,
  path: this.requestUrl(),
  method: 'GET',
  headers : headers
};

if(this.debug) console.log(options);

var req = https.request(options, function(res) {

if(this.debug)  console.log("statusCode: ", res.statusCode);
if(this.debug)  console.log("headers: ", res.headers);

  res.on('data', function(d) {
    twit._receive(d);
    if(this.debug) process.stdout.write(d);
  });

  res.on('response', function(d) {
	    twit._clientResponse = d;
	    if(this.debug) process.stdout.write(d);
	  });

  res.on('end', function() {
      twit.emit('end', this);
      twit.emit('close', this);
    });

});

req.end();

req.on('error', function(e) {
  console.error(e);
});

  return this;
};

// UTILITY METHODS

// Passes the received data to the streaming JSON parser.
//
// chunk - String data received from the HTTP stream.
//
// Returns nothing.
TwitterNode.prototype._receive = function(chunk) {
  this.parser.receive(chunk);
  return this;
};

// Builds the URL for the streaming request.
//
// Returns a String absolute URL.
TwitterNode.prototype.requestUrl = function() {
  var url =  this.path + this.action + ".json" + this.buildParams();
	console.log('make url: ', url);

	return url;
};

// Builds the GET params for the streaming request.
//
// Returns URI encoded string: "?track=LOST"
TwitterNode.prototype.buildParams = function() {
  var options = {};
  extend(options, this.params);
  if (this.trackKeywords.length > 0) options.track = this.trackKeywords.join(",");
  if (this.following.length > 0)     options.follow = this.following.join(",");
  if (this.locations.length > 0)     options.locations = this.locations.join(",");
  if (options.track || options.follow || options.locations) {
    return "?" + query.stringify(options);
  }
  return "";
};

// Base64 encodes the given username and password.
//
// user - String Twitter screen name or email.
// pass - String password.
//
// Returns a Basic Auth header fit for HTTP.
var basicAuth = function basicAuth(user, pass) {
  return "Basic " + new Buffer(user + ":" + pass).toString('base64');
};

// Creates a callback for the object Event of the JSON Parser.
//
// twit - an instance of this TwitterNode.
//
// Returns a function to be passed to the addListener call on the parser.
var processJSONObject = function processJSONObject(twit) {
  return function(tweet) {
    if (tweet.limit) {
      twit.emit('limit', tweet.limit);
    } else if (tweet['delete']) {
      twit.emit('delete', tweet['delete']);
    } else {
      twit.emit('tweet', tweet);
    }
  };
};

node.js vs php & apache

October 6th, 2010 1 comment

En la investigacion de node.js, obviamente busque algunas comparaciones con el viejo y poco querido PHP.

Obviamente intuia que el server de node.js era mucho mas rapido que apache, pero no tenia tiempo de hacer las pruebas, es por eso que busque en internet que se habia hecho al respecto, y aca dejo los datos.

Primero una comparativa de las tecnologias

Apache, PHP node.js
syntax Additional language to web standard ECMA script
try to use common structures
One language to rule them all = reuse parts of your framework on the client side
strings ‘line
line’
‘line\nline’ or “line\n\
line”
templates <code><?php // code ?></code> var s = ‘<code>’;
// code
s += ‘</code>’;
// send response
http://github.com/creationix/microtemplates
database interface PDO + prepared Statements (includes class instance support) Still no prepared statements, 1.5 – 3x slower
Driver update
performance faster
unicode PCRE no Unicode Character Properties / Scripts / Blocks in RegExp (only \w, \W consider Unicode whitespace)
add chars manually to regexp
order no namespaces up to 5.3
simple modules / namespaces
serving files Apache serves static files Overhead to serve static files
Use additional webserver (nginx) or included in web framework
access Only synchronous access
… but easier code
Asynchronous access via closures
… highly nested code
http://github.com/creationix/step
OOP implicit memoization via __get() and reuse of requested key getters (/setters) must access key with other name, bad for iteration or JSON notation
platform many reliable extensions many extensions still experimental
… but the community is dynamic
PostGIS/Postgres MongoDB CouchDB
GIS functionality rich just stuff based on points few
stable yes yes probably
GIS standards full OpenGIS support (except for GeomColl in relational functions, workaround functions) no OpenGIS at all, just points full excepting for GeomColl
GIS indexing no GeomColl
index single geoms
yes yes
GIS performance fast

Fuente: https://docs.google.com/View?id=dfzvhszt_30drxqrvhk

Comparativa de rendimiento

Number of requests performed: 2000
Number of multiple requests made: 50

node.js vs php y apache, request por segundo

node.js vs php y apache, request por segundo

Number of requests performed: 2000Number of multiple requests made: 100

node.js vs php y apache, request por segundo

node.js vs php y apache, request por segundo

Number of requests performed: 2000
Number of multiple requests made: 150

node.js vs php y apache, request por segundo

node.js vs php y apache, request por segundo

Fuente: http://ricallinson.com/nodejs-ash-vs-php-symfony-vs-php-codeigniter

Seguire mi investigacon, cada vez me convenso mas de que node.js tiene un gran futuro.