Added node-modules

This commit is contained in:
Dobie Wollert
2014-09-14 07:04:16 -04:00
parent 663941bf57
commit 6a92348cf5
4870 changed files with 670395 additions and 0 deletions

97
node_modules/socket.io/lib/logger.js generated vendored Normal file
View File

@ -0,0 +1,97 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var util = require('./util')
, toArray = util.toArray;
/**
* Log levels.
*/
var levels = [
'error'
, 'warn'
, 'info'
, 'debug'
];
/**
* Colors for log levels.
*/
var colors = [
31
, 33
, 36
, 90
];
/**
* Pads the nice output to the longest log level.
*/
function pad (str) {
var max = 0;
for (var i = 0, l = levels.length; i < l; i++)
max = Math.max(max, levels[i].length);
if (str.length < max)
return str + new Array(max - str.length + 1).join(' ');
return str;
};
/**
* Logger (console).
*
* @api public
*/
var Logger = module.exports = function (opts) {
opts = opts || {}
this.colors = false !== opts.colors;
this.level = 3;
this.enabled = true;
};
/**
* Log method.
*
* @api public
*/
Logger.prototype.log = function (type) {
var index = levels.indexOf(type);
if (index > this.level || !this.enabled)
return this;
console.log.apply(
console
, [this.colors
? ' \033[' + colors[index] + 'm' + pad(type) + ' -\033[39m'
: type + ':'
].concat(toArray(arguments).slice(1))
);
return this;
};
/**
* Generate methods.
*/
levels.forEach(function (name) {
Logger.prototype[name] = function () {
this.log.apply(this, [name].concat(toArray(arguments)));
};
});

1027
node_modules/socket.io/lib/manager.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,355 @@
/**
* Module dependencies.
*/
var Socket = require('./socket')
, EventEmitter = process.EventEmitter
, parser = require('./parser')
, util = require('./util');
/**
* Exports the constructor.
*/
exports = module.exports = SocketNamespace;
/**
* Constructor.
*
* @api public.
*/
function SocketNamespace (mgr, name) {
this.manager = mgr;
this.name = name || '';
this.sockets = {};
this.auth = false;
this.setFlags();
};
/**
* Inherits from EventEmitter.
*/
SocketNamespace.prototype.__proto__ = EventEmitter.prototype;
/**
* Copies emit since we override it.
*
* @api private
*/
SocketNamespace.prototype.$emit = EventEmitter.prototype.emit;
/**
* Retrieves all clients as Socket instances as an array.
*
* @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 : '');
return this;
};
/**
* Adds a session id we should prevent relaying messages to (flag).
*
* @api public
*/
SocketNamespace.prototype.except = function (id) {
this.flags.exceptions.push(id);
return this;
};
/**
* Sets the default flags.
*
* @api private
*/
SocketNamespace.prototype.setFlags = function () {
this.flags = {
endpoint: this.name
, exceptions: []
};
return this;
};
/**
* Sends out a packet.
*
* @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.
*
* @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;
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);
};
};

249
node_modules/socket.io/lib/parser.js generated vendored Normal file
View File

@ -0,0 +1,249 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
/**
* Packet types.
*/
var packets = exports.packets = {
'disconnect': 0
, 'connect': 1
, 'heartbeat': 2
, 'message': 3
, 'json': 4
, 'event': 5
, 'ack': 6
, 'error': 7
, 'noop': 8
}
, packetslist = Object.keys(packets);
/**
* Errors reasons.
*/
var reasons = exports.reasons = {
'transport not supported': 0
, 'client not handshaken': 1
, 'unauthorized': 2
}
, reasonslist = Object.keys(reasons);
/**
* Errors advice.
*/
var advice = exports.advice = {
'reconnect': 0
}
, advicelist = Object.keys(advice);
/**
* Encodes a packet.
*
* @api private
*/
exports.encodePacket = function (packet) {
var type = packets[packet.type]
, id = packet.id || ''
, endpoint = packet.endpoint || ''
, ack = packet.ack
, data = null;
switch (packet.type) {
case 'message':
if (packet.data !== '')
data = packet.data;
break;
case 'event':
var ev = { name: packet.name };
if (packet.args && packet.args.length) {
ev.args = packet.args;
}
data = JSON.stringify(ev);
break;
case 'json':
data = JSON.stringify(packet.data);
break;
case 'ack':
data = packet.ackId
+ (packet.args && packet.args.length
? '+' + JSON.stringify(packet.args) : '');
break;
case 'connect':
if (packet.qs)
data = packet.qs;
break;
case 'error':
var reason = packet.reason ? reasons[packet.reason] : ''
, adv = packet.advice ? advice[packet.advice] : ''
if (reason !== '' || adv !== '')
data = reason + (adv !== '' ? ('+' + adv) : '')
break;
}
// construct packet with required fragments
var encoded = type + ':' + id + (ack == 'data' ? '+' : '') + ':' + endpoint;
// data fragment is optional
if (data !== null && data !== undefined)
encoded += ':' + data;
return encoded;
};
/**
* Encodes multiple messages (payload).
*
* @param {Array} messages
* @api private
*/
exports.encodePayload = function (packets) {
var decoded = '';
if (packets.length == 1)
return packets[0];
for (var i = 0, l = packets.length; i < l; i++) {
var packet = packets[i];
decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
}
return decoded;
};
/**
* Decodes a packet
*
* @api private
*/
var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
/**
* Wrap the JSON.parse in a seperate function the crankshaft optimizer will
* only punish this function for the usage for try catch
*
* @api private
*/
function parse (data) {
try { return JSON.parse(data) }
catch (e) { return false }
}
exports.decodePacket = function (data) {
var pieces = data.match(regexp);
if (!pieces) return {};
var id = pieces[2] || ''
, data = pieces[5] || ''
, packet = {
type: packetslist[pieces[1]]
, endpoint: pieces[4] || ''
};
// whether we need to acknowledge the packet
if (id) {
packet.id = id;
if (pieces[3])
packet.ack = 'data';
else
packet.ack = true;
}
// handle different packet types
switch (packet.type) {
case 'message':
packet.data = data || '';
break;
case 'event':
pieces = parse(data);
if (pieces) {
packet.name = pieces.name;
packet.args = pieces.args;
}
packet.args = packet.args || [];
break;
case 'json':
packet.data = parse(data);
break;
case 'connect':
packet.qs = data || '';
break;
case 'ack':
pieces = data.match(/^([0-9]+)(\+)?(.*)/);
if (pieces) {
packet.ackId = pieces[1];
packet.args = [];
if (pieces[3]) {
packet.args = parse(pieces[3]) || [];
}
}
break;
case 'error':
pieces = data.split('+');
packet.reason = reasonslist[pieces[0]] || '';
packet.advice = advicelist[pieces[1]] || '';
}
return packet;
};
/**
* Decodes data payload. Detects multiple messages
*
* @return {Array} messages
* @api public
*/
exports.decodePayload = function (data) {
if (undefined == data || null == data) {
return [];
}
if (data[0] == '\ufffd') {
var ret = [];
for (var i = 1, length = ''; i < data.length; i++) {
if (data[i] == '\ufffd') {
ret.push(exports.decodePacket(data.substr(i + 1, length)));
i += Number(length) + 1;
length = '';
} else {
length += data[i];
}
}
return ret;
} else {
return [exports.decodePacket(data)];
}
};

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

@ -0,0 +1,143 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var client = require('socket.io-client');
/**
* Version.
*/
exports.version = '0.9.16';
/**
* Supported protocol version.
*/
exports.protocol = 1;
/**
* Client that we serve.
*/
exports.clientVersion = client.version;
/**
* Attaches a manager
*
* @param {HTTPServer/Number} a HTTP/S server or a port number to listen on.
* @param {Object} opts to be passed to Manager and/or http server
* @param {Function} callback if a port is supplied
* @api public
*/
exports.listen = function (server, options, fn) {
if ('function' == typeof server) {
console.warn('Socket.IO\'s `listen()` method expects an `http.Server` instance\n'
+ 'as its first parameter. Are you migrating from Express 2.x to 3.x?\n'
+ 'If so, check out the "Socket.IO compatibility" section at:\n'
+ 'https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x');
}
if ('function' == typeof options) {
fn = options;
options = {};
}
if ('undefined' == typeof server) {
// create a server that listens on port 80
server = 80;
}
if ('number' == typeof server) {
// if a port number is passed
var port = server;
if (options && options.key)
server = require('https').createServer(options);
else
server = require('http').createServer();
// default response
server.on('request', function (req, res) {
res.writeHead(200);
res.end('Welcome to socket.io.');
});
server.listen(port, fn);
}
// otherwise assume a http/s server
return new exports.Manager(server, options);
};
/**
* Manager constructor.
*
* @api public
*/
exports.Manager = require('./manager');
/**
* Transport constructor.
*
* @api public
*/
exports.Transport = require('./transport');
/**
* Socket constructor.
*
* @api public
*/
exports.Socket = require('./socket');
/**
* Static constructor.
*
* @api public
*/
exports.Static = require('./static');
/**
* Store constructor.
*
* @api public
*/
exports.Store = require('./store');
/**
* Memory Store constructor.
*
* @api public
*/
exports.MemoryStore = require('./stores/memory');
/**
* Redis Store constructor.
*
* @api public
*/
exports.RedisStore = require('./stores/redis');
/**
* Parser.
*
* @api public
*/
exports.parser = require('./parser');

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

