function Client(server, conn){ this.server = server; this.conn = conn; this.encoder = new parser.Encoder(); this.decoder = new parser.Decoder(); this.id = conn.id; this.request = conn.request; this.setup(); this.sockets = {}; this.nsps = {}; this.connectBuffer = []; }
n/a
function Namespace(server, name){ this.name = name; this.server = server; this.sockets = {}; this.connected = {}; this.fns = []; this.ids = 0; this.initAdapter(); }
n/a
function Socket(nsp, client, query){ this.nsp = nsp; this.server = nsp.server; this.adapter = this.nsp.adapter; this.id = nsp.name !== '/' ? nsp.name + '#' + client.id : client.id; this.client = client; this.conn = client.conn; this.rooms = {}; this.acks = {}; this.connected = true; this.disconnected = false; this.handshake = this.buildHandshake(query); this.fns = []; }
n/a
function Server(srv, opts){ if (!(this instanceof Server)) return new Server(srv, opts); if ('object' == typeof srv && !srv.listen) { opts = srv; srv = null; } opts = opts || {}; this.nsps = {}; this.path(opts.path || '/socket.io'); this.serveClient(false !== opts.serveClient); this.adapter(opts.adapter || Adapter); this.origins(opts.origins || '*:*'); this.sockets = this.of('/'); if (srv) this.attach(srv, opts); }
...
```js
var server = require('http').createServer();
var io = require('socket.io')(server);
io.on('connection', function(client){
client.on('event', function(data){});
client.on('disconnect', function(){});
});
server.listen(3000);
```
### Standalone
```js
var io = require('socket.io')();
io.on('connection', function(client){});
...
function Client(server, conn){ this.server = server; this.conn = conn; this.encoder = new parser.Encoder(); this.decoder = new parser.Decoder(); this.id = conn.id; this.request = conn.request; this.setup(); this.sockets = {}; this.nsps = {}; this.connectBuffer = []; }
n/a
close = function (){ if ('open' == this.conn.readyState) { debug('forcing transport close'); this.conn.close(); this.onclose('forced server close'); } }
...
For other available methods, see `Namespace` below.
### Server#close([fn:Function])
Closes socket.io server.
The optional `fn` is passed to the `server.close([callback])` method of the
core `net` module and is called on error or when all connections are closed.
The callback is expected to implement the common single argument `err`
signature (if any).
```js
var Server = require('socket.io');
var PORT = 3030;
...
connect = function (name, query){ debug('connecting to namespace %s', name); var nsp = this.server.nsps[name]; if (!nsp) { this.packet({ type: parser.ERROR, nsp: name, data : 'Invalid namespace'}); return; } if ('/' != name && !this.nsps['/']) { this.connectBuffer.push(name); return; } var self = this; var socket = nsp.add(this, query, function(){ self.sockets[socket.id] = socket; self.nsps[nsp.name] = socket; if ('/' == nsp.name && self.connectBuffer.length > 0) { self.connectBuffer.forEach(self.connect, self); self.connectBuffer = []; } }); }
...
* Called when parser fully decodes a packet.
*
* @api private
*/
Client.prototype.ondecoded = function(packet) {
if (parser.CONNECT == packet.type) {
this.connect(url.parse(packet.nsp).pathname, url.parse(packet.nsp, true).query);
} else {
var socket = this.nsps[packet.nsp];
if (socket) {
process.nextTick(function() {
socket.onpacket(packet);
});
} else {
...
destroy = function (){ this.conn.removeListener('data', this.ondata); this.conn.removeListener('error', this.onerror); this.conn.removeListener('close', this.onclose); this.decoder.removeListener('decoded', this.ondecoded); }
...
* @api private
*/
Client.prototype.onclose = function(reason){
debug('client close with reason %s', reason);
// ignore a potential subsequent `close` event
this.destroy();
// `nsps` and `sockets` are cleaned up seamlessly
for (var id in this.sockets) {
if (this.sockets.hasOwnProperty(id)) {
this.sockets[id].onclose(reason);
}
}
...
disconnect = function (){ for (var id in this.sockets) { if (this.sockets.hasOwnProperty(id)) { this.sockets[id].disconnect(); } } this.sockets = {}; this.close(); }
...
*
* @api private
*/
Client.prototype.disconnect = function(){
for (var id in this.sockets) {
if (this.sockets.hasOwnProperty(id)) {
this.sockets[id].disconnect();
}
}
this.sockets = {};
this.close();
};
/**
...
onclose = function (reason){ debug('client close with reason %s', reason); // ignore a potential subsequent `close` event this.destroy(); // `nsps` and `sockets` are cleaned up seamlessly for (var id in this.sockets) { if (this.sockets.hasOwnProperty(id)) { this.sockets[id].onclose(reason); } } this.sockets = {}; this.decoder.destroy(); // clean up decoder }
...
* @api private
*/
Client.prototype.close = function(){
if ('open' == this.conn.readyState) {
debug('forcing transport close');
this.conn.close();
this.onclose('forced server close');
}
};
/**
* Writes a packet to the transport.
*
* @param {Object} packet object
...
ondata = function (data){ // try/catch is needed for protocol violations (GH-1880) try { this.decoder.add(data); } catch(e) { this.onerror(e); } }
n/a
ondecoded = function (packet) { if (parser.CONNECT == packet.type) { this.connect(url.parse(packet.nsp).pathname, url.parse(packet.nsp, true).query); } else { var socket = this.nsps[packet.nsp]; if (socket) { process.nextTick(function() { socket.onpacket(packet); }); } else { debug('no socket for namespace %s', packet.nsp); } } }
n/a
onerror = function (err){ for (var id in this.sockets) { if (this.sockets.hasOwnProperty(id)) { this.sockets[id].onerror(err); } } this.onclose('client error'); }
...
*/
Client.prototype.ondata = function(data){
// try/catch is needed for protocol violations (GH-1880)
try {
this.decoder.add(data);
} catch(e) {
this.onerror(e);
}
};
/**
* Called when parser fully decodes a packet.
*
* @api private
...
packet = function (packet, opts){ opts = opts || {}; var self = this; // this writes to the actual connection function writeToEngine(encodedPackets) { if (opts.volatile && !self.conn.transport.writable) return; for (var i = 0; i < encodedPackets.length; i++) { self.conn.write(encodedPackets[i], { compress: opts.compress }); } } if ('open' == this.conn.readyState) { debug('writing packet %j', packet); if (!opts.preEncoded) { // not broadcasting, need to encode this.encoder.encode(packet, function (encodedPackets) { // encode, then write results to engine writeToEngine(encodedPackets); }); } else { // a broadcast pre-encodes a packet writeToEngine(packet); } } else { debug('ignoring packet write %j', packet); } }
...
* @api private
*/
Client.prototype.connect = function(name, query){
debug('connecting to namespace %s', name);
var nsp = this.server.nsps[name];
if (!nsp) {
this.packet({ type: parser.ERROR, nsp: name, data : 'Invalid namespace'});
return;
}
if ('/' != name && !this.nsps['/']) {
this.connectBuffer.push(name);
return;
}
...
remove = function (socket){ if (this.sockets.hasOwnProperty(socket.id)) { var nsp = this.sockets[socket.id].nsp.name; delete this.sockets[socket.id]; delete this.nsps[nsp]; } else { debug('ignoring remove for %s', socket.id); } }
...
*/
Socket.prototype.onclose = function(reason){
if (!this.connected) return this;
debug('closing socket - reason %s', reason);
this.emit('disconnecting', reason);
this.leaveAll();
this.nsp.remove(this);
this.client.remove(this);
this.connected = false;
this.disconnected = true;
delete this.nsp.connected[this.id];
this.emit('disconnect', reason);
};
...
setup = function (){ this.onclose = this.onclose.bind(this); this.ondata = this.ondata.bind(this); this.onerror = this.onerror.bind(this); this.ondecoded = this.ondecoded.bind(this); this.decoder.on('decoded', this.ondecoded); this.conn.on('data', this.ondata); this.conn.on('error', this.onerror); this.conn.on('close', this.onclose); }
...
function Client(server, conn){
this.server = server;
this.conn = conn;
this.encoder = new parser.Encoder();
this.decoder = new parser.Decoder();
this.id = conn.id;
this.request = conn.request;
this.setup();
this.sockets = {};
this.nsps = {};
this.connectBuffer = [];
}
/**
* Sets up event listeners.
...
function Namespace(server, name){ this.name = name; this.server = server; this.sockets = {}; this.connected = {}; this.fns = []; this.ids = 0; this.initAdapter(); }
n/a
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; }
...
if ('/' != name && !this.nsps['/']) {
this.connectBuffer.push(name);
return;
}
var self = this;
var socket = nsp.add(this, query, function(){
self.sockets[socket.id] = socket;
self.nsps[nsp.name] = socket;
if ('/' == nsp.name && self.connectBuffer.length > 0) {
self.connectBuffer.forEach(self.connect, self);
self.connectBuffer = [];
}
...
clients = function (fn){ this.adapter.clients(this.rooms, fn); // delete rooms flag for scenario: // .in('room').clients() (GH-1978) delete this.rooms; return this; }
...
Gets a list of client IDs connected to this namespace (across all nodes if applicable).
An example to get all clients in a namespace:
```js
var io = require('socket.io')();
io.of('/chat').clients(function(error, clients){
if (error) throw error;
console.log(clients); // => [PZDoMHjiu8PYfRiKAAAF, Anw2LatarvGVVXEIAAAD]
});
```
An example to get all clients in namespace's room:
...
compress = function (compress){ this.flags = this.flags || {}; this.flags.compress = compress; return this; }
...
Sets a modifier for a subsequent event emission that the event data will
only be _compressed_ if the value is `true`. Defaults to `true` when you don't call the method.
```js
var io = require('socket.io')();
io.on('connection', function(client){
client.compress(false).emit('an event', { some: 'data' });
});
```
### Socket#disconnect(close:Boolean):Socket
Disconnects this client. If value of close is `true`, closes the underlying connection.
Otherwise, it just disconnects the namespace.
...
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; }
...
### Server#emit
Emits an event to all connected clients. The following two are
equivalent:
```js
var io = require('socket.io')();
io.sockets.emit('an event sent to all connected clients');
io.emit('an event sent to all connected clients');
```
For other available methods, see `Namespace` below.
### Server#close([fn:Function])
...
in = function (name){ this.rooms = this.rooms || []; if (!~this.rooms.indexOf(name)) this.rooms.push(name); return this; }
...
});
```
An example to get all clients in namespace's room:
```js
var io = require('socket.io')();
io.of('/chat').in('general').clients(function(error, clients){
if (error) throw error;
console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
});
```
As with broadcasting, the default is all clients from the default namespace ('/'):
...
initAdapter = function (){ this.adapter = new (this.server.adapter())(this); }
...
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;
...
remove = function (socket){ if (this.sockets.hasOwnProperty(socket.id)) { delete this.sockets[socket.id]; } else { debug('ignoring remove for %s', socket.id); } }
...
*/
Socket.prototype.onclose = function(reason){
if (!this.connected) return this;
debug('closing socket - reason %s', reason);
this.emit('disconnecting', reason);
this.leaveAll();
this.nsp.remove(this);
this.client.remove(this);
this.connected = false;
this.disconnected = true;
delete this.nsp.connected[this.id];
this.emit('disconnect', reason);
};
...
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); }
...
* @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;
...
send = function (){ var args = Array.prototype.slice.call(arguments); args.unshift('message'); this.emit.apply(this, args); return this; }
n/a
to = function (name){ this.rooms = this.rooms || []; if (!~this.rooms.indexOf(name)) this.rooms.push(name); return this; }
...
only be _broadcasted_ to clients that have joined the given `room`.
To emit to multiple rooms, you can call `to` several times.
```js
var io = require('socket.io')();
io.on('connection', function(client){
client.to('others').emit('an event', { some: 'data' });
});
```
### Socket#in(room:String):Socket
Same as `Socket#to`
...
use = function (fn){ this.fns.push(fn); return this; }
...
Registers a middleware, which is a function that gets executed for
every incoming `Socket`, and receives as parameters the socket and a
function to optionally defer execution to the next registered
middleware.
```js
var io = require('socket.io')();
io.use(function(socket, next){
if (socket.request.headers.cookie) return next();
next(new Error('Authentication error'));
});
```
Errors passed to middleware callbacks are sent as special `error`
packets to clients.
...
write = function (){ var args = Array.prototype.slice.call(arguments); args.unshift('message'); this.emit.apply(this, args); return this; }
...
opts = opts || {};
var self = this;
// this writes to the actual connection
function writeToEngine(encodedPackets) {
if (opts.volatile && !self.conn.transport.writable) return;
for (var i = 0; i < encodedPackets.length; i++) {
self.conn.write(encodedPackets[i], { compress: opts.compress });
}
}
if ('open' == this.conn.readyState) {
debug('writing packet %j', packet);
if (!opts.preEncoded) { // not broadcasting, need to encode
this.encoder.encode(packet, function (encodedPackets) { // encode, then write results to engine
...
function Socket(nsp, client, query){ this.nsp = nsp; this.server = nsp.server; this.adapter = this.nsp.adapter; this.id = nsp.name !== '/' ? nsp.name + '#' + client.id : client.id; this.client = client; this.conn = client.conn; this.rooms = {}; this.acks = {}; this.connected = true; this.disconnected = false; this.handshake = this.buildHandshake(query); this.fns = []; }
n/a
ack = function (id){ var self = this; var sent = false; return function(){ // prevent double callbacks if (sent) return; var args = Array.prototype.slice.call(arguments); debug('sending ack %j', args); var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK; self.packet({ id: id, type: type, data: args }); sent = true; }; }
...
Socket.prototype.onevent = function(packet){
var args = packet.data || [];
debug('emitting event %j', args);
if (null != packet.id) {
debug('attaching ack callback to event');
args.push(this.ack(packet.id));
}
this.dispatch(args);
};
/**
* Produces an ack callback to emit with an event.
...
buildHandshake = function (query){ var self = this; function buildQuery(){ var requestQuery = url.parse(self.request.url, true).query; //if socket-specific query exist, replace query strings in requestQuery return assign({}, query, requestQuery); } return { headers: this.request.headers, time: (new Date) + '', address: this.conn.remoteAddress, xdomain: !!this.request.headers.origin, secure: !!this.request.connection.encrypted, issued: +(new Date), url: this.request.url, query: buildQuery() }; }
...
this.id = nsp.name !== '/' ? nsp.name + '#' + client.id : client.id;
this.client = client;
this.conn = client.conn;
this.rooms = {};
this.acks = {};
this.connected = true;
this.disconnected = false;
this.handshake = this.buildHandshake(query);
this.fns = [];
}
/**
* Inherits from `EventEmitter`.
*/
...
compress = function (compress){ this.flags = this.flags || {}; this.flags.compress = compress; return this; }
...
Sets a modifier for a subsequent event emission that the event data will
only be _compressed_ if the value is `true`. Defaults to `true` when you don't call the method.
```js
var io = require('socket.io')();
io.on('connection', function(client){
client.compress(false).emit('an event', { some: 'data' });
});
```
### Socket#disconnect(close:Boolean):Socket
Disconnects this client. If value of close is `true`, closes the underlying connection.
Otherwise, it just disconnects the namespace.
...
disconnect = function (close){ if (!this.connected) return this; if (close) { this.client.disconnect(); } else { this.packet({ type: parser.DISCONNECT }); this.onclose('server namespace disconnect'); } return this; }
...
*
* @api private
*/
Client.prototype.disconnect = function(){
for (var id in this.sockets) {
if (this.sockets.hasOwnProperty(id)) {
this.sockets[id].disconnect();
}
}
this.sockets = {};
this.close();
};
/**
...
dispatch = function (event){ debug('dispatching an event %j', event); var self = this; this.run(event, function(err){ process.nextTick(function(){ if (err) { return self.error(err.data || err.message); } emit.apply(self, event); }); }); }
...
debug('emitting event %j', args);
if (null != packet.id) {
debug('attaching ack callback to event');
args.push(this.ack(packet.id));
}
this.dispatch(args);
};
/**
* Produces an ack callback to emit with an event.
*
* @param {Number} id packet id
* @api private
...
emit = function (ev){ if (~exports.events.indexOf(ev)) { emit.apply(this, arguments); } else { var args = Array.prototype.slice.call(arguments); var packet = {}; packet.type = hasBin(args) ? parser.BINARY_EVENT : parser.EVENT; packet.data = args; var flags = this.flags || {}; // access last argument to see if it's an ACK callback if ('function' == typeof args[args.length - 1]) { if (this._rooms || flags.broadcast) { throw new Error('Callbacks are not supported when broadcasting'); } debug('emitting packet with ack id %d', this.nsp.ids); this.acks[this.nsp.ids] = args.pop(); packet.id = this.nsp.ids++; } if (this._rooms || flags.broadcast) { this.adapter.broadcast(packet, { except: [this.id], rooms: this._rooms, flags: flags }); } else { // dispatch packet this.packet(packet, { volatile: flags.volatile, compress: flags.compress }); } // reset flags delete this._rooms; delete this.flags; } return this; }
...
### Server#emit
Emits an event to all connected clients. The following two are
equivalent:
```js
var io = require('socket.io')();
io.sockets.emit('an event sent to all connected clients');
io.emit('an event sent to all connected clients');
```
For other available methods, see `Namespace` below.
### Server#close([fn:Function])
...
error = function (err){ this.packet({ type: parser.ERROR, data: err }); }
...
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
...
in = function (name){ this._rooms = this._rooms || []; if (!~this._rooms.indexOf(name)) this._rooms.push(name); return this; }
...
});
```
An example to get all clients in namespace's room:
```js
var io = require('socket.io')();
io.of('/chat').in('general').clients(function(error, clients){
if (error) throw error;
console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
});
```
As with broadcasting, the default is all clients from the default namespace ('/'):
...
join = function (room, fn){ debug('joining room %s', room); var self = this; if (this.rooms.hasOwnProperty(room)) { fn && fn(null); return this; } this.adapter.add(this.id, room, function(err){ if (err) return fn && fn(err); debug('joined room %s', room); self.rooms[room] = room; fn && fn(null); }); return this; }
...
*
* @api private
*/
Socket.prototype.onconnect = function(){
debug('socket connected - writing packet');
this.nsp.connected[this.id] = this;
this.join(this.id);
this.packet({ type: parser.CONNECT });
};
/**
* Called with each packet. Called by `Client`.
*
* @param {Object} packet
...
leave = function (room, fn){ debug('leave room %s', room); var self = this; this.adapter.del(this.id, room, function(err){ if (err) return fn && fn(err); debug('left room %s', room); delete self.rooms[room]; fn && fn(null); }); return this; }
n/a
leaveAll = function (){ this.adapter.delAll(this.id); this.rooms = {}; }
...
* @api private
*/
Socket.prototype.onclose = function(reason){
if (!this.connected) return this;
debug('closing socket - reason %s', reason);
this.emit('disconnecting', reason);
this.leaveAll();
this.nsp.remove(this);
this.client.remove(this);
this.connected = false;
this.disconnected = true;
delete this.nsp.connected[this.id];
this.emit('disconnect', reason);
};
...
onack = function (packet){ var ack = this.acks[packet.id]; if ('function' == typeof ack) { debug('calling ack %s with %j', packet.id, packet.data); ack.apply(this, packet.data); delete this.acks[packet.id]; } else { debug('bad ack %s', packet.id); } }
...
break;
case parser.BINARY_EVENT:
this.onevent(packet);
break;
case parser.ACK:
this.onack(packet);
break;
case parser.BINARY_ACK:
this.onack(packet);
break;
case parser.DISCONNECT:
...
onclose = function (reason){ if (!this.connected) return this; debug('closing socket - reason %s', reason); this.emit('disconnecting', reason); this.leaveAll(); this.nsp.remove(this); this.client.remove(this); this.connected = false; this.disconnected = true; delete this.nsp.connected[this.id]; this.emit('disconnect', reason); }
...
* @api private
*/
Client.prototype.close = function(){
if ('open' == this.conn.readyState) {
debug('forcing transport close');
this.conn.close();
this.onclose('forced server close');
}
};
/**
* Writes a packet to the transport.
*
* @param {Object} packet object
...
onconnect = function (){ debug('socket connected - writing packet'); this.nsp.connected[this.id] = this; this.join(this.id); this.packet({ type: parser.CONNECT }); }
...
// 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');
...
ondisconnect = function (){ debug('got disconnect packet'); this.onclose('client namespace disconnect'); }
...
break;
case parser.BINARY_ACK:
this.onack(packet);
break;
case parser.DISCONNECT:
this.ondisconnect();
break;
case parser.ERROR:
this.emit('error', packet.data);
}
};
...
onerror = function (err){ if (this.listeners('error').length) { this.emit('error', err); } else { console.error('Missing error handler on `socket`.'); console.error(err.stack); } }
...
*/
Client.prototype.ondata = function(data){
// try/catch is needed for protocol violations (GH-1880)
try {
this.decoder.add(data);
} catch(e) {
this.onerror(e);
}
};
/**
* Called when parser fully decodes a packet.
*
* @api private
...
onevent = function (packet){ var args = packet.data || []; debug('emitting event %j', args); if (null != packet.id) { debug('attaching ack callback to event'); args.push(this.ack(packet.id)); } this.dispatch(args); }
...
* @api private
*/
Socket.prototype.onpacket = function(packet){
debug('got packet %j', packet);
switch (packet.type) {
case parser.EVENT:
this.onevent(packet);
break;
case parser.BINARY_EVENT:
this.onevent(packet);
break;
case parser.ACK:
...
onpacket = function (packet){ debug('got packet %j', packet); switch (packet.type) { case parser.EVENT: this.onevent(packet); break; case parser.BINARY_EVENT: this.onevent(packet); break; case parser.ACK: this.onack(packet); break; case parser.BINARY_ACK: this.onack(packet); break; case parser.DISCONNECT: this.ondisconnect(); break; case parser.ERROR: this.emit('error', packet.data); } }
...
Client.prototype.ondecoded = function(packet) {
if (parser.CONNECT == packet.type) {
this.connect(url.parse(packet.nsp).pathname, url.parse(packet.nsp, true).query);
} else {
var socket = this.nsps[packet.nsp];
if (socket) {
process.nextTick(function() {
socket.onpacket(packet);
});
} else {
debug('no socket for namespace %s', packet.nsp);
}
}
};
...
packet = function (packet, opts){ packet.nsp = this.nsp.name; opts = opts || {}; opts.compress = false !== opts.compress; this.client.packet(packet, opts); }
...
* @api private
*/
Client.prototype.connect = function(name, query){
debug('connecting to namespace %s', name);
var nsp = this.server.nsps[name];
if (!nsp) {
this.packet({ type: parser.ERROR, nsp: name, data : 'Invalid namespace'});
return;
}
if ('/' != name && !this.nsps['/']) {
this.connectBuffer.push(name);
return;
}
...
run = function (event, fn){ var fns = this.fns.slice(0); if (!fns.length) return fn(null); function run(i){ fns[i](event, 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); }
...
* @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;
...
send = function (){ var args = Array.prototype.slice.call(arguments); args.unshift('message'); this.emit.apply(this, args); return this; }
n/a
to = function (name){ this._rooms = this._rooms || []; if (!~this._rooms.indexOf(name)) this._rooms.push(name); return this; }
...
only be _broadcasted_ to clients that have joined the given `room`.
To emit to multiple rooms, you can call `to` several times.
```js
var io = require('socket.io')();
io.on('connection', function(client){
client.to('others').emit('an event', { some: 'data' });
});
```
### Socket#in(room:String):Socket
Same as `Socket#to`
...
use = function (fn){ this.fns.push(fn); return this; }
...
Registers a middleware, which is a function that gets executed for
every incoming `Socket`, and receives as parameters the socket and a
function to optionally defer execution to the next registered
middleware.
```js
var io = require('socket.io')();
io.use(function(socket, next){
if (socket.request.headers.cookie) return next();
next(new Error('Authentication error'));
});
```
Errors passed to middleware callbacks are sent as special `error`
packets to clients.
...
write = function (){ var args = Array.prototype.slice.call(arguments); args.unshift('message'); this.emit.apply(this, args); return this; }
...
opts = opts || {};
var self = this;
// this writes to the actual connection
function writeToEngine(encodedPackets) {
if (opts.volatile && !self.conn.transport.writable) return;
for (var i = 0; i < encodedPackets.length; i++) {
self.conn.write(encodedPackets[i], { compress: opts.compress });
}
}
if ('open' == this.conn.readyState) {
debug('writing packet %j', packet);
if (!opts.preEncoded) { // not broadcasting, need to encode
this.encoder.encode(packet, function (encodedPackets) { // encode, then write results to engine
...