diff node_modules/socket.io/lib/namespace.js @ 76:0ae87af84e2f

added oscgroups
author Rob Canning <rob@foo.net>
date Sun, 13 Jul 2014 10:07:41 +0100
parents 333afcfd3f3a
children
line wrap: on
line diff
--- a/node_modules/socket.io/lib/namespace.js	Tue Jul 01 08:51:53 2014 +0000
+++ b/node_modules/socket.io/lib/namespace.js	Sun Jul 13 10:07:41 2014 +0100
@@ -1,355 +1,242 @@
+
 /**
  * Module dependencies.
  */
 
-var Socket = require('./socket')
-  , EventEmitter = process.EventEmitter
-  , parser = require('./parser')
-  , util = require('./util');
+var Socket = require('./socket');
+var Emitter = require('events').EventEmitter;
+var parser = require('socket.io-parser');
+var debug = require('debug')('socket.io:namespace');
+var hasBin = require('has-binary-data');
 
 /**
- * Exports the constructor.
+ * Module exports.
  */
 
-exports = module.exports = SocketNamespace;
+module.exports = exports = Namespace;
 
 /**
- * Constructor.
- *
- * @api public.
+ * Blacklisted events.
  */
 
-function SocketNamespace (mgr, name) {
-  this.manager = mgr;
-  this.name = name || '';
-  this.sockets = {};
-  this.auth = false;
-  this.setFlags();
-};
+exports.events = [
+  'connect',    // for symmetry with client
+  'connection',
+  'newListener'
+];
 
 /**
- * Inherits from EventEmitter.
+ * Flags.
  */
 
-SocketNamespace.prototype.__proto__ = EventEmitter.prototype;
+exports.flags = ['json'];
 
 /**
- * Copies emit since we override it.
+ * `EventEmitter#emit` reference.
+ */
+
+var emit = Emitter.prototype.emit;
+
+/**
+ * Namespace constructor.
+ *
+ * @param {Server} server instance
+ * @param {Socket} name
+ * @api private
+ */
+
+function Namespace(server, name){
+  this.name = name;
+  this.server = server;
+  this.sockets = [];
+  this.connected = {};
+  this.fns = [];
+  this.ids = 0;
+  this.acks = {};
+  this.initAdapter();
+}
+
+/**
+ * Inherits from `EventEmitter`.
+ */
+
+Namespace.prototype.__proto__ = Emitter.prototype;
+
+/**
+ * Apply flags from `Socket`.
+ */
+
+exports.flags.forEach(function(flag){
+  Namespace.prototype.__defineGetter__(flag, function(){
+    this.flags = this.flags || {};
+    this.flags[flag] = true;
+    return this;
+  });
+});
+
+/**
+ * Initializes the `Adapter` for this nsp.
+ * Run upon changing adapter by `Server#adapter`
+ * in addition to the constructor.
  *
  * @api private
  */
 
-SocketNamespace.prototype.$emit = EventEmitter.prototype.emit;
+Namespace.prototype.initAdapter = function(){
+  this.adapter = new (this.server.adapter())(this);
+};
 
 /**
- * Retrieves all clients as Socket instances as an array.
+ * Sets up namespace middleware.
  *
+ * @return {Namespace} self
  * @api public
  */
 