@ -0,0 +1,369 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var parser = require('./parser')
, util = require('./util')
, EventEmitter = process.EventEmitter
/**
* Export the constructor.
*/
exports = module.exports = Socket;
/**
* Default error event listener to prevent uncaught exceptions.
*/
var defaultError = function () {};
/**
* Socket constructor.
*
* @param {Manager} manager instance
* @param {String} session id
* @param {Namespace} namespace the socket belongs to
* @param {Boolean} whether the
* @api public
*/
function Socket (manager, id, nsp, readable) {
this.id = id;
this.namespace = nsp;
this.manager = manager;
this.disconnected = false;
this.ackPackets = 0;
this.acks = {};
this.setFlags();
this.readable = readable;
this.store = this.manager.store.client(this.id);
this.on('error', defaultError);
};
/**
* Inherits from EventEmitter.
*/
Socket.prototype.__proto__ = EventEmitter.prototype;
/**
* Accessor shortcut for the handshake data
*
* @api private
*/
Socket.prototype.__defineGetter__('handshake', function () {
return this.manager.handshaken[this.id];
});
/**
* Accessor shortcut for the transport type
*
* @api private
*/
Socket.prototype.__defineGetter__('transport', function () {
return this.manager.transports[this.id].name;
});
/**
* Accessor shortcut for the logger.
*
* @api private
*/
Socket.prototype.__defineGetter__('log', function () {
return this.manager.log;
});
/**
* JSON message flag.
*
* @api public
*/
Socket.prototype.__defineGetter__('json', function () {
this.flags.json = true;
return this;
});
/**
* Volatile message flag.
*
* @api public
*/
Socket.prototype.__defineGetter__('volatile', function () {
this.flags.volatile = true;
return this;
});
/**
* Broadcast message flag.
*
* @api public
*/
Socket.prototype.__defineGetter__('broadcast', function () {
this.flags.broadcast = true;
return this;
});
/**
* Overrides the room to broadcast messages to (flag)
*
* @api public
*/
Socket.prototype.to = Socket.prototype.in = function (room) {
this.flags.room = room;
return this;
};
/**
* Resets flags
*
* @api private
*/
Socket.prototype.setFlags = function () {
this.flags = {
endpoint: this.namespace.name
, room: ''
};
return this;
};
/**
* Triggered on disconnect
*
* @api private
*/
Socket.prototype.onDisconnect = function (reason) {
if (!this.disconnected) {
this.$emit('disconnect', reason);
this.disconnected = true;
}
};
/**
* Joins a user to a room.
*
* @api public
*/
Socket.prototype.join = function (name, fn) {
var nsp = this.namespace.name
, name = (nsp + '/') + name;
this.manager.onJoin(this.id, name);
this.manager.store.publish('join', this.id, name);
if (fn) {
this.log.warn('Client#join callback is deprecated');
fn();
}
return this;
};
/**
* Un-joins a user from a room.
*
* @api public
*/
Socket.prototype.leave = function (name, fn) {
var nsp = this.namespace.name
, name = (nsp + '/') + name;
this.manager.onLeave(this.id, name);
this.manager.store.publish('leave', this.id, name);
if (fn) {
this.log.warn('Client#leave callback is deprecated');
fn();
}
return this;
};
/**
* Transmits a packet.
*
* @api private
*/
Socket.prototype.packet = function (packet) {
if (this.flags.broadcast) {
this.log.debug('broadcasting packet');
this.namespace.in(this.flags.room).except(this.id).packet(packet);
} else {
packet.endpoint = this.flags.endpoint;
packet = parser.encodePacket(packet);
this.dispatch(packet, this.flags.volatile);
}
this.setFlags();
return this;
};
/**
* Dispatches a packet
*
* @api private
*/
Socket.prototype.dispatch = function (packet, volatile) {
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
this.manager.transports[this.id].onDispatch(packet, volatile);
} else {
if (!volatile) {
this.manager.onClientDispatch(this.id, packet, volatile);
}
this.manager.store.publish('dispatch:' + this.id, packet, volatile);
}
};
/**
* Stores data for the client.
*
* @api public
*/
Socket.prototype.set = function (key, value, fn) {
this.store.set(key, value, fn);
return this;
};
/**
* Retrieves data for the client
*
* @api public
*/
Socket.prototype.get = function (key, fn) {
this.store.get(key, fn);
return this;
};
/**
* Checks data for the client
*
* @api public
*/
Socket.prototype.has = function (key, fn) {
this.store.has(key, fn);
return this;
};
/**
* Deletes data for the client
*
* @api public
*/
Socket.prototype.del = function (key, fn) {
this.store.del(key, fn);
return this;
};
/**
* Kicks client
*
* @api public
*/
Socket.prototype.disconnect = function () {
if (!this.disconnected) {
this.log.info('booting client');
if ('' === this.namespace.name) {
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
this.manager.transports[this.id].onForcedDisconnect();
} else {
this.manager.onClientDisconnect(this.id);
this.manager.store.publish('disconnect:' + this.id);
}
} else {
this.packet({type: 'disconnect'});
this.manager.onLeave(this.id, this.namespace.name);
this.$emit('disconnect', 'booted');
}
}
return this;
};
/**
* Send a message.
*
* @api public
*/
Socket.prototype.send = function (data, fn) {
var packet = {
type: this.flags.json ? 'json' : 'message'
, data: data
};
if (fn) {
packet.id = ++this.ackPackets;
packet.ack = true;
this.acks[packet.id] = fn;
}
return this.packet(packet);
};
/**
* Original emit function.
*
* @api private
*/
Socket.prototype.$emit = EventEmitter.prototype.emit;
/**
* Emit override for custom events.
*
* @api public
*/
Socket.prototype.emit = function (ev) {
if (ev == 'newListener') {
return this.$emit.apply(this, arguments);
}
var args = util.toArray(arguments).slice(1)
, lastArg = args[args.length - 1]
, packet = {
type: 'event'
, name: ev
};
if ('function' == typeof lastArg) {
packet.id = ++this.ackPackets;
packet.ack = lastArg.length ? 'data' : true;
this.acks[packet.id] = lastArg;
args = args.slice(0, args.length - 1);
}
packet.args = args;
return this.packet(packet);
};

395
node_modules/socket.io/lib/static.js generated vendored Normal file
View File

@ -0,0 +1,395 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var client = require('socket.io-client')
, cp = require('child_process')
, fs = require('fs')
, util = require('./util');
/**
* File type details.
*
* @api private
*/
var mime = {
js: {
type: 'application/javascript'
, encoding: 'utf8'
, gzip: true
}
, swf: {
type: 'application/x-shockwave-flash'
, encoding: 'binary'
, gzip: false
}
};
/**
* Regexp for matching custom transport patterns. Users can configure their own
* socket.io bundle based on the url structure. Different transport names are
* concatinated using the `+` char. /socket.io/socket.io+websocket.js should
* create a bundle that only contains support for the websocket.
*
* @api private
*/
var bundle = /\+((?:\+)?[\w\-]+)*(?:\.v\d+\.\d+\.\d+)?(?:\.js)$/
, versioning = /\.v\d+\.\d+\.\d+(?:\.js)$/;
/**
* Export the constructor
*/
exports = module.exports = Static;
/**
* Static constructor
*
* @api public
*/
function Static (manager) {
this.manager = manager;
this.cache = {};
this.paths = {};
this.init();
}
/**
* Initialize the Static by adding default file paths.
*
* @api public
*/
Static.prototype.init = function () {
/**
* Generates a unique id based the supplied transports array
*
* @param {Array} transports The array with transport types
* @api private
*/
function id (transports) {
var id = transports.join('').split('').map(function (char) {
return ('' + char.charCodeAt(0)).split('').pop();
}).reduce(function (char, id) {
return char +id;
});
return client.version + ':' + id;
}
/**
* Generates a socket.io-client file based on the supplied transports.
*
* @param {Array} transports The array with transport types
* @param {Function} callback Callback for the static.write
* @api private
*/
function build (transports, callback) {
client.builder(transports, {
minify: self.manager.enabled('browser client minification')
}, function (err, content) {
callback(err, content ? new Buffer(content) : null, id(transports));
}
);
}
var self = this;
// add our default static files
this.add('/static/flashsocket/WebSocketMain.swf', {
file: client.dist + '/WebSocketMain.swf'
});
this.add('/static/flashsocket/WebSocketMainInsecure.swf', {
file: client.dist + '/WebSocketMainInsecure.swf'
});
// generates dedicated build based on the available transports
this.add('/socket.io.js', function (path, callback) {
build(self.manager.get('transports'), callback);
});
this.add('/socket.io.v', { mime: mime.js }, function (path, callback) {
build(self.manager.get('transports'), callback);
});
// allow custom builds based on url paths
this.add('/socket.io+', { mime: mime.js }, function (path, callback) {
var available = self.manager.get('transports')
, matches = path.match(bundle)
, transports = [];
if (!matches) return callback('No valid transports');
// make sure they valid transports
matches[0].split('.')[0].split('+').slice(1).forEach(function (transport) {
if (!!~available.indexOf(transport)) {
transports.push(transport);
}
});
if (!transports.length) return callback('No valid transports');
build(transports, callback);
});
// clear cache when transports change
this.manager.on('set:transports', function (key, value) {
delete self.cache['/socket.io.js'];
Object.keys(self.cache).forEach(function (key) {
if (bundle.test(key)) {
delete self.cache[key];
}
});
});
};
/**
* Gzip compress buffers.
*
* @param {Buffer} data The buffer that needs gzip compression
* @param {Function} callback
* @api public
*/
Static.prototype.gzip = function (data, callback) {
var gzip = cp.spawn('gzip', ['-9', '-c', '-f', '-n'])
, encoding = Buffer.isBuffer(data) ? 'binary' : 'utf8'
, buffer = []
, err;
gzip.stdout.on('data', function (data) {
buffer.push(data);
});
gzip.stderr.on('data', function (data) {
err = data +'';
buffer.length = 0;
});
gzip.on('close', function () {
if (err) return callback(err);
var size = 0
, index = 0
, i = buffer.length
, content;
while (i--) {
size += buffer[i].length;
}
content = new Buffer(size);
i = buffer.length;
buffer.forEach(function (buffer) {
var length = buffer.length;
buffer.copy(content, index, 0, length);
index += length;
});
buffer.length = 0;
callback(null, content);
});
gzip.stdin.end(data, encoding);
};
/**
* Is the path a static file?
*
* @param {String} path The path that needs to be checked
* @api public
*/
Static.prototype.has = function (path) {
// fast case
if (this.paths[path]) return this.paths[path];
var keys = Object.keys(this.paths)
, i = keys.length;
while (i--) {
if (-~path.indexOf(keys[i])) return this.paths[keys[i]];
}
return false;
};
/**
* Add new paths new paths that can be served using the static provider.
*
* @param {String} path The path to respond to
* @param {Options} options Options for writing out the response
* @param {Function} [callback] Optional callback if no options.file is
* supplied this would be called instead.
* @api public
*/
Static.prototype.add = function (path, options, callback) {
var extension = /(?:\.(\w{1,4}))$/.exec(path);
if (!callback && typeof options == 'function') {
callback = options;
options = {};
}
options.mime = options.mime || (extension ? mime[extension[1]] : false);
if (callback) options.callback = callback;
if (!(options.file || options.callback) || !options.mime) return false;
this.paths[path] = options;
return true;
};
/**
* Writes a static response.
*
* @param {String} path The path for the static content
* @param {HTTPRequest} req The request object
* @param {HTTPResponse} res The response object
* @api public
*/
Static.prototype.write = function (path, req, res) {
/**
* Write a response without throwing errors because can throw error if the
* response is no longer writable etc.
*
* @api private
*/
function write (status, headers, content, encoding) {
try {
res.writeHead(status, headers || undefined);
// only write content if it's not a HEAD request and we actually have
// some content to write (304's doesn't have content).
res.end(
req.method !== 'HEAD' && content ? content : ''
, encoding || undefined
);
} catch (e) {}
}
/**
* Answers requests depending on the request properties and the reply object.
*
* @param {Object} reply The details and content to reply the response with
* @api private
*/
function answer (reply) {
var cached = req.headers['if-none-match'] === reply.etag;
if (cached && self.manager.enabled('browser client etag')) {
return write(304);
}
var accept = req.headers['accept-encoding'] || ''
, gzip = !!~accept.toLowerCase().indexOf('gzip')
, mime = reply.mime
, versioned = reply.versioned
, headers = {
'Content-Type': mime.type
};
// check if we can add a etag
if (self.manager.enabled('browser client etag') && reply.etag && !versioned) {
headers['Etag'] = reply.etag;
}
// see if we need to set Expire headers because the path is versioned
if (versioned) {
var expires = self.manager.get('browser client expires');
headers['Cache-Control'] = 'private, x-gzip-ok="", max-age=' + expires;
headers['Date'] = new Date().toUTCString();
headers['Expires'] = new Date(Date.now() + (expires * 1000)).toUTCString();
}
if (gzip && reply.gzip) {
headers['Content-Length'] = reply.gzip.length;
headers['Content-Encoding'] = 'gzip';
headers['Vary'] = 'Accept-Encoding';
write(200, headers, reply.gzip.content, mime.encoding);
} else {
headers['Content-Length'] = reply.length;
write(200, headers, reply.content, mime.encoding);
}
self.manager.log.debug('served static content ' + path);
}
var self = this
, details;
// most common case first
if (this.manager.enabled('browser client cache') && this.cache[path]) {
return answer(this.cache[path]);
} else if (this.manager.get('browser client handler')) {
return this.manager.get('browser client handler').call(this, req, res);
} else if ((details = this.has(path))) {
/**
* A small helper function that will let us deal with fs and dynamic files
*
* @param {Object} err Optional error
* @param {Buffer} content The data
* @api private
*/
function ready (err, content, etag) {
if (err) {
self.manager.log.warn('Unable to serve file. ' + (err.message || err));
return write(500, null, 'Error serving static ' + path);
}
// store the result in the cache
var reply = self.cache[path] = {
content: content
, length: content.length
, mime: details.mime
, etag: etag || client.version
, versioned: versioning.test(path)
};
// check if gzip is enabled
if (details.mime.gzip && self.manager.enabled('browser client gzip')) {
self.gzip(content, function (err, content) {
if (!err) {
reply.gzip = {
content: content
, length: content.length
}
}
answer(reply);
});
} else {
answer(reply);
}
}
if (details.file) {
fs.readFile(details.file, ready);
} else if(details.callback) {
details.callback.call(this, path, ready);
} else {
write(404, null, 'File handle not found');
}
} else {
write(404, null, 'File not found');
}
};

