complete redesign: use nodejs on server instead of php - documentation to be updated

This commit is contained in:
Marc Wäckerlin
2016-01-10 23:17:30 +00:00
parent 1c3765955b
commit a56d3118de
1376 changed files with 183732 additions and 1253 deletions

251
nodejs/node_modules/socket.io/lib/client.js generated vendored Normal file
View File

@@ -0,0 +1,251 @@
/**
* Module dependencies.
*/
var parser = require('socket.io-parser');
var debug = require('debug')('socket.io:client');
/**
* Module exports.
*/
module.exports = Client;
/**
* Client constructor.
*
* @param {Server} server instance
* @param {Socket} connection
* @api private
*/
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.
*
* @api private
*/
Client.prototype.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);
};
/**
* Connects a client to a namespace.
*
* @param {String} namespace name
* @api private
*/
Client.prototype.connect = function(name){
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, 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 = [];
}
});
};
/**
* Disconnects from all namespaces and closes transport.
*
* @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();
};
/**
* Removes a socket. Called by each `Socket`.
*
* @api private
*/
Client.prototype.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);
}
};
/**
* Closes the underlying connection.
*
* @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
* @param {Object} options
* @api private
*/
Client.prototype.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);
}
};
/**
* Called with incoming transport data.
*
* @api private
*/
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
*/
Client.prototype.ondecoded = function(packet) {
if (parser.CONNECT == packet.type) {
this.connect(packet.nsp);
} else {
var socket = this.nsps[packet.nsp];
if (socket) {
socket.onpacket(packet);
} else {
debug('no socket for namespace %s', packet.nsp);
}
}
};
/**
* Handles an error.
*
* @param {Objcet} error object
* @api private
*/
Client.prototype.onerror = function(err){
for (var id in this.sockets) {
if (this.sockets.hasOwnProperty(id)) {
this.sockets[id].onerror(err);
}
}
this.onclose('client error');
};
/**
* Called upon transport close.
*
* @param {String} reason
* @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);
}
}
this.sockets = {};
this.decoder.destroy(); // clean up decoder
};
/**
* Cleans up event listeners.
*
* @api private
*/
Client.prototype.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);
};

