NewsBlur/node/node_modules/socket.io/lib/namespace.js

300 lines
5.8 KiB
JavaScript
Raw Normal View History

2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Module dependencies.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
var Socket = require('./socket');
var Emitter = require('events').EventEmitter;
var parser = require('socket.io-parser');
var hasBin = require('has-binary2');
2016-11-29 18:29:50 -08:00
var debug = require('debug')('socket.io:namespace');
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Module exports.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
module.exports = exports = Namespace;
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Blacklisted events.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
exports.events = [
'connect', // for symmetry with client
'connection',
'newListener'
];
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Flags.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
exports.flags = [
'json',
'volatile',
'local'
];
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* `EventEmitter#emit` reference.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
var emit = Emitter.prototype.emit;
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Namespace constructor.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @param {Server} server instance
* @param {Socket} name
* @api private
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
function Namespace(server, name){
this.name = name;
this.server = server;
this.sockets = {};
this.connected = {};
this.fns = [];
this.ids = 0;
this.rooms = [];
this.flags = {};
2016-11-29 18:29:50 -08:00
this.initAdapter();
}
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Inherits from `EventEmitter`.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.__proto__ = Emitter.prototype;
2012-01-02 18:22:06 -08:00
/**
2016-11-29 18:29:50 -08:00
* Apply flags from `Socket`.
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
exports.flags.forEach(function(flag){
Object.defineProperty(Namespace.prototype, flag, {
get: function() {
this.flags[flag] = true;
return this;
}
});
2012-01-02 18:22:06 -08:00
});
/**
2016-11-29 18:29:50 -08:00
* Initializes the `Adapter` for this nsp.
* Run upon changing adapter by `Server#adapter`
* in addition to the constructor.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @api private
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.initAdapter = function(){
this.adapter = new (this.server.adapter())(this);
2012-01-02 18:22:06 -08:00
};
/**
2016-11-29 18:29:50 -08:00
* Sets up namespace middleware.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @return {Namespace} self
2012-01-02 18:22:06 -08:00
* @api public
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.use = function(fn){
if (this.server.eio && this.name === '/') {
debug('removing initial packet');
delete this.server.eio.initialPacket;
}
2016-11-29 18:29:50 -08:00
this.fns.push(fn);
2012-01-02 18:22:06 -08:00
return this;
};
/**
2016-11-29 18:29:50 -08:00
* Executes the middleware for an incoming client.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @param {Socket} socket that will get added
* @param {Function} fn last fn call in the middleware
2012-01-02 18:22:06 -08:00
* @api private
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.run = function(socket, fn){
var fns = this.fns.slice(0);
if (!fns.length) return fn(null);
2012-01-02 18:22:06 -08:00
2016-11-29 18:29:50 -08:00
function run(i){
fns[i](socket, function(err){
// upon error, short-circuit
if (err) return fn(err);
2012-01-02 18:22:06 -08:00
2016-11-29 18:29:50 -08:00
// if no middleware left, summon callback
if (!fns[i + 1]) return fn(null);
2012-01-02 18:22:06 -08:00
2016-11-29 18:29:50 -08:00
// go on to next
run(i + 1);
});
}
2012-01-02 18:22:06 -08:00
2016-11-29 18:29:50 -08:00
run(0);
2012-01-02 18:22:06 -08:00
};
/**
2016-11-29 18:29:50 -08:00
* Targets a room when emitting.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @param {String} name
* @return {Namespace} self
2012-01-02 18:22:06 -08:00
* @api public
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.to =
Namespace.prototype.in = function(name){
if (!~this.rooms.indexOf(name)) this.rooms.push(name);
return this;
2012-01-02 18:22:06 -08:00
};
/**
2016-11-29 18:29:50 -08:00
* Adds a new client.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @return {Socket}
* @api private
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.add = function(client, query, fn){
debug('adding socket to nsp %s', this.name);
var socket = new Socket(this, client, query);
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[socket.id] = 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');
}
});
2012-01-02 18:22:06 -08:00
});
2016-11-29 18:29:50 -08:00
return socket;
2012-01-02 18:22:06 -08:00
};
/**
2016-11-29 18:29:50 -08:00
* Removes a client. Called by each `Socket`.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @api private
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.remove = function(socket){
if (this.sockets.hasOwnProperty(socket.id)) {
delete this.sockets[socket.id];
} else {
debug('ignoring remove for %s', socket.id);
2012-01-02 18:22:06 -08:00
}
};
/**
2016-11-29 18:29:50 -08:00
* Emits to all clients.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @return {Namespace} self
2012-01-02 18:22:06 -08:00
* @api public
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.emit = function(ev){
if (~exports.events.indexOf(ev)) {
emit.apply(this, arguments);
return this;
}
// set up packet object
var args = Array.prototype.slice.call(arguments);
var packet = {
type: (this.flags.binary !== undefined ? this.flags.binary : hasBin(args)) ? parser.BINARY_EVENT : parser.EVENT,
data: args
};
2016-11-29 18:29:50 -08:00
if ('function' == typeof args[args.length - 1]) {
throw new Error('Callbacks are not supported when broadcasting');
}
2016-11-29 18:29:50 -08:00
var rooms = this.rooms.slice(0);
var flags = Object.assign({}, this.flags);
2016-11-29 18:29:50 -08:00
// reset flags
this.rooms = [];
this.flags = {};
this.adapter.broadcast(packet, {
rooms: rooms,
flags: flags
});
2016-11-29 18:29:50 -08:00
2012-01-02 18:22:06 -08:00
return this;
};
/**
2016-11-29 18:29:50 -08:00
* Sends a `message` event to all clients.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @return {Namespace} self
* @api public
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.send =
Namespace.prototype.write = function(){
var args = Array.prototype.slice.call(arguments);
args.unshift('message');
this.emit.apply(this, args);
return this;
2012-01-02 18:22:06 -08:00
};
/**
2016-11-29 18:29:50 -08:00
* Gets a list of clients.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @return {Namespace} self
* @api public
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.clients = function(fn){
if(!this.adapter){
throw new Error('No adapter for this namespace, are you trying to get the list of clients of a dynamic namespace?')
}
2016-11-29 18:29:50 -08:00
this.adapter.clients(this.rooms, fn);
// reset rooms for scenario:
2016-11-29 18:29:50 -08:00
// .in('room').clients() (GH-1978)
this.rooms = [];
2012-01-02 18:22:06 -08:00
return this;
};
/**
2016-11-29 18:29:50 -08:00
* Sets the compress flag.
2012-01-02 18:22:06 -08:00
*
2016-11-29 18:29:50 -08:00
* @param {Boolean} compress if `true`, compresses the sending data
* @return {Socket} self
* @api public
2012-01-02 18:22:06 -08:00
*/
2016-11-29 18:29:50 -08:00
Namespace.prototype.compress = function(compress){
this.flags.compress = compress;
return this;
2012-01-02 18:22:06 -08:00
};
/**
* Sets the binary flag
*
* @param {Boolean} Encode as if it has binary data if `true`, Encode as if it doesnt have binary data if `false`
* @return {Socket} self
* @api public
*/
Namespace.prototype.binary = function (binary) {
this.flags.binary = binary;
return this;
};