98
node_modules/socket.io/lib/store.js generated vendored Normal file
View File

@ -0,0 +1,98 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Expose the constructor.
*/
exports = module.exports = Store;
/**
* Module dependencies.
*/
var EventEmitter = process.EventEmitter;
/**
* Store interface
*
* @api public
*/
function Store (options) {
this.options = options;
this.clients = {};
};
/**
* Inherit from EventEmitter.
*/
Store.prototype.__proto__ = EventEmitter.prototype;
/**
* Initializes a client store
*
* @param {String} id
* @api public
*/
Store.prototype.client = function (id) {
if (!this.clients[id]) {
this.clients[id] = new (this.constructor.Client)(this, id);
}
return this.clients[id];
};
/**
* Destroys a client
*
* @api {String} sid
* @param {Number} number of seconds to expire client data
* @api private
*/
Store.prototype.destroyClient = function (id, expiration) {
if (this.clients[id]) {
this.clients[id].destroy(expiration);
delete this.clients[id];
}
return this;
};
/**
* Destroys the store
*
* @param {Number} number of seconds to expire client data
* @api private
*/
Store.prototype.destroy = function (clientExpiration) {
var keys = Object.keys(this.clients)
, count = keys.length;
for (var i = 0, l = count; i < l; i++) {
this.destroyClient(keys[i], clientExpiration);
}
this.clients = {};
return this;
};
/**
* Client.
*
* @api public
*/
Store.Client = function (store, id) {
this.store = store;
this.id = id;
};

143
node_modules/socket.io/lib/stores/memory.js generated vendored Normal file
View File

@ -0,0 +1,143 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var crypto = require('crypto')
, Store = require('../store');
/**
* Exports the constructor.
*/
exports = module.exports = Memory;
Memory.Client = Client;
/**
* Memory store
*
* @api public
*/
function Memory (opts) {
Store.call(this, opts);
};
/**
* Inherits from Store.
*/
Memory.prototype.__proto__ = Store.prototype;
/**
* Publishes a message.
*
* @api private
*/
Memory.prototype.publish = function () { };
/**
* Subscribes to a channel
*
* @api private
*/
Memory.prototype.subscribe = function () { };
/**
* Unsubscribes
*
* @api private
*/
Memory.prototype.unsubscribe = function () { };
/**
* Client constructor
*
* @api private
*/
function Client () {
Store.Client.apply(this, arguments);
this.data = {};
};
/**
* Inherits from Store.Client
*/
Client.prototype.__proto__ = Store.Client;
/**
* Gets a key
*
* @api public
*/
Client.prototype.get = function (key, fn) {
fn(null, this.data[key] === undefined ? null : this.data[key]);
return this;
};
/**
* Sets a key
*
* @api public
*/
Client.prototype.set = function (key, value, fn) {
this.data[key] = value;
fn && fn(null);
return this;
};
/**
* Has a key
*
* @api public
*/
Client.prototype.has = function (key, fn) {
fn(null, key in this.data);
};
/**
* Deletes a key
*
* @api public
*/
Client.prototype.del = function (key, fn) {
delete this.data[key];
fn && fn(null);
return this;
};
/**
* Destroys the client.
*
* @param {Number} number of seconds to expire data
* @api private
*/
Client.prototype.destroy = function (expiration) {
if ('number' != typeof expiration) {
this.data = {};
} else {
var self = this;
setTimeout(function () {
self.data = {};
}, expiration * 1000);
}
return this;
};

269
node_modules/socket.io/lib/stores/redis.js generated vendored Normal file
View File

@ -0,0 +1,269 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var crypto = require('crypto')
, Store = require('../store')
, assert = require('assert');
/**
* Exports the constructor.
*/
exports = module.exports = Redis;
Redis.Client = Client;
/**
* Redis store.
* Options:
* - nodeId (fn) gets an id that uniquely identifies this node
* - redis (fn) redis constructor, defaults to redis
* - redisPub (object) options to pass to the pub redis client
* - redisSub (object) options to pass to the sub redis client
* - redisClient (object) options to pass to the general redis client
* - pack (fn) custom packing, defaults to JSON or msgpack if installed
* - unpack (fn) custom packing, defaults to JSON or msgpack if installed
*
* @api public
*/
function Redis (opts) {
opts = opts || {};
// node id to uniquely identify this node
var nodeId = opts.nodeId || function () {
// by default, we generate a random id
return Math.abs(Math.random() * Math.random() * Date.now() | 0);
};
this.nodeId = nodeId();
// packing / unpacking mechanism
if (opts.pack) {
this.pack = opts.pack;
this.unpack = opts.unpack;
} else {
try {
var msgpack = require('msgpack');
this.pack = msgpack.pack;
this.unpack = msgpack.unpack;
} catch (e) {
this.pack = JSON.stringify;
this.unpack = JSON.parse;
}
}
var redis = opts.redis || require('redis')
, RedisClient = redis.RedisClient;
// initialize a pubsub client and a regular client
if (opts.redisPub instanceof RedisClient) {
this.pub = opts.redisPub;
} else {
opts.redisPub || (opts.redisPub = {});
this.pub = redis.createClient(opts.redisPub.port, opts.redisPub.host, opts.redisPub);
}
if (opts.redisSub instanceof RedisClient) {
this.sub = opts.redisSub;
} else {
opts.redisSub || (opts.redisSub = {});
this.sub = redis.createClient(opts.redisSub.port, opts.redisSub.host, opts.redisSub);
}
if (opts.redisClient instanceof RedisClient) {
this.cmd = opts.redisClient;
} else {
opts.redisClient || (opts.redisClient = {});
this.cmd = redis.createClient(opts.redisClient.port, opts.redisClient.host, opts.redisClient);
}
Store.call(this, opts);
this.sub.setMaxListeners(0);
this.setMaxListeners(0);
};
/**
* Inherits from Store.
*/
Redis.prototype.__proto__ = Store.prototype;
/**
* Publishes a message.
*
* @api private
*/
Redis.prototype.publish = function (name) {
var args = Array.prototype.slice.call(arguments, 1);
this.pub.publish(name, this.pack({ nodeId: this.nodeId, args: args }));
this.emit.apply(this, ['publish', name].concat(args));
};
/**
* Subscribes to a channel
*
* @api private
*/
Redis.prototype.subscribe = function (name, consumer, fn) {
this.sub.subscribe(name);
if (consumer || fn) {
var self = this;
self.sub.on('subscribe', function subscribe (ch) {
if (name == ch) {
function message (ch, msg) {
if (name == ch) {
msg = self.unpack(msg);
// we check that the message consumed wasnt emitted by this node
if (self.nodeId != msg.nodeId) {
consumer.apply(null, msg.args);
}
}
};
self.sub.on('message', message);
self.on('unsubscribe', function unsubscribe (ch) {
if (name == ch) {
self.sub.removeListener('message', message);
self.removeListener('unsubscribe', unsubscribe);
}
});
self.sub.removeListener('subscribe', subscribe);
fn && fn();
}
});
}
this.emit('subscribe', name, consumer, fn);
};
/**
* Unsubscribes
*
* @api private
*/
Redis.prototype.unsubscribe = function (name, fn) {
this.sub.unsubscribe(name);
if (fn) {
var client = this.sub;
client.on('unsubscribe', function unsubscribe (ch) {
if (name == ch) {
fn();
client.removeListener('unsubscribe', unsubscribe);
}
});
}
this.emit('unsubscribe', name, fn);
};
/**
* Destroys the store
*
* @api public
*/
Redis.prototype.destroy = function () {
Store.prototype.destroy.call(this);
this.pub.end();
this.sub.end();
this.cmd.end();
};
/**
* Client constructor
*
* @api private
*/
function Client (store, id) {
Store.Client.call(this, store, id);
};
/**
* Inherits from Store.Client
*/
Client.prototype.__proto__ = Store.Client;
/**
* Redis hash get
*
* @api private
*/
Client.prototype.get = function (key, fn) {
this.store.cmd.hget(this.id, key, fn);
return this;
};
/**
* Redis hash set
*
* @api private
*/
Client.prototype.set = function (key, value, fn) {
this.store.cmd.hset(this.id, key, value, fn);
return this;
};
/**
* Redis hash del
*
* @api private
*/
Client.prototype.del = function (key, fn) {
this.store.cmd.hdel(this.id, key, fn);
return this;
};
/**
* Redis hash has
*
* @api private
*/
Client.prototype.has = function (key, fn) {
this.store.cmd.hexists(this.id, key, function (err, has) {
if (err) return fn(err);
fn(null, !!has);
});
return this;
};
/**
* Destroys client
*
* @param {Number} number of seconds to expire data
* @api private
*/
Client.prototype.destroy = function (expiration) {
if ('number' != typeof expiration) {
this.store.cmd.del(this.id);
} else {
this.store.cmd.expire(this.id, expiration);
}
return this;
};

534
node_modules/socket.io/lib/transport.js generated vendored Normal file
View File