-SocketNamespace.prototype.clients = function (room) {
-  var room = this.name + (room !== undefined ?
-     '/' + room : '');
-
-  if (!this.manager.rooms[room]) {
-    return [];
-  }
-
-  return this.manager.rooms[room].map(function (id) {
-    return this.socket(id);
-  }, this);
-};
-
-/**
- * Access logger interface.
- *
- * @api public
- */
-
-SocketNamespace.prototype.__defineGetter__('log', function () {
-  return this.manager.log;
-});
-
-/**
- * Access store.
- *
- * @api public
- */
-
-SocketNamespace.prototype.__defineGetter__('store', function () {
-  return this.manager.store;
-});
-
-/**
- * JSON message flag.
- *
- * @api public
- */
-
-SocketNamespace.prototype.__defineGetter__('json', function () {
-  this.flags.json = true;
-  return this;
-});
-
-/**
- * Volatile message flag.
- *
- * @api public
- */
-
-SocketNamespace.prototype.__defineGetter__('volatile', function () {
-  this.flags.volatile = true;
-  return this;
-});
-
-/**
- * Overrides the room to relay messages to (flag).
- *
- * @api public
- */
-
-SocketNamespace.prototype.in = SocketNamespace.prototype.to = function (room) {
-  this.flags.endpoint = this.name + (room ? '/' + room : '');
+Namespace.prototype.use = function(fn){
+  this.fns.push(fn);
   return this;
 };
 
 /**
- * Adds a session id we should prevent relaying messages to (flag).
+ * Executes the middleware for an incoming client.
  *
+ * @param {Socket} socket that will get added
+ * @param {Function} last fn call in the middleware
+ * @api private
+ */
+
+Namespace.prototype.run = function(socket, fn){
+  var fns = this.fns.slice(0);
+  if (!fns.length) return fn(null);
+
+  function run(i){
+    fns[i](socket, function(err){
+      // upon error, short-circuit
+      if (err) return fn(err);
+
+      // if no middleware left, summon callback
+      if (!fns[i + 1]) return fn(null);
+
+      // go on to next
+      run(i + 1);
+    });
+  }
+
+  run(0);
+};
+
+/**
+ * Targets a room when emitting.
+ *
+ * @param {String} name
+ * @return {Namespace} self
  * @api public
  */
 
-SocketNamespace.prototype.except = function (id) {
-  this.flags.exceptions.push(id);
+Namespace.prototype.to =
+Namespace.prototype['in'] = function(name){
+  this.rooms = this.rooms || [];
+  if (!~this.rooms.indexOf(name)) this.rooms.push(name);
   return this;
 };
 
 /**
- * Sets the default flags.
+ * Adds a new client.
+ *
+ * @return {Socket}
+ * @api private
+ */
+
+Namespace.prototype.add = function(client, fn){
+  debug('adding socket to nsp %s', this.name);
+  var socket = new Socket(this, client);
+  var self = this;
+  this.run(socket, function(err){
+    process.nextTick(function(){
+      if ('open' == client.conn.readyState) {
+        if (err) return socket.error(err.data || err.message);
+
+        // track socket
+        self.sockets.push(socket);
+
+        // it's paramount that the internal `onconnect` logic
+        // fires before user-set events to prevent state order
+        // violations (such as a disconnection before the connection
+        // logic is complete)
+        socket.onconnect();
+        if (fn) fn();
+
+        // fire user-set events
+        self.emit('connect', socket);
+        self.emit('connection', socket);
+      } else {
+        debug('next called after client was closed - ignoring socket');
+      }
+    });
+  });
+  return socket;
+};
+
+/**
+ * Removes a client. Called by each `Socket`.
  *
  * @api private
  */
 
-SocketNamespace.prototype.setFlags = function () {
-  this.flags = {
-      endpoint: this.name
-    , exceptions: []
-  };
+Namespace.prototype.remove = function(socket){
+  var i = this.sockets.indexOf(socket);
+  if (~i) {
+    this.sockets.splice(i, 1);
+  } else {
+    debug('ignoring remove for %s', socket.id);
+  }
+};
+
+/**
+ * Emits to all clients.
+ *
+ * @return {Namespace} self
+ * @api public
+ */
+
+Namespace.prototype.emit = function(ev){
+  if (~exports.events.indexOf(ev)) {
+    emit.apply(this, arguments);
+  } else {
+    // set up packet object
+    var args = Array.prototype.slice.call(arguments);
+    var parserType = parser.EVENT; // default
+    if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary
+
+    var packet = { type: parserType, data: args };
+
+    if ('function' == typeof args[args.length - 1]) {
+      throw new Error('Callbacks are not supported when broadcasting');
+    }
+
+    this.adapter.broadcast(packet, {
+      rooms: this.rooms,
+      flags: this.flags
+    });
+
+    delete this.rooms;
+    delete this.flags;
+  }
   return this;
 };
 
 /**
- * Sends out a packet.
+ * Sends a `message` event to all clients.
  *
- * @api private
- */
-
-SocketNamespace.prototype.packet = function (packet) {
-  packet.endpoint = this.name;
-
-  var store = this.store
-    , log = this.log
-    , volatile = this.flags.volatile
-    , exceptions = this.flags.exceptions
-    , packet = parser.encodePacket(packet);
-
-  this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions);
-  this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions);
-
-  this.setFlags();
-
-  return this;
-};
-
-/**
- * Sends to everyone.
- *
+ * @return {Namespace} self
  * @api public
  */
 
-SocketNamespace.prototype.send = function (data) {
-  return this.packet({
-      type: this.flags.json ? 'json' : 'message'
-    , data: data
-  });
-};
-
-/**
- * Emits to everyone (override).
- *
- * @api public
- */
-
-SocketNamespace.prototype.emit = function (name) {
-  if (name == 'newListener') {
-    return this.$emit.apply(this, arguments);
-  }
-
-  return this.packet({
-      type: 'event'
-    , name: name
-    , args: util.toArray(arguments).slice(1)
-  });
-};
-
-/**
- * Retrieves or creates a write-only socket for a client, unless specified.
- *
- * @param {Boolean} whether the socket will be readable when initialized
- * @api public
- */
-
-SocketNamespace.prototype.socket = function (sid, readable) {
-  if (!this.sockets[sid]) {
-    this.sockets[sid] = new Socket(this.manager, sid, this, readable);
-  }
-
-  return this.sockets[sid];
-};
-
-/**
- * Sets authorization for this namespace.
- *
- * @api public
- */
-
-SocketNamespace.prototype.authorization = function (fn) {
-  this.auth = fn;
+Namespace.prototype.send =
+Namespace.prototype.write = function(){
+  var args = Array.prototype.slice.call(arguments);
+  args.unshift('message');
+  this.emit.apply(this, args);
   return this;
 };
-
-/**
- * Called when a socket disconnects entirely.
- *
- * @api private
- */
-
-SocketNamespace.prototype.handleDisconnect = function (sid, reason, raiseOnDisconnect) {
-  if (this.sockets[sid] && this.sockets[sid].readable) {
-    if (raiseOnDisconnect) this.sockets[sid].onDisconnect(reason);
-    delete this.sockets[sid];
-  }
-};
-
-/**
- * Performs authentication.
- *
- * @param Object client request data
- * @api private
- */
-
-SocketNamespace.prototype.authorize = function (data, fn) {
-  if (this.auth) {
-    var self = this;
-
-    this.auth.call(this, data, function (err, authorized) {
-      self.log.debug('client ' +
-        (authorized ? '' : 'un') + 'authorized for ' + self.name);
-      fn(err, authorized);
-    });
-  } else {
-    this.log.debug('client authorized for ' + this.name);
-    fn(null, true);
-  }
-
-  return this;
-};
-
-/**
- * Handles a packet.
- *
- * @api private
- */
-
-SocketNamespace.prototype.handlePacket = function (sessid, packet) {
-  var socket = this.socket(sessid)
-    , dataAck = packet.ack == 'data'
-    , manager = this.manager
-    , self = this;
-
-  function ack () {
-    self.log.debug('sending data ack packet');
-    socket.packet({
-        type: 'ack'
-      , args: util.toArray(arguments)
-      , ackId: packet.id
-    });
-  };
-
-  function error (err) {
-    self.log.warn('handshake error ' + err + ' for ' + self.name);
-    socket.packet({ type: 'error', reason: err });
-  };
-
-  function connect () {
-    self.manager.onJoin(sessid, self.name);
-    self.store.publish('join', sessid, self.name);
-
-    // packet echo
-    socket.packet({ type: 'connect' });
-
-    // emit connection event
-    self.$emit('connection', socket);
-  };
-
-  switch (packet.type) {
-    case 'connect':
-      if (packet.endpoint == '') {
-        connect();
-      } else {
-        var handshakeData = manager.handshaken[sessid];
-
-        this.authorize(handshakeData, function (err, authorized, newData) {
-          if (err) return error(err);
-
-          if (authorized) {
-            manager.onHandshake(sessid, newData || handshakeData);
-            self.store.publish('handshake', sessid, newData || handshakeData);
-            connect();
-          } else {
-            error('unauthorized');
-          }
-        });
-      }
-      break;
-
-    case 'ack':
-      if (socket.acks[packet.ackId]) {
-        socket.acks[packet.ackId].apply(socket, packet.args);
-      } else {
-        this.log.info('unknown ack packet');
-      }
-      break;
-
-    case 'event':
-      // check if the emitted event is not blacklisted
-      if (-~manager.get('blacklist').indexOf(packet.name)) {
-        this.log.debug('ignoring blacklisted event `' + packet.name + '`');
-      } else {
-        var params = [packet.name].concat(packet.args);
-
-        if (dataAck) {
-          params.push(ack);
-        }
-
-        socket.$emit.apply(socket, params);
-      }
-      break;
-
-    case 'disconnect':
-      this.manager.onLeave(sessid, this.name);
-      this.store.publish('leave', sessid, this.name);
-
-      socket.$emit('disconnect', packet.reason || 'packet');
-      break;
-
-    case 'json':
-    case 'message':
-      var params = ['message', packet.data];
-
-      if (dataAck)
-        params.push(ack);
-
-      socket.$emit.apply(socket, params);
-  };
-};