From f8e5fb60d6bd4d2e65f137458c8f48486d479114 Mon Sep 17 00:00:00 2001 From: Jack Allnutt Date: Wed, 12 Feb 2014 18:47:17 +0000 Subject: [PATCH] Update client lib engine.io v0.7.9 -> v0.9.0 --- client/assets/libs/engine.io.js | 3921 +++++++++++++++---------------- 1 file changed, 1846 insertions(+), 2075 deletions(-) diff --git a/client/assets/libs/engine.io.js b/client/assets/libs/engine.io.js index f38b4df..ec5089f 100644 --- a/client/assets/libs/engine.io.js +++ b/client/assets/libs/engine.io.js @@ -1,1876 +1,1638 @@ -;(function(){ +!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.eio=e():"undefined"!=typeof global?global.eio=e():"undefined"!=typeof self&&(self.eio=e())}(function(){var define,module,exports; +return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o [ `:` ] - * - * Example: - * - * 5:hello world - * 3 - * 4 - * - * @api private - */ - -exports.encodePacket = function (packet) { - var encoded = packets[packet.type]; - - // data fragment is optional - if (undefined !== packet.data) { - encoded += String(packet.data); - } - - return '' + encoded; -}; - -/** - * Decodes a packet. - * - * @return {Object} with `type` and `data` (if any) - * @api private - */ - -exports.decodePacket = function (data) { - var type = data.charAt(0); - - if (Number(type) != type || !packetslist[type]) { - return err; - } - - if (data.length > 1) { - return { type: packetslist[type], data: data.substring(1) }; - } else { - return { type: packetslist[type] }; - } -}; - -/** - * Encodes multiple messages (payload). - * - * :data - * - * Example: - * - * 11:hello world2:hi - * - * @param {Array} packets - * @api private - */ - -exports.encodePayload = function (packets) { - if (!packets.length) { - return '0:'; - } - - var encoded = ''; - var message; - - for (var i = 0, l = packets.length; i < l; i++) { - message = exports.encodePacket(packets[i]); - encoded += message.length + ':' + message; - } - - return encoded; -}; - -/* - * Decodes data when a payload is maybe expected. - * - * @param {String} data, callback method - * @api public - */ - -exports.decodePayload = function (data, callback) { - var packet; - if (data == '') { - // parser error - ignoring payload - return callback(err, 0, 1); - } - - var length = '' - , n, msg; - - for (var i = 0, l = data.length; i < l; i++) { - var chr = data.charAt(i); - - if (':' != chr) { - length += chr; - } else { - if ('' == length || (length != (n = Number(length)))) { - // parser error - ignoring payload - return callback(err, 0, 1); - } - - msg = data.substr(i + 1, n); - - if (length != msg.length) { - // parser error - ignoring payload - return callback(err, 0, 1); - } - - if (msg.length) { - packet = exports.decodePacket(msg); - - if (err.type == packet.type && err.data == packet.data) { - // parser error in individual packet - ignoring payload - return callback(err, 0, 1); - } - - var ret = callback(packet, i + n, l); - if (false === ret) return; - } - - // advance cursor - i += n; - length = ''; - } - } - - if (length != '') { - // parser error - ignoring payload - return callback(err, 0, 1); - } - -}; - -}); -require.register("LearnBoost-engine.io-protocol/lib/keys.js", function(exports, require, module){ - -/** - * Gets the keys for an object. - * - * @return {Array} keys - * @api private - */ - -module.exports = Object.keys || function keys (obj){ - var arr = []; - var has = Object.prototype.hasOwnProperty; - - for (var i in obj) { - if (has.call(obj, i)) { - arr.push(i); - } - } - return arr; -}; - -}); -require.register("visionmedia-debug/index.js", function(exports, require, module){ -if ('undefined' == typeof window) { - module.exports = require('./lib/debug'); -} else { - module.exports = require('./debug'); -} - -}); -require.register("visionmedia-debug/debug.js", function(exports, require, module){ - -/** - * Expose `debug()` as the module. - */ + debug('probe transport "%s" opened', name); + transport.send([{ type: 'ping', data: 'probe' }]); + transport.once('packet', function (msg) { + if (failed) return; + if ('pong' == msg.type && 'probe' == msg.data) { + debug('probe transport "%s" pong', name); + self.upgrading = true; + self.emit('upgrading', transport); -module.exports = debug; + debug('pausing current transport "%s"', self.transport.name); + self.transport.pause(function () { + if (failed) return; + if ('closed' == self.readyState || 'closing' == self.readyState) { + return; + } + debug('changing transport and sending upgrade packet'); + transport.removeListener('error', onerror); + self.emit('upgrade', transport); + self.setTransport(transport); + transport.send([{ type: 'upgrade' }]); + transport = null; + self.upgrading = false; + self.flush(); + }); + } else { + debug('probe transport "%s" failed', name); + var err = new Error('probe error'); + err.transport = transport.name; + self.emit('upgradeError', err); + } + }); + }); -/** - * Create a debugger with the given `name`. - * - * @param {String} name - * @return {Type} - * @api public - */ + transport.once('error', onerror); + function onerror(err) { + if (failed) return; -function debug(name) { - if (!debug.enabled(name)) return function(){}; + // Any callback called by transport should be ignored since now + failed = true; - return function(fmt){ - fmt = coerce(fmt); + var error = new Error('probe error: ' + err); + error.transport = transport.name; - var curr = new Date; - var ms = curr - (debug[name] || curr); - debug[name] = curr; + transport.close(); + transport = null; - fmt = name - + ' ' - + fmt - + ' +' + debug.humanize(ms); + debug('probe transport "%s" failed because of error: %s', name, err); - // This hackery is required for IE8 - // where `console.log` doesn't have 'apply' - window.console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); + self.emit('upgradeError', error); } -} - -/** - * The currently active debug mode names. - */ - -debug.names = []; -debug.skips = []; - -/** - * Enables a debug mode by name. This can include modes - * separated by a colon and wildcards. - * - * @param {String} name - * @api public - */ - -debug.enable = function(name) { - try { - localStorage.debug = name; - } catch(e){} - var split = (name || '').split(/[\s,]+/) - , len = split.length; + transport.open(); - for (var i = 0; i < len; i++) { - name = split[i].replace('*', '.*?'); - if (name[0] === '-') { - debug.skips.push(new RegExp('^' + name.substr(1) + '$')); + this.once('close', function () { + if (transport) { + debug('socket closed prematurely - aborting probe'); + failed = true; + transport.close(); + transport = null; } - else { - debug.names.push(new RegExp('^' + name + '$')); + }); + + this.once('upgrading', function (to) { + if (transport && to.name != transport.name) { + debug('"%s" works - aborting "%s"', to.name, transport.name); + transport.close(); + transport = null; } - } + }); }; /** - * Disable debug output. + * Called when connection is deemed open. * * @api public */ -debug.disable = function(){ - debug.enable(''); -}; - -/** - * Humanize the given `ms`. - * - * @param {Number} m - * @return {String} - * @api private - */ - -debug.humanize = function(ms) { - var sec = 1000 - , min = 60 * 1000 - , hour = 60 * min; - - if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; - if (ms >= min) return (ms / min).toFixed(1) + 'm'; - if (ms >= sec) return (ms / sec | 0) + 's'; - return ms + 'ms'; -}; - -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ +Socket.prototype.onOpen = function () { + debug('socket open'); + this.readyState = 'open'; + this.emit('open'); + this.onopen && this.onopen.call(this); + this.flush(); -debug.enabled = function(name) { - for (var i = 0, len = debug.skips.length; i < len; i++) { - if (debug.skips[i].test(name)) { - return false; - } - } - for (var i = 0, len = debug.names.length; i < len; i++) { - if (debug.names[i].test(name)) { - return true; + // we check for `readyState` in case an `open` + // listener already closed the socket + if ('open' == this.readyState && this.upgrade && this.transport.pause) { + debug('starting upgrade probes'); + for (var i = 0, l = this.upgrades.length; i < l; i++) { + this.probe(this.upgrades[i]); } } - return false; }; /** - * Coerce `val`. - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} - -// persist - -if (window.localStorage) debug.enable(localStorage.debug); - -}); -require.register("engine.io/lib/index.js", function(exports, require, module){ - -module.exports = require('./socket'); - -/** - * Exports parser - * - * @api public - * - */ -module.exports.parser = require('engine.io-parser'); - -}); -require.register("engine.io/lib/socket.js", function(exports, require, module){ -/** - * Module dependencies. - */ - -var util = require('./util') - , transports = require('./transports') - , Emitter = require('./emitter') - , debug = require('debug')('engine-client:socket') - , index = require('indexof') - , parser = require('engine.io-parser'); - -/** - * Module exports. - */ - -module.exports = Socket; - -/** - * Global reference. - */ - -var global = util.global(); - -/** - * Noop function. + * Handles a packet. * * @api private */ -function noop () {}; - -/** - * Socket constructor. - * - * @param {String|Object} uri or options - * @param {Object} options - * @api public - */ +Socket.prototype.onPacket = function (packet) { + if ('opening' == this.readyState || 'open' == this.readyState) { + debug('socket receive: type "%s", data "%s"', packet.type, packet.data); -function Socket(uri, opts){ - if (!(this instanceof Socket)) return new Socket(uri, opts); + this.emit('packet', packet); - opts = opts || {}; + // Socket is live - any packet counts + this.emit('heartbeat'); - if ('object' == typeof uri) { - opts = uri; - uri = null; - } + switch (packet.type) { + case 'open': + this.onHandshake(util.parseJSON(packet.data)); + break; - if (uri) { - uri = util.parseUri(uri); - opts.host = uri.host; - opts.secure = uri.protocol == 'https' || uri.protocol == 'wss'; - opts.port = uri.port; - if (uri.query) opts.query = uri.query; - } + case 'pong': + this.setPing(); + break; - this.secure = null != opts.secure ? opts.secure : - (global.location && 'https:' == location.protocol); + case 'error': + var err = new Error('server error'); + err.code = packet.data; + this.emit('error', err); + break; - if (opts.host) { - var pieces = opts.host.split(':'); - opts.hostname = pieces.shift(); - if (pieces.length) opts.port = pieces.pop(); + case 'message': + this.emit('data', packet.data); + this.emit('message', packet.data); + var event = { data: packet.data }; + event.toString = function () { + return packet.data; + }; + this.onmessage && this.onmessage.call(this, event); + break; + } + } else { + debug('packet received with socket readyState "%s"', this.readyState); } - - this.hostname = opts.hostname || - (global.location ? location.hostname : 'localhost'); - this.port = opts.port || (global.location && location.port ? - location.port : - (this.secure ? 443 : 80)); - this.query = opts.query || {}; - if ('string' == typeof this.query) this.query = util.qsParse(this.query); - this.upgrade = false !== opts.upgrade; - this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/'; - this.forceJSONP = !!opts.forceJSONP; - this.timestampParam = opts.timestampParam || 't'; - this.timestampRequests = !!opts.timestampRequests; - this.flashPath = opts.flashPath || ''; - this.transports = opts.transports || ['polling', 'websocket', 'flashsocket']; - this.readyState = ''; - this.writeBuffer = []; - this.callbackBuffer = []; - this.policyPort = opts.policyPort || 843; - this.open(); - - Socket.sockets.push(this); - Socket.sockets.evs.emit('add', this); }; /** - * Mix in `Emitter`. + * Called upon handshake completion. + * + * @param {Object} handshake obj + * @api private */ -Emitter(Socket.prototype); +Socket.prototype.onHandshake = function (data) { + this.emit('handshake', data); + this.id = data.sid; + this.transport.query.sid = data.sid; + this.upgrades = this.filterUpgrades(data.upgrades); + this.pingInterval = data.pingInterval; + this.pingTimeout = data.pingTimeout; + this.onOpen(); + this.setPing(); + + // Prolong liveness of socket on heartbeat + this.removeListener('heartbeat', this.onHeartbeat); + this.on('heartbeat', this.onHeartbeat); +}; /** - * Protocol version. + * Resets ping timeout. * - * @api public + * @api private */ -Socket.protocol = parser.protocol; // this is an int +Socket.prototype.onHeartbeat = function (timeout) { + clearTimeout(this.pingTimeoutTimer); + var self = this; + self.pingTimeoutTimer = setTimeout(function () { + if ('closed' == self.readyState) return; + self.onClose('ping timeout'); + }, timeout || (self.pingInterval + self.pingTimeout)); +}; /** - * Static EventEmitter. + * Pings server every `this.pingInterval` and expects response + * within `this.pingTimeout` or closes connection. + * + * @api private */ -Socket.sockets = []; -Socket.sockets.evs = new Emitter; +Socket.prototype.setPing = function () { + var self = this; + clearTimeout(self.pingIntervalTimer); + self.pingIntervalTimer = setTimeout(function () { + debug('writing ping packet - expecting pong within %sms', self.pingTimeout); + self.ping(); + self.onHeartbeat(self.pingTimeout); + }, self.pingInterval); +}; /** - * Expose deps for legacy compatibility - * and standalone browser access. - */ +* Sends a ping packet. +* +* @api public +*/ -Socket.Socket = Socket; -Socket.Transport = require('./transport'); -Socket.Emitter = require('./emitter'); -Socket.transports = require('./transports'); -Socket.util = require('./util'); -Socket.parser = require('engine.io-parser'); +Socket.prototype.ping = function () { + this.sendPacket('ping'); +}; /** - * Creates transport of the given type. + * Called on `drain` event * - * @param {String} transport name - * @return {Transport} * @api private */ -Socket.prototype.createTransport = function (name) { - debug('creating transport "%s"', name); - var query = clone(this.query); + Socket.prototype.onDrain = function() { + for (var i = 0; i < this.prevBufferLen; i++) { + if (this.callbackBuffer[i]) { + this.callbackBuffer[i](); + } + } - // append engine.io protocol identifier - query.EIO = parser.protocol; + this.writeBuffer.splice(0, this.prevBufferLen); + this.callbackBuffer.splice(0, this.prevBufferLen); - // transport name - query.transport = name; + // setting prevBufferLen = 0 is very important + // for example, when upgrading, upgrade packet is sent over, + // and a nonzero prevBufferLen could cause problems on `drain` + this.prevBufferLen = 0; - // session id if we already have one - if (this.id) query.sid = this.id; + if (this.writeBuffer.length == 0) { + this.emit('drain'); + } else { + this.flush(); + } +}; - var transport = new transports[name]({ - hostname: this.hostname, - port: this.port, - secure: this.secure, - path: this.path, - query: query, - forceJSONP: this.forceJSONP, - timestampRequests: this.timestampRequests, - timestampParam: this.timestampParam, - flashPath: this.flashPath, - policyPort: this.policyPort - }); +/** + * Flush write buffers. + * + * @api private + */ - return transport; +Socket.prototype.flush = function () { + if ('closed' != this.readyState && this.transport.writable && + !this.upgrading && this.writeBuffer.length) { + debug('flushing %d packets in socket', this.writeBuffer.length); + this.transport.send(this.writeBuffer); + // keep track of current length of writeBuffer + // splice writeBuffer and callbackBuffer on `drain` + this.prevBufferLen = this.writeBuffer.length; + this.emit('flush'); + } }; -function clone (obj) { - var o = {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - o[i] = obj[i]; - } - } - return o; -} +/** + * Sends a message. + * + * @param {String} message. + * @param {Function} callback function. + * @return {Socket} for chaining. + * @api public + */ + +Socket.prototype.write = +Socket.prototype.send = function (msg, fn) { + this.sendPacket('message', msg, fn); + return this; +}; /** - * Initializes transport to use and starts probe. + * Sends a packet. * + * @param {String} packet type. + * @param {String} data. + * @param {Function} callback function. * @api private */ -Socket.prototype.open = function () { - this.readyState = 'opening'; - var transport = this.createTransport(this.transports[0]); - transport.open(); - this.setTransport(transport); +Socket.prototype.sendPacket = function (type, data, fn) { + var packet = { type: type, data: data }; + this.emit('packetCreate', packet); + this.writeBuffer.push(packet); + this.callbackBuffer.push(fn); + this.flush(); }; /** - * Sets the current transport. Disables the existing one (if any). + * Closes the connection. * * @api private */ -Socket.prototype.setTransport = function (transport) { - var self = this; - - if (this.transport) { - debug('clearing existing transport'); - this.transport.removeAllListeners(); +Socket.prototype.close = function () { + if ('opening' == this.readyState || 'open' == this.readyState) { + this.onClose('forced close'); + debug('socket closing - telling transport to close'); + this.transport.close(); } - // set up transport - this.transport = transport; + return this; +}; - // set up transport listeners - transport - .on('drain', function () { - self.onDrain(); - }) - .on('packet', function (packet) { - self.onPacket(packet); - }) - .on('error', function (e) { - self.onError(e); - }) - .on('close', function () { - self.onClose('transport close'); - }); +/** + * Called upon transport error + * + * @api private + */ + +Socket.prototype.onError = function (err) { + debug('socket error %j', err); + this.emit('error', err); + this.onerror && this.onerror.call(this, err); + this.onClose('transport error', err); }; /** - * Probes a transport. + * Called upon transport close. * - * @param {String} transport name * @api private */ -Socket.prototype.probe = function (name) { - debug('probing transport "%s"', name); - var transport = this.createTransport(name, { probe: 1 }) - , failed = false - , self = this; +Socket.prototype.onClose = function (reason, desc) { + if ('opening' == this.readyState || 'open' == this.readyState) { + debug('socket close with reason: "%s"', reason); + var self = this; - transport.once('open', function () { - if (failed) return; + // clear timers + clearTimeout(this.pingIntervalTimer); + clearTimeout(this.pingTimeoutTimer); - debug('probe transport "%s" opened', name); - transport.send([{ type: 'ping', data: 'probe' }]); - transport.once('packet', function (msg) { - if (failed) return; - if ('pong' == msg.type && 'probe' == msg.data) { - debug('probe transport "%s" pong', name); - self.upgrading = true; - self.emit('upgrading', transport); + // clean buffers in next tick, so developers can still + // grab the buffers on `close` event + setTimeout(function() { + self.writeBuffer = []; + self.callbackBuffer = []; + self.prevBufferLen = 0; + }, 0); - debug('pausing current transport "%s"', self.transport.name); - self.transport.pause(function () { - if (failed) return; - if ('closed' == self.readyState || 'closing' == self.readyState) { - return; - } - debug('changing transport and sending upgrade packet'); - transport.removeListener('error', onerror); - self.emit('upgrade', transport); - self.setTransport(transport); - transport.send([{ type: 'upgrade' }]); - transport = null; - self.upgrading = false; - self.flush(); - }); - } else { - debug('probe transport "%s" failed', name); - var err = new Error('probe error'); - err.transport = transport.name; - self.emit('error', err); - } - }); - }); + // ignore further transport communication + this.transport.removeAllListeners(); + + // set ready state + this.readyState = 'closed'; + + // clear session id + this.id = null; + + // emit close event + this.emit('close', reason, desc); + this.onclose && this.onclose.call(this); + } +}; + +/** + * Filters upgrades, returning only those matching client transports. + * + * @param {Array} server upgrades + * @api private + * + */ - transport.once('error', onerror); - function onerror(err) { - if (failed) return; +Socket.prototype.filterUpgrades = function (upgrades) { + var filteredUpgrades = []; + for (var i = 0, j = upgrades.length; i