@ -0,0 +1,534 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var parser = require('./parser');
/**
* Expose the constructor.
*/
exports = module.exports = Transport;
/**
* Transport constructor.
*
* @api public
*/
function Transport (mng, data, req) {
this.manager = mng;
this.id = data.id;
this.disconnected = false;
this.drained = true;
this.handleRequest(req);
};
/**
* Access the logger.
*
* @api public
*/
Transport.prototype.__defineGetter__('log', function () {
return this.manager.log;
});
/**
* Access the store.
*
* @api public
*/
Transport.prototype.__defineGetter__('store', function () {
return this.manager.store;
});
/**
* Handles a request when it's set.
*
* @api private
*/
Transport.prototype.handleRequest = function (req) {
this.log.debug('setting request', req.method, req.url);
this.req = req;
if (req.method == 'GET') {
this.socket = req.socket;
this.open = true;
this.drained = true;
this.setHeartbeatInterval();
this.setHandlers();
this.onSocketConnect();
}
};
/**
* Called when a connection is first set.
*
* @api private
*/
Transport.prototype.onSocketConnect = function () { };
/**
* Sets transport handlers
*
* @api private
*/
Transport.prototype.setHandlers = function () {
var self = this;
// we need to do this in a pub/sub way since the client can POST the message
// over a different socket (ie: different Transport instance)
this.store.subscribe('heartbeat-clear:' + this.id, function () {
self.onHeartbeatClear();
});
this.store.subscribe('disconnect-force:' + this.id, function () {
self.onForcedDisconnect();
});
this.store.subscribe('dispatch:' + this.id, function (packet, volatile) {
self.onDispatch(packet, volatile);
});
this.bound = {
end: this.onSocketEnd.bind(this)
, close: this.onSocketClose.bind(this)
, error: this.onSocketError.bind(this)
, drain: this.onSocketDrain.bind(this)
};
this.socket.on('end', this.bound.end);
this.socket.on('close', this.bound.close);
this.socket.on('error', this.bound.error);
this.socket.on('drain', this.bound.drain);
this.handlersSet = true;
};
/**
* Removes transport handlers
*
* @api private
*/
Transport.prototype.clearHandlers = function () {
if (this.handlersSet) {
this.store.unsubscribe('disconnect-force:' + this.id);
this.store.unsubscribe('heartbeat-clear:' + this.id);
this.store.unsubscribe('dispatch:' + this.id);
this.socket.removeListener('end', this.bound.end);
this.socket.removeListener('close', this.bound.close);
this.socket.removeListener('error', this.bound.error);
this.socket.removeListener('drain', this.bound.drain);
}
};
/**
* Called when the connection dies
*
* @api private
*/
Transport.prototype.onSocketEnd = function () {
this.end('socket end');
};
/**
* Called when the connection dies
*
* @api private
*/
Transport.prototype.onSocketClose = function (error) {
this.end(error ? 'socket error' : 'socket close');
};
/**
* Called when the connection has an error.
*
* @api private
*/
Transport.prototype.onSocketError = function (err) {
if (this.open) {
this.socket.destroy();
this.onClose();
}
this.log.info('socket error ' + err.stack);
};
/**
* Called when the connection is drained.
*
* @api private
*/
Transport.prototype.onSocketDrain = function () {
this.drained = true;
};
/**
* Called upon receiving a heartbeat packet.
*
* @api private
*/
Transport.prototype.onHeartbeatClear = function () {
this.clearHeartbeatTimeout();
this.setHeartbeatInterval();
};
/**
* Called upon a forced disconnection.
*
* @api private
*/
Transport.prototype.onForcedDisconnect = function () {
if (!this.disconnected) {
this.log.info('transport end by forced client disconnection');
if (this.open) {
this.packet({ type: 'disconnect' });
}
this.end('booted');
}
};
/**
* Dispatches a packet.
*
* @api private
*/
Transport.prototype.onDispatch = function (packet, volatile) {
if (volatile) {
this.writeVolatile(packet);
} else {
this.write(packet);
}
};
/**
* Sets the close timeout.
*/
Transport.prototype.setCloseTimeout = function () {
if (!this.closeTimeout) {
var self = this;
this.closeTimeout = setTimeout(function () {
self.log.debug('fired close timeout for client', self.id);
self.closeTimeout = null;
self.end('close timeout');
}, this.manager.get('close timeout') * 1000);
this.log.debug('set close timeout for client', this.id);
}
};
/**
* Clears the close timeout.
*/
Transport.prototype.clearCloseTimeout = function () {
if (this.closeTimeout) {
clearTimeout(this.closeTimeout);
this.closeTimeout = null;
this.log.debug('cleared close timeout for client', this.id);
}
};
/**
* Sets the heartbeat timeout
*/
Transport.prototype.setHeartbeatTimeout = function () {
if (!this.heartbeatTimeout && this.manager.enabled('heartbeats')) {
var self = this;
this.heartbeatTimeout = setTimeout(function () {
self.log.debug('fired heartbeat timeout for client', self.id);
self.heartbeatTimeout = null;
self.end('heartbeat timeout');
}, this.manager.get('heartbeat timeout') * 1000);
this.log.debug('set heartbeat timeout for client', this.id);
}
};
/**
* Clears the heartbeat timeout
*
* @param text
*/
Transport.prototype.clearHeartbeatTimeout = function () {
if (this.heartbeatTimeout && this.manager.enabled('heartbeats')) {
clearTimeout(this.heartbeatTimeout);
this.heartbeatTimeout = null;
this.log.debug('cleared heartbeat timeout for client', this.id);
}
};
/**
* Sets the heartbeat interval. To be called when a connection opens and when
* a heartbeat is received.
*
* @api private
*/
Transport.prototype.setHeartbeatInterval = function () {
if (!this.heartbeatInterval && this.manager.enabled('heartbeats')) {
var self = this;
this.heartbeatInterval = setTimeout(function () {
self.heartbeat();
self.heartbeatInterval = null;
}, this.manager.get('heartbeat interval') * 1000);
this.log.debug('set heartbeat interval for client', this.id);
}
};
/**
* Clears all timeouts.
*
* @api private
*/
Transport.prototype.clearTimeouts = function () {
this.clearCloseTimeout();
this.clearHeartbeatTimeout();
this.clearHeartbeatInterval();
};
/**
* Sends a heartbeat
*
* @api private
*/
Transport.prototype.heartbeat = function () {
if (this.open) {
this.log.debug('emitting heartbeat for client', this.id);
this.packet({ type: 'heartbeat' });
this.setHeartbeatTimeout();
}
return this;
};
/**
* Handles a message.
*
* @param {Object} packet object
* @api private
*/
Transport.prototype.onMessage = function (packet) {
var current = this.manager.transports[this.id];
if ('heartbeat' == packet.type) {
this.log.debug('got heartbeat packet');
if (current && current.open) {
current.onHeartbeatClear();
} else {
this.store.publish('heartbeat-clear:' + this.id);
}
} else {
if ('disconnect' == packet.type && packet.endpoint == '') {
this.log.debug('got disconnection packet');
if (current) {
current.onForcedDisconnect();
} else {
this.store.publish('disconnect-force:' + this.id);
}
return;
}
if (packet.id && packet.ack != 'data') {
this.log.debug('acknowledging packet automatically');
var ack = parser.encodePacket({
type: 'ack'
, ackId: packet.id
, endpoint: packet.endpoint || ''
});
if (current && current.open) {
current.onDispatch(ack);
} else {
this.manager.onClientDispatch(this.id, ack);
this.store.publish('dispatch:' + this.id, ack);
}
}
// handle packet locally or publish it
if (current) {
this.manager.onClientMessage(this.id, packet);
} else {
this.store.publish('message:' + this.id, packet);
}
}
};
/**
* Clears the heartbeat interval
*
* @api private
*/
Transport.prototype.clearHeartbeatInterval = function () {
if (this.heartbeatInterval && this.manager.enabled('heartbeats')) {
clearTimeout(this.heartbeatInterval);
this.heartbeatInterval = null;
this.log.debug('cleared heartbeat interval for client', this.id);
}
};
/**
* Finishes the connection and makes sure client doesn't reopen
*
* @api private
*/
Transport.prototype.disconnect = function (reason) {
this.packet({ type: 'disconnect' });
this.end(reason);
return this;
};
/**
* Closes the connection.
*
* @api private
*/
Transport.prototype.close = function () {
if (this.open) {
this.doClose();
this.onClose();
}
};
/**
* Called upon a connection close.
*
* @api private
*/
Transport.prototype.onClose = function () {
if (this.open) {
this.setCloseTimeout();
this.clearHandlers();
this.open = false;
this.manager.onClose(this.id);
this.store.publish('close', this.id);
}
};
/**
* Cleans up the connection, considers the client disconnected.
*
* @api private
*/
Transport.prototype.end = function (reason) {
if (!this.disconnected) {
this.log.info('transport end (' + reason + ')');
var local = this.manager.transports[this.id];
this.close();
this.clearTimeouts();
this.disconnected = true;
if (local) {
this.manager.onClientDisconnect(this.id, reason, true);
} else {
this.store.publish('disconnect:' + this.id, reason);
}
}
};
/**
* Signals that the transport should pause and buffer data.
*
* @api public
*/
Transport.prototype.discard = function () {
this.log.debug('discarding transport');
this.discarded = true;
this.clearTimeouts();
this.clearHandlers();
return this;
};
/**
* Writes an error packet with the specified reason and advice.
*
* @param {Number} advice
* @param {Number} reason
* @api public
*/
Transport.prototype.error = function (reason, advice) {
this.packet({
type: 'error'
, reason: reason
, advice: advice
});
this.log.warn(reason, advice ? ('client should ' + advice) : '');
this.end('error');
};
/**
* Write a packet.
*
* @api public
*/
Transport.prototype.packet = function (obj) {
return this.write(parser.encodePacket(obj));
};
/**
* Writes a volatile message.
*
* @api private
*/
Transport.prototype.writeVolatile = function (msg) {
if (this.open) {
if (this.drained) {
this.write(msg);
} else {
this.log.debug('ignoring volatile packet, buffer not drained');
}
} else {
this.log.debug('ignoring volatile packet, transport not open');
}
};

129
node_modules/socket.io/lib/transports/flashsocket.js generated vendored Normal file
View File

@ -0,0 +1,129 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var WebSocket = require('./websocket');
/**
* Export the constructor.
*/
exports = module.exports = FlashSocket;
/**
* The FlashSocket transport is just a proxy
* for WebSocket connections.
*
* @api public
*/
function FlashSocket (mng, data, req) {
return WebSocket.call(this, mng, data, req);
}
/**
* Inherits from WebSocket.
*/
FlashSocket.prototype.__proto__ = WebSocket.prototype;
/**
* Transport name
*
* @api public
*/
FlashSocket.prototype.name = 'flashsocket';
/**
* Listens for new configuration changes of the Manager
* this way we can enable and disable the flash server.
*
* @param {Manager} Manager instance.
* @api private
*/
FlashSocket.init = function (manager) {
var server;
function create () {
// Drop out immediately if the user has
// disabled the flash policy server
if (!manager.get('flash policy server')) {
return;
}
server = require('policyfile').createServer({
log: function(msg){
manager.log.info(msg);
}
}, manager.get('origins'));
server.on('close', function (e) {
server = null;
});
server.listen(manager.get('flash policy port'), manager.server);
manager.flashPolicyServer = server;
}
// listen for origin changes, so we can update the server
manager.on('set:origins', function (value, key) {
if (!server) return;
// update the origins and compile a new response buffer
server.origins = Array.isArray(value) ? value : [value];
server.compile();
});
// destory the server and create a new server
manager.on('set:flash policy port', function (value, key) {
var transports = manager.get('transports');
if (~transports.indexOf('flashsocket')) {
if (server) {
if (server.port === value) return;
// destroy the server and rebuild it on a new port
try {
server.close();
}
catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
}
create();
}
});
// create or destroy the server
manager.on('set:flash policy server', function (value, key) {
var transports = manager.get('transports');
if (~transports.indexOf('flashsocket')) {
if (server && !value) {
// destroy the server
try {
server.close();
}
catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
}
} else if (!server && value) {
// create the server
create();
}
});
// only start the server
manager.on('set:transports', function (value, key){
if (!server && ~manager.get('transports').indexOf('flashsocket')) {
create();
}
});
// check if we need to initialize at start
if (~manager.get('transports').indexOf('flashsocket')){
create();
}
};