386
nodejs/node_modules/socket.io/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,386 @@
/**
* Module dependencies.
*/
var http = require('http');
var read = require('fs').readFileSync;
var parse = require('url').parse;
var engine = require('engine.io');
var client = require('socket.io-client');
var clientVersion = require('socket.io-client/package').version;
var Client = require('./client');
var Namespace = require('./namespace');
var Adapter = require('socket.io-adapter');
var debug = require('debug')('socket.io:server');
var url = require('url');
/**
* Module exports.
*/
module.exports = Server;
/**
* Socket.IO client source.
*/
var clientSource = read(require.resolve('socket.io-client/socket.io.js'), 'utf-8');
/**
* Server constructor.
*
* @param {http.Server|Number|Object} http server, port or options
* @param {Object} options
* @api public
*/
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);
}
/**
* Server request verification function, that checks for allowed origins
*
* @param {http.IncomingMessage} request
* @param {Function} callback to be called with the result: `fn(err, success)`
*/
Server.prototype.checkRequest = function(req, fn) {
var origin = req.headers.origin || req.headers.referer;
// file:// URLs produce a null Origin which can't be authorized via echo-back
if ('null' == origin || null == origin) origin = '*';
if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
if (origin) {
try {
var parts = url.parse(origin);
var defaultPort = 'https:' == parts.protocol ? 443 : 80;
parts.port = parts.port != null
? parts.port
: defaultPort;
var ok =
~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
~this._origins.indexOf(parts.hostname + ':*') ||
~this._origins.indexOf('*:' + parts.port);
return fn(null, !!ok);
} catch (ex) {
}
}
fn(null, false);
};
/**
* Sets/gets whether client code is being served.
*
* @param {Boolean} whether to serve client code
* @return {Server|Boolean} self when setting or value when getting
* @api public
*/
Server.prototype.serveClient = function(v){
if (!arguments.length) return this._serveClient;
this._serveClient = v;
return this;
};
/**
* Old settings for backwards compatibility
*/
var oldSettings = {
"transports": "transports",
"heartbeat timeout": "pingTimeout",
"heartbeat interval": "pingInterval",
"destroy buffer size": "maxHttpBufferSize"
};
/**
* Backwards compatiblity.
*
* @api public
*/
Server.prototype.set = function(key, val){
if ('authorization' == key && val) {
this.use(function(socket, next) {
val(socket.request, function(err, authorized) {
if (err) return next(new Error(err));
if (!authorized) return next(new Error('Not authorized'));
next();
});
});
} else if ('origins' == key && val) {
this.origins(val);
} else if ('resource' == key) {
this.path(val);
} else if (oldSettings[key] && this.eio[oldSettings[key]]) {
this.eio[oldSettings[key]] = val;
} else {
console.error('Option %s is not valid. Please refer to the README.', key);
}
return this;
};
/**
* Sets the client serving path.
*
* @param {String} pathname
* @return {Server|String} self when setting or value when getting
* @api public
*/
Server.prototype.path = function(v){
if (!arguments.length) return this._path;
this._path = v.replace(/\/$/, '');
return this;
};
/**
* Sets the adapter for rooms.
*
* @param {Adapter} pathname
* @return {Server|Adapter} self when setting or value when getting
* @api public
*/
Server.prototype.adapter = function(v){
if (!arguments.length) return this._adapter;
this._adapter = v;
for (var i in this.nsps) {
if (this.nsps.hasOwnProperty(i)) {
this.nsps[i].initAdapter();
}
}
return this;
};
/**
* Sets the allowed origins for requests.
*
* @param {String} origins
* @return {Server|Adapter} self when setting or value when getting
* @api public
*/
Server.prototype.origins = function(v){
if (!arguments.length) return this._origins;
this._origins = v;
return this;
};
/**
* Attaches socket.io to a server or port.
*
* @param {http.Server|Number} server or port
* @param {Object} options passed to engine.io
* @return {Server} self
* @api public
*/
Server.prototype.listen =
Server.prototype.attach = function(srv, opts){
if ('function' == typeof srv) {
var msg = 'You are trying to attach socket.io to an express ' +
'request handler function. Please pass a http.Server instance.';
throw new Error(msg);
}
// handle a port as a string
if (Number(srv) == srv) {
srv = Number(srv);
}
if ('number' == typeof srv) {
debug('creating http server and binding to %d', srv);
var port = srv;
srv = http.Server(function(req, res){
res.writeHead(404);
res.end();
});
srv.listen(port);
}
// set engine.io path to `/socket.io`
opts = opts || {};
opts.path = opts.path || this.path();
// set origins verification
opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);
// initialize engine
debug('creating engine.io instance with opts %j', opts);
this.eio = engine.attach(srv, opts);
// attach static file serving
if (this._serveClient) this.attachServe(srv);
// Export http server
this.httpServer = srv;
// bind to engine events
this.bind(this.eio);
return this;
};
/**
* Attaches the static file serving.
*
* @param {Function|http.Server} http server
* @api private
*/
Server.prototype.attachServe = function(srv){
debug('attaching client serving req handler');
var url = this._path + '/socket.io.js';
var evs = srv.listeners('request').slice(0);
var self = this;
srv.removeAllListeners('request');
srv.on('request', function(req, res) {
if (0 === req.url.indexOf(url)) {
self.serve(req, res);
} else {
for (var i = 0; i < evs.length; i++) {
evs[i].call(srv, req, res);
}
}
});
};
/**
* Handles a request serving `/socket.io.js`
*
* @param {http.Request} req
* @param {http.Response} res
* @api private
*/
Server.prototype.serve = function(req, res){
var etag = req.headers['if-none-match'];
if (etag) {
if (clientVersion == etag) {
debug('serve client 304');
res.writeHead(304);
res.end();
return;
}
}
debug('serve client source');
res.setHeader('Content-Type', 'application/javascript');
res.setHeader('ETag', clientVersion);
res.writeHead(200);
res.end(clientSource);
};
/**
* Binds socket.io to an engine.io instance.
*
* @param {engine.Server} engine.io (or compatible) server
* @return {Server} self
* @api public
*/
Server.prototype.bind = function(engine){
this.engine = engine;
this.engine.on('connection', this.onconnection.bind(this));
return this;
};
/**
* Called with each incoming transport connection.
*
* @param {engine.Socket} socket
* @return {Server} self
* @api public
*/
Server.prototype.onconnection = function(conn){
debug('incoming connection with id %s', conn.id);
var client = new Client(this, conn);
client.connect('/');
return this;
};
/**
* Looks up a namespace.
*
* @param {String} nsp name
* @param {Function} optional, nsp `connection` ev handler
* @api public
*/
Server.prototype.of = function(name, fn){
if (String(name)[0] !== '/') name = '/' + name;
var nsp = this.nsps[name];
if (!nsp) {
debug('initializing namespace %s', name);
nsp = new Namespace(this, name);
this.nsps[name] = nsp;
}
if (fn) nsp.on('connect', fn);
return nsp;
};
/**
* Closes server connection
*
* @api public
*/
Server.prototype.close = function(){
for (var id in this.nsps['/'].sockets) {
if (this.nsps['/'].sockets.hasOwnProperty(id)) {
this.nsps['/'].sockets[id].onclose();
}
}
this.engine.close();
if(this.httpServer){
this.httpServer.close();
}
};
/**
* Expose main namespace (/).
*/
['on', 'to', 'in', 'use', 'emit', 'send', 'write', 'clients', 'compress'].forEach(function(fn){
Server.prototype[fn] = function(){
var nsp = this.sockets[fn];
return nsp.apply(this.sockets, arguments);
};
});
Namespace.flags.forEach(function(flag){
Server.prototype.__defineGetter__(flag, function(){
this.sockets.flags = this.sockets.flags || {};
this.sockets.flags[flag] = true;
return this;
});
});
/**
* BC with `io.listen`
*/
Server.listen = Server;

