mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-14 01:17:55 -05:00
That new flag will prevent the adapter (redis) from publishing the emit to the pub/sub server. When several instances of a server receive the same event from a third party (not from a client), each server instance broadcasts the event to all his clients. With the local flag, and the change in the redis adapter, each server instance send the event only to his client, so each client receive only one unique event.
276 lines
5.3 KiB
JavaScript
276 lines
5.3 KiB
JavaScript
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
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');
|
|
|
|
/**
|
|
* Module exports.
|
|
*/
|
|
|
|
module.exports = exports = Namespace;
|
|
|
|
/**
|
|
* Blacklisted events.
|
|
*/
|
|
|
|
exports.events = [
|
|
'connect', // for symmetry with client
|
|
'connection',
|
|
'newListener'
|
|
];
|
|
|
|
/**
|
|
* Flags.
|
|
*/
|
|
|
|
exports.flags = [
|
|
'json',
|
|
'volatile',
|
|
'local'
|
|
];
|
|
|
|
/**
|
|
* `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.initAdapter();
|
|
}
|
|
|
|
/**
|
|
* Inherits from `EventEmitter`.
|
|
*/
|
|
|
|
Namespace.prototype.__proto__ = Emitter.prototype;
|
|
|
|
/**
|
|
* Apply flags from `Socket`.
|
|
*/
|
|
|
|
exports.flags.forEach(function(flag){
|
|
Object.defineProperty(Namespace.prototype, flag, {
|
|
get: 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
|
|
*/
|
|
|
|
Namespace.prototype.initAdapter = function(){
|
|
this.adapter = new (this.server.adapter())(this);
|
|
};
|
|
|
|
/**
|
|
* Sets up namespace middleware.
|
|
*
|
|
* @return {Namespace} self
|
|
* @api public
|
|
*/
|
|
|
|
Namespace.prototype.use = function(fn){
|
|
this.fns.push(fn);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Executes the middleware for an incoming client.
|
|
*
|
|
* @param {Socket} socket that will get added
|
|
* @param {Function} fn 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
|
|
*/
|
|
|
|
Namespace.prototype.to =
|
|
Namespace.prototype.in = function(name){
|
|
this.rooms = this.rooms || [];
|
|
if (!~this.rooms.indexOf(name)) this.rooms.push(name);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Adds a new client.
|
|
*
|
|
* @return {Socket}
|
|
* @api private
|
|
*/
|
|
|
|
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');
|
|
}
|
|
});
|
|
});
|
|
return socket;
|
|
};
|
|
|
|
/**
|
|
* Removes a client. Called by each `Socket`.
|
|
*
|
|
* @api private
|
|
*/
|
|
|
|
Namespace.prototype.remove = function(socket){
|
|
if (this.sockets.hasOwnProperty(socket.id)) {
|
|
delete this.sockets[socket.id];
|
|
} 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 a `message` event to all clients.
|
|
*
|
|
* @return {Namespace} self
|
|
* @api public
|
|
*/
|
|
|
|
Namespace.prototype.send =
|
|
Namespace.prototype.write = function(){
|
|
var args = Array.prototype.slice.call(arguments);
|
|
args.unshift('message');
|
|
this.emit.apply(this, args);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Gets a list of clients.
|
|
*
|
|
* @return {Namespace} self
|
|
* @api public
|
|
*/
|
|
|
|
Namespace.prototype.clients = function(fn){
|
|
this.adapter.clients(this.rooms, fn);
|
|
// delete rooms flag for scenario:
|
|
// .in('room').clients() (GH-1978)
|
|
delete this.rooms;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Sets the compress flag.
|
|
*
|
|
* @param {Boolean} compress if `true`, compresses the sending data
|
|
* @return {Socket} self
|
|
* @api public
|
|
*/
|
|
|
|
Namespace.prototype.compress = function(compress){
|
|
this.flags = this.flags || {};
|
|
this.flags.compress = compress;
|
|
return this;
|
|
};
|