83
node_modules/socket.io/lib/transports/htmlfile.js generated vendored Normal file
View File

@ -0,0 +1,83 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var HTTPTransport = require('./http');
/**
* Export the constructor.
*/
exports = module.exports = HTMLFile;
/**
* HTMLFile transport constructor.
*
* @api public
*/
function HTMLFile (mng, data, req) {
HTTPTransport.call(this, mng, data, req);
};
/**
* Inherits from Transport.
*/
HTMLFile.prototype.__proto__ = HTTPTransport.prototype;
/**
* Transport name
*
* @api public
*/
HTMLFile.prototype.name = 'htmlfile';
/**
* Handles the request.
*
* @api private
*/
HTMLFile.prototype.handleRequest = function (req) {
HTTPTransport.prototype.handleRequest.call(this, req);
if (req.method == 'GET') {
req.res.writeHead(200, {
'Content-Type': 'text/html; charset=UTF-8'
, 'Connection': 'keep-alive'
, 'Transfer-Encoding': 'chunked'
});
req.res.write(
'<html><body>'
+ '<script>var _ = function (msg) { parent.s._(msg, document); };</script>'
+ new Array(174).join(' ')
);
}
};
/**
* Performs the write.
*
* @api private
*/
HTMLFile.prototype.write = function (data) {
// escape all forward slashes. see GH-1251
data = '<script>_(' + JSON.stringify(data).replace(/\//g, '\\/') + ');</script>';
if (this.response.write(data)) {
this.drained = true;
}
this.log.debug(this.name + ' writing', data);
};

147
node_modules/socket.io/lib/transports/http-polling.js generated vendored Normal file
View File

@ -0,0 +1,147 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var HTTPTransport = require('./http');
/**
* Exports the constructor.
*/
exports = module.exports = HTTPPolling;
/**
* HTTP polling constructor.
*
* @api public.
*/
function HTTPPolling (mng, data, req) {
HTTPTransport.call(this, mng, data, req);
};
/**
* Inherits from HTTPTransport.
*
* @api public.
*/
HTTPPolling.prototype.__proto__ = HTTPTransport.prototype;
/**
* Transport name
*
* @api public
*/
HTTPPolling.prototype.name = 'httppolling';
/**
* Override setHandlers
*
* @api private
*/
HTTPPolling.prototype.setHandlers = function () {
HTTPTransport.prototype.setHandlers.call(this);
this.socket.removeListener('end', this.bound.end);
this.socket.removeListener('close', this.bound.close);
};
/**
* Removes heartbeat timeouts for polling.
*/
HTTPPolling.prototype.setHeartbeatInterval = function () {
return this;
};
/**
* Handles a request
*
* @api private
*/
HTTPPolling.prototype.handleRequest = function (req) {
HTTPTransport.prototype.handleRequest.call(this, req);
if (req.method == 'GET') {
var self = this;
this.pollTimeout = setTimeout(function () {
self.packet({ type: 'noop' });
self.log.debug(self.name + ' closed due to exceeded duration');
}, this.manager.get('polling duration') * 1000);
this.log.debug('setting poll timeout');
}
};
/**
* Clears polling timeout
*
* @api private
*/
HTTPPolling.prototype.clearPollTimeout = function () {
if (this.pollTimeout) {
clearTimeout(this.pollTimeout);
this.pollTimeout = null;
this.log.debug('clearing poll timeout');
}
return this;
};
/**
* Override clear timeouts to clear the poll timeout
*
* @api private
*/
HTTPPolling.prototype.clearTimeouts = function () {
HTTPTransport.prototype.clearTimeouts.call(this);
this.clearPollTimeout();
};
/**
* doWrite to clear poll timeout
*
* @api private
*/
HTTPPolling.prototype.doWrite = function () {
this.clearPollTimeout();
};
/**
* Performs a write.
*
* @api private.
*/
HTTPPolling.prototype.write = function (data, close) {
this.doWrite(data);
this.response.end();
this.onClose();
};
/**
* Override end.
*
* @api private
*/
HTTPPolling.prototype.end = function (reason) {
this.clearPollTimeout();
return HTTPTransport.prototype.end.call(this, reason);
};

121
node_modules/socket.io/lib/transports/http.js generated vendored Normal file
View File

@ -0,0 +1,121 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var Transport = require('../transport')
, parser = require('../parser')
, qs = require('querystring');
/**
* Export the constructor.
*/
exports = module.exports = HTTPTransport;
/**
* HTTP interface constructor. For all non-websocket transports.
*
* @api public
*/
function HTTPTransport (mng, data, req) {
Transport.call(this, mng, data, req);
};
/**
* Inherits from Transport.
*/
HTTPTransport.prototype.__proto__ = Transport.prototype;
/**
* Handles a request.
*
* @api private
*/
HTTPTransport.prototype.handleRequest = function (req) {
// Always set the response in case an error is returned to the client
this.response = req.res;
if (req.method == 'POST') {
var buffer = ''
, res = req.res
, origin = req.headers.origin
, headers = { 'Content-Length': 1, 'Content-Type': 'text/plain; charset=UTF-8' }
, self = this;
req.on('data', function (data) {
buffer += data;
if (Buffer.byteLength(buffer) >= self.manager.get('destroy buffer size')) {
buffer = '';
req.connection.destroy();
}
});
req.on('end', function () {
res.writeHead(200, headers);
res.end('1');
self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
});
// prevent memory leaks for uncompleted requests
req.on('close', function () {
buffer = '';
self.onClose();
});
if (origin) {
// https://developer.mozilla.org/En/HTTP_Access_Control
headers['Access-Control-Allow-Origin'] = origin;
headers['Access-Control-Allow-Credentials'] = 'true';
}
} else {
Transport.prototype.handleRequest.call(this, req);
}
};
/**
* Handles data payload.
*
* @api private
*/
HTTPTransport.prototype.onData = function (data) {
var messages = parser.decodePayload(data);
this.log.debug(this.name + ' received data packet', data);
for (var i = 0, l = messages.length; i < l; i++) {
this.onMessage(messages[i]);
}
};
/**
* Closes the request-response cycle
*
* @api private
*/
HTTPTransport.prototype.doClose = function () {
this.response.end();
};
/**
* Writes a payload of messages
*
* @api private
*/
HTTPTransport.prototype.payload = function (msgs) {
this.write(parser.encodePayload(msgs));
};

12
node_modules/socket.io/lib/transports/index.js generated vendored Normal file
View File

@ -0,0 +1,12 @@
/**
* Export transports.
*/
module.exports = {
websocket: require('./websocket')
, flashsocket: require('./flashsocket')
, htmlfile: require('./htmlfile')
, 'xhr-polling': require('./xhr-polling')
, 'jsonp-polling': require('./jsonp-polling')
};

97
node_modules/socket.io/lib/transports/jsonp-polling.js generated vendored Normal file
View File

@ -0,0 +1,97 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var HTTPPolling = require('./http-polling');
var jsonpolling_re = /^\d+$/
/**
* Export the constructor.
*/
exports = module.exports = JSONPPolling;
/**
* JSON-P polling transport.
*
* @api public
*/
function JSONPPolling (mng, data, req) {
HTTPPolling.call(this, mng, data, req);
this.head = 'io.j[0](';
this.foot = ');';
if (data.query.i && jsonpolling_re.test(data.query.i)) {
this.head = 'io.j[' + data.query.i + '](';
}
};
/**
* Inherits from Transport.
*/
JSONPPolling.prototype.__proto__ = HTTPPolling.prototype;
/**
* Transport name
*
* @api public
*/
JSONPPolling.prototype.name = 'jsonppolling';
/**
* Make sure POST are decoded.
*/
JSONPPolling.prototype.postEncoded = true;
/**
* Handles incoming data.
* Due to a bug in \n handling by browsers, we expect a JSONified string.
*
* @api private
*/
JSONPPolling.prototype.onData = function (data) {
try {
data = JSON.parse(data);
} catch (e) {
this.error('parse', 'reconnect');
return;
}
HTTPPolling.prototype.onData.call(this, data);
};
/**
* Performs the write.
*
* @api private
*/
JSONPPolling.prototype.doWrite = function (data) {
HTTPPolling.prototype.doWrite.call(this);
var data = data === undefined
? '' : this.head + JSON.stringify(data) + this.foot;
this.response.writeHead(200, {
'Content-Type': 'text/javascript; charset=UTF-8'
, 'Content-Length': Buffer.byteLength(data)
, 'Connection': 'Keep-Alive'
, 'X-XSS-Protection': '0'
});
this.response.write(data);
this.log.debug(this.name + ' writing', data);
};

36
node_modules/socket.io/lib/transports/websocket.js generated vendored Normal file
View File

@ -0,0 +1,36 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var protocolVersions = require('./websocket/');
/**
* Export the constructor.
*/
exports = module.exports = WebSocket;
/**
* HTTP interface constructor. Interface compatible with all transports that
* depend on request-response cycles.
*
* @api public
*/
function WebSocket (mng, data, req) {
var transport
, version = req.headers['sec-websocket-version'];
if (typeof version !== 'undefined' && typeof protocolVersions[version] !== 'undefined') {
transport = new protocolVersions[version](mng, data, req);
}
else transport = new protocolVersions['default'](mng, data, req);
if (typeof this.name !== 'undefined') transport.name = this.name;
return transport;
};

View File

@ -0,0 +1,362 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var Transport = require('../../transport')
, EventEmitter = process.EventEmitter
, crypto = require('crypto')
, parser = require('../../parser');
/**
* Export the constructor.
*/
exports = module.exports = WebSocket;
/**
* HTTP interface constructor. Interface compatible with all transports that
* depend on request-response cycles.
*
* @api public
*/
function WebSocket (mng, data, req) {
// parser
var self = this;
this.parser = new Parser();
this.parser.on('data', function (packet) {
self.log.debug(self.name + ' received data packet', packet);
self.onMessage(parser.decodePacket(packet));
});
this.parser.on('close', function () {
self.end();
});
this.parser.on('error', function () {
self.end();
});
Transport.call(this, mng, data, req);
};
/**
* Inherits from Transport.
*/
WebSocket.prototype.__proto__ = Transport.prototype;
/**
* Transport name
*
* @api public
*/
WebSocket.prototype.name = 'websocket';
/**
* Websocket draft version
*
* @api public
*/
WebSocket.prototype.protocolVersion = 'hixie-76';
/**
* Called when the socket connects.
*
* @api private
*/
WebSocket.prototype.onSocketConnect = function () {
var self = this;
this.socket.setNoDelay(true);
this.buffer = true;
this.buffered = [];
if (this.req.headers.upgrade !== 'WebSocket') {
this.log.warn(this.name + ' connection invalid');
this.end();
return;
}
var origin = this.req.headers['origin']
, waitingForNonce = false;
if(this.manager.settings['match origin protocol']){
location = (origin.indexOf('https')>-1 ? 'wss' : 'ws') + '://' + this.req.headers.host + this.req.url;
}else if(this.socket.encrypted){
location = 'wss://' + this.req.headers.host + this.req.url;
}else{
location = 'ws://' + this.req.headers.host + this.req.url;
}
if (this.req.headers['sec-websocket-key1']) {
// If we don't have the nonce yet, wait for it (HAProxy compatibility).
if (! (this.req.head && this.req.head.length >= 8)) {
waitingForNonce = true;
}
var headers = [
'HTTP/1.1 101 WebSocket Protocol Handshake'
, 'Upgrade: WebSocket'
, 'Connection: Upgrade'
, 'Sec-WebSocket-Origin: ' + origin
, 'Sec-WebSocket-Location: ' + location
];
if (this.req.headers['sec-websocket-protocol']){
headers.push('Sec-WebSocket-Protocol: '
+ this.req.headers['sec-websocket-protocol']);
}
} else {
var headers = [
'HTTP/1.1 101 Web Socket Protocol Handshake'
, 'Upgrade: WebSocket'
, 'Connection: Upgrade'
, 'WebSocket-Origin: ' + origin
, 'WebSocket-Location: ' + location
];
}
try {
this.socket.write(headers.concat('', '').join('\r\n'));
this.socket.setTimeout(0);
this.socket.setNoDelay(true);
this.socket.setEncoding('utf8');
} catch (e) {
this.end();
return;
}
if (waitingForNonce) {
this.socket.setEncoding('binary');
} else if (this.proveReception(headers)) {
self.flush();
}
var headBuffer = '';
this.socket.on('data', function (data) {
if (waitingForNonce) {
headBuffer += data;
if (headBuffer.length < 8) {
return;
}
// Restore the connection to utf8 encoding after receiving the nonce
self.socket.setEncoding('utf8');
waitingForNonce = false;
// Stuff the nonce into the location where it's expected to be
self.req.head = headBuffer.substr(0, 8);
headBuffer = '';
if (self.proveReception(headers)) {
self.flush();
}
return;
}
self.parser.add(data);
});
};
/**
* Writes to the socket.
*
* @api private
*/
WebSocket.prototype.write = function (data) {
if (this.open) {
this.drained = false;
if (this.buffer) {
this.buffered.push(data);
return this;
}
var length = Buffer.byteLength(data)
, buffer = new Buffer(2 + length);
buffer.write('\x00', 'binary');
buffer.write(data, 1, 'utf8');
buffer.write('\xff', 1 + length, 'binary');
try {
if (this.socket.write(buffer)) {
this.drained = true;
}
} catch (e) {
this.end();
}
this.log.debug(this.name + ' writing', data);
}
};
/**
* Flushes the internal buffer
*
* @api private
*/
WebSocket.prototype.flush = function () {
this.buffer = false;
for (var i = 0, l = this.buffered.length; i < l; i++) {
this.write(this.buffered.splice(0, 1)[0]);
}
};
/**
* Finishes the handshake.
*
* @api private
*/
WebSocket.prototype.proveReception = function (headers) {
var self = this
, k1 = this.req.headers['sec-websocket-key1']
, k2 = this.req.headers['sec-websocket-key2'];
if (k1 && k2){
var md5 = crypto.createHash('md5');
[k1, k2].forEach(function (k) {
var n = parseInt(k.replace(/[^\d]/g, ''))
, spaces = k.replace(/[^ ]/g, '').length;
if (spaces === 0 || n % spaces !== 0){
self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
self.end();
return false;
}
n /= spaces;
md5.update(String.fromCharCode(
n >> 24 & 0xFF,
n >> 16 & 0xFF,
n >> 8 & 0xFF,
n & 0xFF));
});
md5.update(this.req.head.toString('binary'));
try {
this.socket.write(md5.digest('binary'), 'binary');
} catch (e) {
this.end();
}
}
return true;
};
/**
* Writes a payload.
*
* @api private
*/
WebSocket.prototype.payload = function (msgs) {
for (var i = 0, l = msgs.length; i < l; i++) {
this.write(msgs[i]);
}
return this;
};
/**
* Closes the connection.
*
* @api private
*/
WebSocket.prototype.doClose = function () {
this.socket.end();
};
/**
* WebSocket parser
*
* @api public
*/
function Parser () {
this.buffer = '';
this.i = 0;
};
/**
* Inherits from EventEmitter.
*/
Parser.prototype.__proto__ = EventEmitter.prototype;
/**
* Adds data to the buffer.
*
* @api public
*/
Parser.prototype.add = function (data) {
this.buffer += data;
this.parse();
};
/**
* Parses the buffer.
*
* @api private
*/
Parser.prototype.parse = function () {
for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
chr = this.buffer[i];
if (this.buffer.length == 2 && this.buffer[1] == '\u0000') {
this.emit('close');
this.buffer = '';
this.i = 0;
return;
}
if (i === 0){
if (chr != '\u0000')
this.error('Bad framing. Expected null byte as first frame');
else
continue;
}
if (chr == '\ufffd'){
this.emit('data', this.buffer.substr(1, i - 1));
this.buffer = this.buffer.substr(i + 1);
this.i = 0;
return this.parse();
}
}
};
/**
* Handles an error
*
* @api private
*/
Parser.prototype.error = function (reason) {
this.buffer = '';
this.i = 0;
this.emit('error', reason);
return this;
};