272
nodejs/node_modules/socket.io/lib/namespace.js generated vendored Normal file
View File

@@ -0,0 +1,272 @@
/**
* 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'
];
/**
* `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){
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
*/
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} 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, 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[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} 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;
};

470
nodejs/node_modules/socket.io/lib/socket.js generated vendored Normal file
View File

@@ -0,0 +1,470 @@
/**
* Module dependencies.
*/
var Emitter = require('events').EventEmitter;
var parser = require('socket.io-parser');
var url = require('url');
var debug = require('debug')('socket.io:socket');
var hasBin = require('has-binary');
/**
* Module exports.
*/
module.exports = exports = Socket;
/**
* Blacklisted events.
*
* @api public
*/
exports.events = [
'error',
'connect',
'disconnect',
'newListener',
'removeListener'
];
/**
* Flags.
*
* @api private
*/
var flags = [
'json',
'volatile',
'broadcast'
];
/**
* `EventEmitter#emit` reference.
*/
var emit = Emitter.prototype.emit;
/**
* Interface to a `Client` for a given `Namespace`.
*
* @param {Namespace} nsp
* @param {Client} client
* @api public
*/
function Socket(nsp, client){
this.nsp = nsp;
this.server = nsp.server;
this.adapter = this.nsp.adapter;
this.id = nsp.name + '#' + client.id;
this.client = client;
this.conn = client.conn;
this.rooms = {};
this.acks = {};
this.connected = true;
this.disconnected = false;
this.handshake = this.buildHandshake();
}
/**
* Inherits from `EventEmitter`.
*/
Socket.prototype.__proto__ = Emitter.prototype;
/**
* Apply flags from `Socket`.
*/
flags.forEach(function(flag){
Socket.prototype.__defineGetter__(flag, function(){
this.flags = this.flags || {};
this.flags[flag] = true;
return this;
});
});
/**
* `request` engine.io shorcut.
*
* @api public
*/
Socket.prototype.__defineGetter__('request', function(){
return this.conn.request;
});
/**
* Builds the `handshake` BC object
*
* @api private
*/
Socket.prototype.buildHandshake = function(){
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: url.parse(this.request.url, true).query || {}
};
};
/**
* Emits to this client.
*
* @return {Socket} self
* @api public
*/
Socket.prototype.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;
};
/**
* Targets a room when broadcasting.
*
* @param {String} name
* @return {Socket} self
* @api public
*/
Socket.prototype.to =
Socket.prototype.in = function(name){
this._rooms = this._rooms || [];
if (!~this._rooms.indexOf(name)) this._rooms.push(name);
return this;
};
/**
* Sends a `message` event.
*
* @return {Socket} self
* @api public
*/
Socket.prototype.send =
Socket.prototype.write = function(){
var args = Array.prototype.slice.call(arguments);
args.unshift('message');
this.emit.apply(this, args);
return this;
};
/**
* Writes a packet.
*
* @param {Object} packet object
* @param {Object} options
* @api private
*/
Socket.prototype.packet = function(packet, opts){
packet.nsp = this.nsp.name;
opts = opts || {};
opts.compress = false !== opts.compress;
this.client.packet(packet, opts);
};
/**
* Joins a room.
*
* @param {String} room
* @param {Function} optional, callback
* @return {Socket} self
* @api private
*/
Socket.prototype.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;
};
/**
* Leaves a room.
*
* @param {String} room
* @param {Function} optional, callback
* @return {Socket} self
* @api private
*/
Socket.prototype.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;
};
/**
* Leave all rooms.
*
* @api private
*/
Socket.prototype.leaveAll = function(){
this.adapter.delAll(this.id);
this.rooms = {};
};
/**
* Called by `Namespace` upon succesful
* middleware execution (ie: authorization).
*
* @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
* @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:
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);
}
};
/**
* Called upon event packet.
*
* @param {Object} packet object
* @api private
*/
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));
}
emit.apply(this, args);
};
/**
* Produces an ack callback to emit with an event.
*
* @param {Number} packet id
* @api private
*/
Socket.prototype.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;
};
};
/**
* Called upon ack packet.
*
* @api private
*/
Socket.prototype.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);
}
};
/**
* Called upon client disconnect packet.
*
* @api private
*/
Socket.prototype.ondisconnect = function(){
debug('got disconnect packet');
this.onclose('client namespace disconnect');
};
/**
* Handles a client error.
*
* @api private
*/
Socket.prototype.onerror = function(err){
if (this.listeners('error').length) {
this.emit('error', err);
} else {
console.error('Missing error handler on `socket`.');
console.error(err.stack);
}
};
/**
* Called upon closing. Called by `Client`.
*
* @param {String} reason
* @param {Error} optional error object
* @api private
*/
Socket.prototype.onclose = function(reason){
if (!this.connected) return this;
debug('closing socket - reason %s', 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);
};
/**
* Produces an `error` packet.
*
* @param {Object} error object
* @api private
*/
Socket.prototype.error = function(err){
this.packet({ type: parser.ERROR, data: err });
};
/**
* Disconnects this client.
*
* @param {Boolean} if `true`, closes the underlying connection
* @return {Socket} self
* @api public
*/
Socket.prototype.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;
};
/**
* Sets the compress flag.
*
* @param {Boolean} if `true`, compresses the sending data
* @return {Socket} self
* @api public
*/
Socket.prototype.compress = function(compress){
this.flags = this.flags || {};
this.flags.compress = compress;
return this;
};