twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

namespace.js (5954B)


      1 
      2 /**
      3  * Module dependencies.
      4  */
      5 
      6 var Socket = require('./socket');
      7 var Emitter = require('events').EventEmitter;
      8 var parser = require('socket.io-parser');
      9 var hasBin = require('has-binary2');
     10 var debug = require('debug')('socket.io:namespace');
     11 
     12 /**
     13  * Module exports.
     14  */
     15 
     16 module.exports = exports = Namespace;
     17 
     18 /**
     19  * Blacklisted events.
     20  */
     21 
     22 exports.events = [
     23   'connect',    // for symmetry with client
     24   'connection',
     25   'newListener'
     26 ];
     27 
     28 /**
     29  * Flags.
     30  */
     31 
     32 exports.flags = [
     33   'json',
     34   'volatile',
     35   'local'
     36 ];
     37 
     38 /**
     39  * `EventEmitter#emit` reference.
     40  */
     41 
     42 var emit = Emitter.prototype.emit;
     43 
     44 /**
     45  * Namespace constructor.
     46  *
     47  * @param {Server} server instance
     48  * @param {Socket} name
     49  * @api private
     50  */
     51 
     52 function Namespace(server, name){
     53   this.name = name;
     54   this.server = server;
     55   this.sockets = {};
     56   this.connected = {};
     57   this.fns = [];
     58   this.ids = 0;
     59   this.rooms = [];
     60   this.flags = {};
     61   this.initAdapter();
     62 }
     63 
     64 /**
     65  * Inherits from `EventEmitter`.
     66  */
     67 
     68 Namespace.prototype.__proto__ = Emitter.prototype;
     69 
     70 /**
     71  * Apply flags from `Socket`.
     72  */
     73 
     74 exports.flags.forEach(function(flag){
     75   Object.defineProperty(Namespace.prototype, flag, {
     76     get: function() {
     77       this.flags[flag] = true;
     78       return this;
     79     }
     80   });
     81 });
     82 
     83 /**
     84  * Initializes the `Adapter` for this nsp.
     85  * Run upon changing adapter by `Server#adapter`
     86  * in addition to the constructor.
     87  *
     88  * @api private
     89  */
     90 
     91 Namespace.prototype.initAdapter = function(){
     92   this.adapter = new (this.server.adapter())(this);
     93 };
     94 
     95 /**
     96  * Sets up namespace middleware.
     97  *
     98  * @return {Namespace} self
     99  * @api public
    100  */
    101 
    102 Namespace.prototype.use = function(fn){
    103   if (this.server.eio && this.name === '/') {
    104     debug('removing initial packet');
    105     delete this.server.eio.initialPacket;
    106   }
    107   this.fns.push(fn);
    108   return this;
    109 };
    110 
    111 /**
    112  * Executes the middleware for an incoming client.
    113  *
    114  * @param {Socket} socket that will get added
    115  * @param {Function} fn last fn call in the middleware
    116  * @api private
    117  */
    118 
    119 Namespace.prototype.run = function(socket, fn){
    120   var fns = this.fns.slice(0);
    121   if (!fns.length) return fn(null);
    122 
    123   function run(i){
    124     fns[i](socket, function(err){
    125       // upon error, short-circuit
    126       if (err) return fn(err);
    127 
    128       // if no middleware left, summon callback
    129       if (!fns[i + 1]) return fn(null);
    130 
    131       // go on to next
    132       run(i + 1);
    133     });
    134   }
    135 
    136   run(0);
    137 };
    138 
    139 /**
    140  * Targets a room when emitting.
    141  *
    142  * @param {String} name
    143  * @return {Namespace} self
    144  * @api public
    145  */
    146 
    147 Namespace.prototype.to =
    148 Namespace.prototype.in = function(name){
    149   if (!~this.rooms.indexOf(name)) this.rooms.push(name);
    150   return this;
    151 };
    152 
    153 /**
    154  * Adds a new client.
    155  *
    156  * @return {Socket}
    157  * @api private
    158  */
    159 
    160 Namespace.prototype.add = function(client, query, fn){
    161   debug('adding socket to nsp %s', this.name);
    162   var socket = new Socket(this, client, query);
    163   var self = this;
    164   this.run(socket, function(err){
    165     process.nextTick(function(){
    166       if ('open' == client.conn.readyState) {
    167         if (err) return socket.error(err.data || err.message);
    168 
    169         // track socket
    170         self.sockets[socket.id] = socket;
    171 
    172         // it's paramount that the internal `onconnect` logic
    173         // fires before user-set events to prevent state order
    174         // violations (such as a disconnection before the connection
    175         // logic is complete)
    176         socket.onconnect();
    177         if (fn) fn();
    178 
    179         // fire user-set events
    180         self.emit('connect', socket);
    181         self.emit('connection', socket);
    182       } else {
    183         debug('next called after client was closed - ignoring socket');
    184       }
    185     });
    186   });
    187   return socket;
    188 };
    189 
    190 /**
    191  * Removes a client. Called by each `Socket`.
    192  *
    193  * @api private
    194  */
    195 
    196 Namespace.prototype.remove = function(socket){
    197   if (this.sockets.hasOwnProperty(socket.id)) {
    198     delete this.sockets[socket.id];
    199   } else {
    200     debug('ignoring remove for %s', socket.id);
    201   }
    202 };
    203 
    204 /**
    205  * Emits to all clients.
    206  *
    207  * @return {Namespace} self
    208  * @api public
    209  */
    210 
    211 Namespace.prototype.emit = function(ev){
    212   if (~exports.events.indexOf(ev)) {
    213     emit.apply(this, arguments);
    214     return this;
    215   }
    216   // set up packet object
    217   var args = Array.prototype.slice.call(arguments);
    218   var packet = {
    219     type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT,
    220     data: args
    221   };
    222 
    223   if ('function' == typeof args[args.length - 1]) {
    224     throw new Error('Callbacks are not supported when broadcasting');
    225   }
    226 
    227   var rooms = this.rooms.slice(0);
    228   var flags = Object.assign({}, this.flags);
    229 
    230   // reset flags
    231   this.rooms = [];
    232   this.flags = {};
    233 
    234   this.adapter.broadcast(packet, {
    235     rooms: rooms,
    236     flags: flags
    237   });
    238 
    239   return this;
    240 };
    241 
    242 /**
    243  * Sends a `message` event to all clients.
    244  *
    245  * @return {Namespace} self
    246  * @api public
    247  */
    248 
    249 Namespace.prototype.send =
    250 Namespace.prototype.write = function(){
    251   var args = Array.prototype.slice.call(arguments);
    252   args.unshift('message');
    253   this.emit.apply(this, args);
    254   return this;
    255 };
    256 
    257 /**
    258  * Gets a list of clients.
    259  *
    260  * @return {Namespace} self
    261  * @api public
    262  */
    263 
    264 Namespace.prototype.clients = function(fn){
    265   if(!this.adapter){
    266     throw new Error('No adapter for this namespace, are you trying to get the list of clients of a dynamic namespace?')
    267   }
    268   this.adapter.clients(this.rooms, fn);
    269   // reset rooms for scenario:
    270   // .in('room').clients() (GH-1978)
    271   this.rooms = [];
    272   return this;
    273 };
    274 
    275 /**
    276  * Sets the compress flag.
    277  *
    278  * @param {Boolean} compress if `true`, compresses the sending data
    279  * @return {Socket} self
    280  * @api public
    281  */
    282 
    283 Namespace.prototype.compress = function(compress){
    284   this.flags.compress = compress;
    285   return this;
    286 };
    287 
    288 /**
    289  * Sets the binary flag
    290  *
    291  * @param {Boolean} Encode as if it has binary data if `true`, Encode as if it doesnt have binary data if `false`
    292  * @return {Socket} self
    293  * @api public
    294  */
    295 
    296  Namespace.prototype.binary = function (binary) {
    297    this.flags.binary = binary;
    298    return this;
    299  };