View File

@ -0,0 +1,622 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var Transport = require('../../transport')
, EventEmitter = process.EventEmitter
, crypto = require('crypto')
, url = require('url')
, parser = require('../../parser')
, util = require('../../util');
/**
* Export the constructor.
*/
exports = module.exports = WebSocket;
exports.Parser = Parser;
/**
* HTTP interface constructor. Interface compatible with all transports that
* depend on request-response cycles.
*
* @api public
*/
function WebSocket (mng, data, req) {
// parser
var self = this;
this.manager = mng;
this.parser = new Parser();
this.parser.on('data', function (packet) {
self.onMessage(parser.decodePacket(packet));
});
this.parser.on('ping', function () {
// version 8 ping => pong
try {
self.socket.write('\u008a\u0000');
}
catch (e) {
self.end();
return;
}
});
this.parser.on('close', function () {
self.end();
});
this.parser.on('error', function (reason) {
self.log.warn(self.name + ' parser error: ' + reason);
self.end();
});
Transport.call(this, mng, data, req);
};
/**
* Inherits from Transport.
*/
WebSocket.prototype.__proto__ = Transport.prototype;
/**
* Transport name
*
* @api public
*/
WebSocket.prototype.name = 'websocket';
/**
* Websocket draft version
*
* @api public
*/
WebSocket.prototype.protocolVersion = '07-12';
/**
* Called when the socket connects.
*
* @api private
*/
WebSocket.prototype.onSocketConnect = function () {
var self = this;
if (typeof this.req.headers.upgrade === 'undefined' ||
this.req.headers.upgrade.toLowerCase() !== 'websocket') {
this.log.warn(this.name + ' connection invalid');
this.end();
return;
}
var origin = this.req.headers['sec-websocket-origin']
, location = ((this.manager.settings['match origin protocol'] ?
origin.match(/^https/) : this.socket.encrypted) ?
'wss' : 'ws')
+ '://' + this.req.headers.host + this.req.url;
if (!this.verifyOrigin(origin)) {
this.log.warn(this.name + ' connection invalid: origin mismatch');
this.end();
return;
}
if (!this.req.headers['sec-websocket-key']) {
this.log.warn(this.name + ' connection invalid: received no key');
this.end();
return;
}
// calc key
var key = this.req.headers['sec-websocket-key'];
var shasum = crypto.createHash('sha1');
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
key = shasum.digest('base64');
var headers = [
'HTTP/1.1 101 Switching Protocols'
, 'Upgrade: websocket'
, 'Connection: Upgrade'
, 'Sec-WebSocket-Accept: ' + key
];
try {
this.socket.write(headers.concat('', '').join('\r\n'));
this.socket.setTimeout(0);
this.socket.setNoDelay(true);
} catch (e) {
this.end();
return;
}
this.socket.on('data', function (data) {
self.parser.add(data);
});
};
/**
* Verifies the origin of a request.
*
* @api private
*/
WebSocket.prototype.verifyOrigin = function (origin) {
var origins = this.manager.get('origins');
if (origin === 'null') origin = '*';
if (origins.indexOf('*:*') !== -1) {
return true;
}
if (origin) {
try {
var parts = url.parse(origin);
parts.port = parts.port || 80;
var ok =
~origins.indexOf(parts.hostname + ':' + parts.port) ||
~origins.indexOf(parts.hostname + ':*') ||
~origins.indexOf('*:' + parts.port);
if (!ok) this.log.warn('illegal origin: ' + origin);
return ok;
} catch (ex) {
this.log.warn('error parsing origin');
}
}
else {
this.log.warn('origin missing from websocket call, yet required by config');
}
return false;
};
/**
* Writes to the socket.
*
* @api private
*/
WebSocket.prototype.write = function (data) {
if (this.open) {
var buf = this.frame(0x81, data);
try {
this.socket.write(buf, 'binary');
}
catch (e) {
this.end();
return;
}
this.log.debug(this.name + ' writing', data);
}
};
/**
* Writes a payload.
*
* @api private
*/
WebSocket.prototype.payload = function (msgs) {
for (var i = 0, l = msgs.length; i < l; i++) {
this.write(msgs[i]);
}
return this;
};
/**
* Frame server-to-client output as a text packet.
*
* @api private
*/
WebSocket.prototype.frame = function (opcode, str) {
var dataBuffer = new Buffer(str)
, dataLength = dataBuffer.length
, startOffset = 2
, secondByte = dataLength;
if (dataLength > 65536) {
startOffset = 10;
secondByte = 127;
}
else if (dataLength > 125) {
startOffset = 4;
secondByte = 126;
}
var outputBuffer = new Buffer(dataLength + startOffset);
outputBuffer[0] = opcode;
outputBuffer[1] = secondByte;
dataBuffer.copy(outputBuffer, startOffset);
switch (secondByte) {
case 126:
outputBuffer[2] = dataLength >>> 8;
outputBuffer[3] = dataLength % 256;
break;
case 127:
var l = dataLength;
for (var i = 1; i <= 8; ++i) {
outputBuffer[startOffset - i] = l & 0xff;
l >>>= 8;
}
}
return outputBuffer;
};
/**
* Closes the connection.
*
* @api private
*/
WebSocket.prototype.doClose = function () {
this.socket.end();
};
/**
* WebSocket parser
*
* @api public
*/
function Parser () {
this.state = {
activeFragmentedOperation: null,
lastFragment: false,
masked: false,
opcode: 0
};
this.overflow = null;
this.expectOffset = 0;
this.expectBuffer = null;
this.expectHandler = null;
this.currentMessage = '';
var self = this;
this.opcodeHandlers = {
// text
'1': function(data) {
var finish = function(mask, data) {
self.currentMessage += self.unmask(mask, data);
if (self.state.lastFragment) {
self.emit('data', self.currentMessage);
self.currentMessage = '';
}
self.endPacket();
}
var expectData = function(length) {
if (self.state.masked) {
self.expect('Mask', 4, function(data) {
var mask = data;
self.expect('Data', length, function(data) {
finish(mask, data);
});
});
}
else {
self.expect('Data', length, function(data) {
finish(null, data);
});
}
}
// decode length
var firstLength = data[1] & 0x7f;
if (firstLength < 126) {
expectData(firstLength);
}
else if (firstLength == 126) {
self.expect('Length', 2, function(data) {
expectData(util.unpack(data));
});
}
else if (firstLength == 127) {
self.expect('Length', 8, function(data) {
if (util.unpack(data.slice(0, 4)) != 0) {
self.error('packets with length spanning more than 32 bit is currently not supported');
return;
}
var lengthBytes = data.slice(4); // note: cap to 32 bit length
expectData(util.unpack(data));
});
}
},
// binary
'2': function(data) {
var finish = function(mask, data) {
if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
self.currentMessage.push(self.unmask(mask, data, true));
if (self.state.lastFragment) {
self.emit('binary', self.concatBuffers(self.currentMessage));
self.currentMessage = '';
}
self.endPacket();
}
var expectData = function(length) {
if (self.state.masked) {
self.expect('Mask', 4, function(data) {
var mask = data;
self.expect('Data', length, function(data) {
finish(mask, data);
});
});
}
else {
self.expect('Data', length, function(data) {
finish(null, data);
});
}
}
// decode length
var firstLength = data[1] & 0x7f;
if (firstLength < 126) {
expectData(firstLength);
}
else if (firstLength == 126) {
self.expect('Length', 2, function(data) {
expectData(util.unpack(data));
});
}
else if (firstLength == 127) {
self.expect('Length', 8, function(data) {
if (util.unpack(data.slice(0, 4)) != 0) {
self.error('packets with length spanning more than 32 bit is currently not supported');
return;
}
var lengthBytes = data.slice(4); // note: cap to 32 bit length
expectData(util.unpack(data));
});
}
},
// close
'8': function(data) {
self.emit('close');
self.reset();
},
// ping
'9': function(data) {
if (self.state.lastFragment == false) {
self.error('fragmented ping is not supported');
return;
}
var finish = function(mask, data) {
self.emit('ping', self.unmask(mask, data));
self.endPacket();
}
var expectData = function(length) {
if (self.state.masked) {
self.expect('Mask', 4, function(data) {
var mask = data;
self.expect('Data', length, function(data) {
finish(mask, data);
});
});
}
else {
self.expect('Data', length, function(data) {
finish(null, data);
});
}
}
// decode length
var firstLength = data[1] & 0x7f;
if (firstLength == 0) {
finish(null, null);
}
else if (firstLength < 126) {
expectData(firstLength);
}
else if (firstLength == 126) {
self.expect('Length', 2, function(data) {
expectData(util.unpack(data));
});
}
else if (firstLength == 127) {
self.expect('Length', 8, function(data) {
expectData(util.unpack(data));
});
}
}
}
this.expect('Opcode', 2, this.processPacket);
};
/**
* Inherits from EventEmitter.
*/
Parser.prototype.__proto__ = EventEmitter.prototype;
/**
* Add new data to the parser.
*
* @api public
*/
Parser.prototype.add = function(data) {
if (this.expectBuffer == null) {
this.addToOverflow(data);
return;
}
var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
this.expectOffset += toRead;
if (toRead < data.length) {
// at this point the overflow buffer shouldn't at all exist
this.overflow = new Buffer(data.length - toRead);
data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
}
if (this.expectOffset == this.expectBuffer.length) {
var bufferForHandler = this.expectBuffer;
this.expectBuffer = null;
this.expectOffset = 0;
this.expectHandler.call(this, bufferForHandler);
}
}
/**
* Adds a piece of data to the overflow.
*
* @api private
*/
Parser.prototype.addToOverflow = function(data) {
if (this.overflow == null) this.overflow = data;
else {
var prevOverflow = this.overflow;
this.overflow = new Buffer(this.overflow.length + data.length);
prevOverflow.copy(this.overflow, 0);
data.copy(this.overflow, prevOverflow.length);
}
}
/**
* Waits for a certain amount of bytes to be available, then fires a callback.
*
* @api private
*/
Parser.prototype.expect = function(what, length, handler) {
this.expectBuffer = new Buffer(length);
this.expectOffset = 0;
this.expectHandler = handler;
if (this.overflow != null) {
var toOverflow = this.overflow;
this.overflow = null;
this.add(toOverflow);
}
}
/**
* Start processing a new packet.
*
* @api private
*/
Parser.prototype.processPacket = function (data) {
if ((data[0] & 0x70) != 0) {
this.error('reserved fields must be empty');
}
this.state.lastFragment = (data[0] & 0x80) == 0x80;
this.state.masked = (data[1] & 0x80) == 0x80;
var opcode = data[0] & 0xf;
if (opcode == 0) {
// continuation frame
this.state.opcode = this.state.activeFragmentedOperation;
if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
this.error('continuation frame cannot follow current opcode')
return;
}
}
else {
this.state.opcode = opcode;
if (this.state.lastFragment === false) {
this.state.activeFragmentedOperation = opcode;
}
}
var handler = this.opcodeHandlers[this.state.opcode];
if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
else handler(data);
}
/**
* Endprocessing a packet.
*
* @api private
*/
Parser.prototype.endPacket = function() {
this.expectOffset = 0;
this.expectBuffer = null;
this.expectHandler = null;
if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
// end current fragmented operation
this.state.activeFragmentedOperation = null;
}
this.state.lastFragment = false;
this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
this.state.masked = false;
this.expect('Opcode', 2, this.processPacket);
}
/**
* Reset the parser state.
*
* @api private
*/
Parser.prototype.reset = function() {
this.state = {
activeFragmentedOperation: null,
lastFragment: false,
masked: false,
opcode: 0
};
this.expectOffset = 0;
this.expectBuffer = null;
this.expectHandler = null;
this.overflow = null;
this.currentMessage = '';
}
/**
* Unmask received data.
*
* @api private
*/
Parser.prototype.unmask = function (mask, buf, binary) {
if (mask != null) {
for (var i = 0, ll = buf.length; i < ll; i++) {
buf[i] ^= mask[i % 4];
}
}
if (binary) return buf;
return buf != null ? buf.toString('utf8') : '';
}
/**
* Concatenates a list of buffers.
*
* @api private
*/
Parser.prototype.concatBuffers = function(buffers) {
var length = 0;
for (var i = 0, l = buffers.length; i < l; ++i) {
length += buffers[i].length;
}
var mergedBuffer = new Buffer(length);
var offset = 0;
for (var i = 0, l = buffers.length; i < l; ++i) {
buffers[i].copy(mergedBuffer, offset);
offset += buffers[i].length;
}
return mergedBuffer;
}
/**
* Handles an error
*
* @api private
*/
Parser.prototype.error = function (reason) {
this.reset();
this.emit('error', reason);
return this;
};

View File

@ -0,0 +1,622 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var Transport = require('../../transport')
, EventEmitter = process.EventEmitter
, crypto = require('crypto')
, url = require('url')
, parser = require('../../parser')
, util = require('../../util');
/**
* Export the constructor.
*/
exports = module.exports = WebSocket;
exports.Parser = Parser;
/**
* HTTP interface constructor. Interface compatible with all transports that
* depend on request-response cycles.
*
* @api public
*/
function WebSocket (mng, data, req) {
// parser
var self = this;
this.manager = mng;
this.parser = new Parser();
this.parser.on('data', function (packet) {
self.onMessage(parser.decodePacket(packet));
});
this.parser.on('ping', function () {
// version 8 ping => pong
try {
self.socket.write('\u008a\u0000');
}
catch (e) {
self.end();
return;
}
});
this.parser.on('close', function () {
self.end();
});
this.parser.on('error', function (reason) {
self.log.warn(self.name + ' parser error: ' + reason);
self.end();
});
Transport.call(this, mng, data, req);
};
/**
* Inherits from Transport.
*/
WebSocket.prototype.__proto__ = Transport.prototype;
/**
* Transport name
*
* @api public
*/
WebSocket.prototype.name = 'websocket';
/**
* Websocket draft version
*
* @api public
*/
WebSocket.prototype.protocolVersion = '16';
/**
* Called when the socket connects.
*
* @api private
*/
WebSocket.prototype.onSocketConnect = function () {
var self = this;
if (typeof this.req.headers.upgrade === 'undefined' ||
this.req.headers.upgrade.toLowerCase() !== 'websocket') {
this.log.warn(this.name + ' connection invalid');
this.end();
return;
}
var origin = this.req.headers['origin'] || ''
, location = ((this.manager.settings['match origin protocol'] ?
origin.match(/^https/) : this.socket.encrypted) ?
'wss' : 'ws')
+ '://' + this.req.headers.host + this.req.url;
if (!this.verifyOrigin(origin)) {
this.log.warn(this.name + ' connection invalid: origin mismatch');
this.end();
return;
}
if (!this.req.headers['sec-websocket-key']) {
this.log.warn(this.name + ' connection invalid: received no key');
this.end();
return;
}
// calc key
var key = this.req.headers['sec-websocket-key'];
var shasum = crypto.createHash('sha1');
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
key = shasum.digest('base64');
var headers = [
'HTTP/1.1 101 Switching Protocols'
, 'Upgrade: websocket'
, 'Connection: Upgrade'
, 'Sec-WebSocket-Accept: ' + key
];
try {
this.socket.write(headers.concat('', '').join('\r\n'));
this.socket.setTimeout(0);
this.socket.setNoDelay(true);
} catch (e) {
this.end();
return;
}
this.socket.on('data', function (data) {
self.parser.add(data);
});
};
/**
* Verifies the origin of a request.
*
* @api private
*/
WebSocket.prototype.verifyOrigin = function (origin) {
var origins = this.manager.get('origins');
if (origin === 'null') origin = '*';
if (origins.indexOf('*:*') !== -1) {
return true;
}
if (origin) {
try {
var parts = url.parse(origin);
parts.port = parts.port || 80;
var ok =
~origins.indexOf(parts.hostname + ':' + parts.port) ||
~origins.indexOf(parts.hostname + ':*') ||
~origins.indexOf('*:' + parts.port);
if (!ok) this.log.warn('illegal origin: ' + origin);
return ok;
} catch (ex) {
this.log.warn('error parsing origin');
}
}
else {
this.log.warn('origin missing from websocket call, yet required by config');
}
return false;
};
/**
* Writes to the socket.
*
* @api private
*/
WebSocket.prototype.write = function (data) {
if (this.open) {
var buf = this.frame(0x81, data);
try {
this.socket.write(buf, 'binary');
}
catch (e) {
this.end();
return;
}
this.log.debug(this.name + ' writing', data);
}
};
/**
* Writes a payload.
*
* @api private
*/
WebSocket.prototype.payload = function (msgs) {
for (var i = 0, l = msgs.length; i < l; i++) {
this.write(msgs[i]);
}
return this;
};
/**
* Frame server-to-client output as a text packet.
*
* @api private
*/
WebSocket.prototype.frame = function (opcode, str) {
var dataBuffer = new Buffer(str)
, dataLength = dataBuffer.length
, startOffset = 2
, secondByte = dataLength;
if (dataLength > 65536) {
startOffset = 10;
secondByte = 127;
}
else if (dataLength > 125) {
startOffset = 4;
secondByte = 126;
}
var outputBuffer = new Buffer(dataLength + startOffset);
outputBuffer[0] = opcode;
outputBuffer[1] = secondByte;
dataBuffer.copy(outputBuffer, startOffset);
switch (secondByte) {
case 126:
outputBuffer[2] = dataLength >>> 8;
outputBuffer[3] = dataLength % 256;
break;
case 127:
var l = dataLength;
for (var i = 1; i <= 8; ++i) {
outputBuffer[startOffset - i] = l & 0xff;
l >>>= 8;
}
}
return outputBuffer;
};
/**
* Closes the connection.
*
* @api private
*/
WebSocket.prototype.doClose = function () {
this.socket.end();
};
/**
* WebSocket parser
*
* @api public
*/
function Parser () {
this.state = {
activeFragmentedOperation: null,
lastFragment: false,
masked: false,
opcode: 0
};
this.overflow = null;
this.expectOffset = 0;
this.expectBuffer = null;
this.expectHandler = null;
this.currentMessage = '';
var self = this;
this.opcodeHandlers = {
// text
'1': function(data) {
var finish = function(mask, data) {
self.currentMessage += self.unmask(mask, data);
if (self.state.lastFragment) {
self.emit('data', self.currentMessage);
self.currentMessage = '';
}
self.endPacket();
}
var expectData = function(length) {
if (self.state.masked) {
self.expect('Mask', 4, function(data) {
var mask = data;
self.expect('Data', length, function(data) {
finish(mask, data);
});
});
}
else {
self.expect('Data', length, function(data) {
finish(null, data);
});
}
}
// decode length
var firstLength = data[1] & 0x7f;
if (firstLength < 126) {
expectData(firstLength);
}
else if (firstLength == 126) {
self.expect('Length', 2, function(data) {
expectData(util.unpack(data));
});
}
else if (firstLength == 127) {
self.expect('Length', 8, function(data) {
if (util.unpack(data.slice(0, 4)) != 0) {
self.error('packets with length spanning more than 32 bit is currently not supported');
return;
}
var lengthBytes = data.slice(4); // note: cap to 32 bit length
expectData(util.unpack(data));
});
}
},
// binary
'2': function(data) {
var finish = function(mask, data) {
if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
self.currentMessage.push(self.unmask(mask, data, true));
if (self.state.lastFragment) {
self.emit('binary', self.concatBuffers(self.currentMessage));
self.currentMessage = '';
}
self.endPacket();
}
var expectData = function(length) {
if (self.state.masked) {
self.expect('Mask', 4, function(data) {
var mask = data;
self.expect('Data', length, function(data) {
finish(mask, data);
});
});
}
else {
self.expect('Data', length, function(data) {
finish(null, data);
});
}
}
// decode length
var firstLength = data[1] & 0x7f;
if (firstLength < 126) {
expectData(firstLength);
}
else if (firstLength == 126) {
self.expect('Length', 2, function(data) {
expectData(util.unpack(data));
});
}
else if (firstLength == 127) {
self.expect('Length', 8, function(data) {
if (util.unpack(data.slice(0, 4)) != 0) {
self.error('packets with length spanning more than 32 bit is currently not supported');
return;
}
var lengthBytes = data.slice(4); // note: cap to 32 bit length
expectData(util.unpack(data));
});
}
},
// close
'8': function(data) {
self.emit('close');
self.reset();
},
// ping
'9': function(data) {
if (self.state.lastFragment == false) {
self.error('fragmented ping is not supported');
return;
}
var finish = function(mask, data) {
self.emit('ping', self.unmask(mask, data));
self.endPacket();
}
var expectData = function(length) {
if (self.state.masked) {
self.expect('Mask', 4, function(data) {
var mask = data;
self.expect('Data', length, function(data) {
finish(mask, data);
});
});
}
else {
self.expect('Data', length, function(data) {
finish(null, data);
});
}
}
// decode length
var firstLength = data[1] & 0x7f;
if (firstLength == 0) {
finish(null, null);
}
else if (firstLength < 126) {
expectData(firstLength);
}
else if (firstLength == 126) {
self.expect('Length', 2, function(data) {
expectData(util.unpack(data));
});
}
else if (firstLength == 127) {
self.expect('Length', 8, function(data) {
expectData(util.unpack(data));
});
}
}
}
this.expect('Opcode', 2, this.processPacket);
};
/**
* Inherits from EventEmitter.
*/
Parser.prototype.__proto__ = EventEmitter.prototype;
/**
* Add new data to the parser.
*
* @api public
*/
Parser.prototype.add = function(data) {
if (this.expectBuffer == null) {
this.addToOverflow(data);
return;
}
var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
this.expectOffset += toRead;
if (toRead < data.length) {
// at this point the overflow buffer shouldn't at all exist
this.overflow = new Buffer(data.length - toRead);
data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
}
if (this.expectOffset == this.expectBuffer.length) {
var bufferForHandler = this.expectBuffer;
this.expectBuffer = null;
this.expectOffset = 0;
this.expectHandler.call(this, bufferForHandler);
}
}
/**
* Adds a piece of data to the overflow.
*
* @api private
*/
Parser.prototype.addToOverflow = function(data) {
if (this.overflow == null) this.overflow = data;
else {
var prevOverflow = this.overflow;
this.overflow = new Buffer(this.overflow.length + data.length);
prevOverflow.copy(this.overflow, 0);
data.copy(this.overflow, prevOverflow.length);
}
}
/**
* Waits for a certain amount of bytes to be available, then fires a callback.
*
* @api private
*/
Parser.prototype.expect = function(what, length, handler) {
this.expectBuffer = new Buffer(length);
this.expectOffset = 0;
this.expectHandler = handler;
if (this.overflow != null) {
var toOverflow = this.overflow;
this.overflow = null;
this.add(toOverflow);
}
}
/**
* Start processing a new packet.
*
* @api private
*/
Parser.prototype.processPacket = function (data) {
if ((data[0] & 0x70) != 0) {
this.error('reserved fields must be empty');
return;
}
this.state.lastFragment = (data[0] & 0x80) == 0x80;
this.state.masked = (data[1] & 0x80) == 0x80;
var opcode = data[0] & 0xf;
if (opcode == 0) {
// continuation frame
this.state.opcode = this.state.activeFragmentedOperation;
if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
this.error('continuation frame cannot follow current opcode')
return;
}
}
else {
this.state.opcode = opcode;
if (this.state.lastFragment === false) {
this.state.activeFragmentedOperation = opcode;
}
}
var handler = this.opcodeHandlers[this.state.opcode];
if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
else handler(data);
}
/**
* Endprocessing a packet.
*
* @api private
*/
Parser.prototype.endPacket = function() {
this.expectOffset = 0;
this.expectBuffer = null;
this.expectHandler = null;
if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
// end current fragmented operation
this.state.activeFragmentedOperation = null;
}
this.state.lastFragment = false;
this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
this.state.masked = false;
this.expect('Opcode', 2, this.processPacket);
}
/**
* Reset the parser state.
*
* @api private
*/
Parser.prototype.reset = function() {
this.state = {
activeFragmentedOperation: null,
lastFragment: false,
masked: false,
opcode: 0
};
this.expectOffset = 0;
this.expectBuffer = null;
this.expectHandler = null;
this.overflow = null;
this.currentMessage = '';
}
/**
* Unmask received data.
*
* @api private
*/
Parser.prototype.unmask = function (mask, buf, binary) {
if (mask != null) {
for (var i = 0, ll = buf.length; i < ll; i++) {
buf[i] ^= mask[i % 4];
}
}
if (binary) return buf;
return buf != null ? buf.toString('utf8') : '';
}
/**
* Concatenates a list of buffers.
*
* @api private
*/
Parser.prototype.concatBuffers = function(buffers) {
var length = 0;
for (var i = 0, l = buffers.length; i < l; ++i) {
length += buffers[i].length;
}
var mergedBuffer = new Buffer(length);
var offset = 0;
for (var i = 0, l = buffers.length; i < l; ++i) {
buffers[i].copy(mergedBuffer, offset);
offset += buffers[i].length;
}
return mergedBuffer;
}
/**
* Handles an error
*
* @api private
*/
Parser.prototype.error = function (reason) {
this.reset();
this.emit('error', reason);
return this;
};

View File

@ -0,0 +1,11 @@
/**
* Export websocket versions.
*/
module.exports = {
7: require('./hybi-07-12'),
8: require('./hybi-07-12'),
13: require('./hybi-16'),
default: require('./default')
};

69
node_modules/socket.io/lib/transports/xhr-polling.js generated vendored Normal file
View File

@ -0,0 +1,69 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module requirements.
*/
var HTTPPolling = require('./http-polling');
/**
* Export the constructor.
*/
exports = module.exports = XHRPolling;
/**
* Ajax polling transport.
*
* @api public
*/
function XHRPolling (mng, data, req) {
HTTPPolling.call(this, mng, data, req);
};
/**
* Inherits from Transport.
*/
XHRPolling.prototype.__proto__ = HTTPPolling.prototype;
/**
* Transport name
*
* @api public
*/
XHRPolling.prototype.name = 'xhr-polling';
/**
* Frames data prior to write.
*
* @api private
*/
XHRPolling.prototype.doWrite = function (data) {
HTTPPolling.prototype.doWrite.call(this);
var origin = this.req.headers.origin
, headers = {
'Content-Type': 'text/plain; charset=UTF-8'
, 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data)
, 'Connection': 'Keep-Alive'
};
if (origin) {
// https://developer.mozilla.org/En/HTTP_Access_Control
headers['Access-Control-Allow-Origin'] = origin;
headers['Access-Control-Allow-Credentials'] = 'true';
}
this.response.writeHead(200, headers);
this.response.write(data);
this.log.debug(this.name + ' writing', data);
};

50
node_modules/socket.io/lib/util.js generated vendored Normal file
View File

@ -0,0 +1,50 @@
/*!
* socket.io-node
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
/**
* Converts an enumerable to an array.
*
* @api public
*/
exports.toArray = function (enu) {
var arr = [];
for (var i = 0, l = enu.length; i < l; i++)
arr.push(enu[i]);
return arr;
};
/**
* Unpacks a buffer to a number.
*
* @api public
*/
exports.unpack = function (buffer) {
var n = 0;
for (var i = 0; i < buffer.length; ++i) {
n = (i == 0) ? buffer[i] : (n * 256) + buffer[i];
}
return n;
}
/**
* Left pads a string.
*
* @api public
*/
exports.padl = function (s,n,c) {
return new Array(1 + n - s.length).join(c) + s;
}