From 7df19c6fe5c8bbb00d9ad69038bf1590de5fd3be Mon Sep 17 00:00:00 2001 From: GSiry Date: Sun, 31 Dec 2017 14:31:25 -0500 Subject: [PATCH] initial push to github --- .gitattributes | 2 + .gitignore | 20 +++ .jshintrc | 20 +++ .npmignore | 21 +++ .travis.yml | 10 ++ .vscode/launch.json | 11 ++ README.md | 2 + Signaling-Server.js | 404 +++++++++++++++++++++++++++++++++++++++++++ config.json | 5 + package.json | 47 +++++ res/socket.io.min.js | 25 +++ server.js | 86 +++++++++ socket.io.js | 3 + socket.io.min.js | 25 +++ underscore-min.js | 6 + 15 files changed, 687 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 .npmignore create mode 100644 .travis.yml create mode 100644 .vscode/launch.json create mode 100644 README.md create mode 100644 Signaling-Server.js create mode 100644 config.json create mode 100644 package.json create mode 100644 res/socket.io.min.js create mode 100644 server.js create mode 100644 socket.io.js create mode 100644 socket.io.min.js create mode 100644 underscore-min.js diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..eba1110 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a919175 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +node_modules +bower_components + +make-tar.sh + +*.tar.gz +lib-cov + +.*.swp +._* +.DS_Store +.git +.hg +.npmrc +.lock-wscript +.svn +.wafpickle-* +config.gypi +CVS +npm-debug.log \ No newline at end of file diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..d7bfa51 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,20 @@ +{ + "browser": true, + "camelcase": true, + "curly": true, + "devel": true, + "eqeqeq": true, + "forin": false, + "globalstrict": true, + "quotmark": "single", + "undef": true, + "unused": "strict", + "globals": { + "RTCMultiConnection": true, + "RMCDefaultChannel": true, + "selfNPObject": true, + "MediaStream": true, + "AudioContext": true, + "onPluginRTCInitialized": true + } +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..fe7365c --- /dev/null +++ b/.npmignore @@ -0,0 +1,21 @@ +node_modules +bower_components + +make-tar.sh + +*.tar.gz +lib-cov +v2.2.2 + +.*.swp +._* +.DS_Store +.git +.hg +.npmrc +.lock-wscript +.svn +.wafpickle-* +config.gypi +CVS +npm-debug.log \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..c1cc706 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: + - "0.11" +install: npm install +before_script: + - npm install grunt-cli + - npm install grunt + - grunt +matrix: + fast_finish: true diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..982a2b0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}\\server.js" + } + ] + } \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f580cfe --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +A Modified version of Muaz Khan's Socket.io based signaliing server for WebRTC. +This version is designed to be used with the AVSPEED iConfRTC SDK \ No newline at end of file diff --git a/Signaling-Server.js b/Signaling-Server.js new file mode 100644 index 0000000..30d177c --- /dev/null +++ b/Signaling-Server.js @@ -0,0 +1,404 @@ +// Muaz Khan - www.MuazKhan.com +// MIT License - www.WebRTC-Experiment.com/licence + +// 2017-12-31 updated by gaetan siry to work with the iConfRTC SDK +// AVSPEED RTC Signaling Server +// info@avspeed.com + +module.exports = exports = function(app, socketCallback) { + var listOfUsers = {}; + var users = {}; + var shiftedModerationControls = {}; + var ScalableBroadcast; + + var io = require('socket.io'); + var _ = require('./underscore-min.js'); + + + try { + io = io(app); + io.on('connection', onConnection); + } catch (e) { + io = io.listen(app, { + log: true, + origins: '*:*' + }); + + io.set('transports', [ + 'websocket', // 'disconnect' EVENT will work only with 'websocket' + 'xhr-polling', + 'jsonp-polling' + ]); + + io.sockets.on('connection', onConnection); + } + + function findClientsSocket(roomId, namespace) { + var res = [] + // the default namespace is "/" + , + ns = io.of(namespace || "/"); + + if (ns) { + for (var id in ns.connected) { + if (roomId) { + var index = ns.connected[id].rooms.indexOf(roomId); + if (index !== -1) { + res.push(ns.connected[id]); + } + } else { + res.push(ns.connected[id]); + } + } + } + return res; + } + + function onConnection(socket) { + var params = socket.handshake.query; + var socketMessageEvent = params.msgEvent || 'RTCConnection-Message'; + + // temporarily disabled + if (false && !!listOfUsers[params.userid]) { + params.dontUpdateUserId = true; + + var useridAlreadyTaken = params.userid; + params.userid = (Math.random() * 1000).toString().replace('.', ''); + socket.emit('userid-already-taken', useridAlreadyTaken, params.userid); + } + + var decodedUserStr = new Buffer(params.userName, 'base64') + var decodedUser = decodedUserStr.toString(); + + socket.userid = params.userid; + socket.username = decodedUser; + socket.session = params.session; + + //main user list + users[socket.id] = { + id: socket.id, + userName: socket.username, + session: socket.session + }; + + listOfUsers[socket.userid] = { + socket: socket, + connectedWith: {}, + isPublic: false, // means: isPublicModerator + extra: {}, + userName: socket.username, + session: socket.session + }; + + socket.on('JoinMeeting', function(meetingID) { + + console.log('joining with socket id ' + socket.id + ' user ' + socket.username); + socket.join(meetingID); + //update user list with current meeting ID + users[socket.id].meetingID = meetingID; + + //send a new list of users w/ session to view to the users in my meeting + var tempList = _.where(users, { meetingID: meetingID }); + + socket.broadcast.to(meetingID).emit('onJoinedMeeting', meetingID, socket.id, socket.username, socket.session, tempList); + socket.emit('onSelfJoinedMeeting', meetingID, socket.id, socket.username, socket.session, tempList); + }); + + socket.on('LeaveMeeting', function() { + var meetingID = users[socket.id].meetingID; + + delete users[socket.id]; + delete listOfUsers[socket.id]; + socket.broadcast.to(meetingID).emit('onUserLeftMeeting', meetingID, socket.id, socket.username, socket.session); + socket.emit('onSelfLeftMeeting', meetingID, socket.id, socket.username, socket.session); + }); + + socket.on('SendMessageToMeeting', function(message, toUser) { + var meetingID = users[socket.id].meetingID; + + if (toUser != "") { + socket.broadcast.to(meetingID).emit('onMeetingMessageReceived', message, socket.username, socket.id, true); + } else { + //todo gsiry 9/19/2016 + //socket.broadcast.to(meetingID).emit('onMeetingMessageReceived', message, socket.username, socket.id, true); + } + }); + + socket.on('extra-data-updated', function(extra) { + try { + if (!listOfUsers[socket.userid]) return; + listOfUsers[socket.userid].extra = extra; + + for (var user in listOfUsers[socket.userid].connectedWith) { + listOfUsers[user].socket.emit('extra-data-updated', socket.userid, extra); + } + } catch (e) {} + }); + + socket.on('become-a-public-moderator', function() { + try { + if (!listOfUsers[socket.userid]) return; + listOfUsers[socket.userid].isPublic = true; + } catch (e) {} + }); + + socket.on('dont-make-me-moderator', function() { + try { + if (!listOfUsers[socket.userid]) return; + listOfUsers[socket.userid].isPublic = false; + } catch (e) {} + }); + + socket.on('get-public-moderators', function(userIdStartsWith, callback) { + try { + userIdStartsWith = userIdStartsWith || ''; + var allPublicModerators = []; + for (var moderatorId in listOfUsers) { + if (listOfUsers[moderatorId].isPublic && moderatorId.indexOf(userIdStartsWith) === 0 && moderatorId !== socket.userid) { + var moderator = listOfUsers[moderatorId]; + allPublicModerators.push({ + userid: moderatorId, + extra: moderator.extra + }); + } + } + + callback(allPublicModerators); + } catch (e) {} + }); + + socket.on('changed-uuid', function(newUserId, callback) { + if (params.dontUpdateUserId) { + delete params.dontUpdateUserId; + return; + } + + try { + if (listOfUsers[socket.userid] && listOfUsers[socket.userid].socket.id == socket.userid) { + if (newUserId === socket.userid) return; + + var oldUserId = socket.userid; + listOfUsers[newUserId] = listOfUsers[oldUserId]; + listOfUsers[newUserId].socket.userid = socket.userid = newUserId; + delete listOfUsers[oldUserId]; + + callback(); + return; + } + + socket.userid = newUserId; + listOfUsers[socket.userid] = { + socket: socket, + connectedWith: {}, + isPublic: false, + extra: {} + }; + + callback(); + } catch (e) {} + }); + + socket.on('set-password', function(password) { + try { + if (listOfUsers[socket.userid]) { + listOfUsers[socket.userid].password = password; + } + } catch (e) {} + }); + + socket.on('disconnect-with', function(remoteUserId, callback) { + try { + if (listOfUsers[socket.userid] && listOfUsers[socket.userid].connectedWith[remoteUserId]) { + delete listOfUsers[socket.userid].connectedWith[remoteUserId]; + socket.emit('user-disconnected', remoteUserId); + } + + if (!listOfUsers[remoteUserId]) return callback(); + + if (listOfUsers[remoteUserId].connectedWith[socket.userid]) { + delete listOfUsers[remoteUserId].connectedWith[socket.userid]; + listOfUsers[remoteUserId].socket.emit('user-disconnected', socket.userid); + } + callback(); + } catch (e) {} + }); + + socket.on('close-entire-session', function(callback) { + try { + var connectedWith = listOfUsers[socket.userid].connectedWith; + Object.keys(connectedWith).forEach(function(key) { + if (connectedWith[key] && connectedWith[key].emit) { + try { + connectedWith[key].emit('closed-entire-session', socket.userid, listOfUsers[socket.userid].extra); + } catch (e) {} + } + }); + + delete shiftedModerationControls[socket.userid]; + callback(); + } catch (e) { + throw e; + } + }); + + function onMessageCallback(message) { + try { + if (!listOfUsers[message.sender]) { + socket.emit('user-not-found', message.sender); + return; + } + + if (!message.message.userLeft && !listOfUsers[message.sender].connectedWith[message.remoteUserId] && !!listOfUsers[message.remoteUserId]) { + listOfUsers[message.sender].connectedWith[message.remoteUserId] = listOfUsers[message.remoteUserId].socket; + listOfUsers[message.sender].socket.emit('user-connected', message.remoteUserId); + + if (!listOfUsers[message.remoteUserId]) { + listOfUsers[message.remoteUserId] = { + socket: null, + connectedWith: {}, + isPublic: false, + extra: {} + }; + } + + listOfUsers[message.remoteUserId].connectedWith[message.sender] = socket; + + if (listOfUsers[message.remoteUserId].socket) { + listOfUsers[message.remoteUserId].socket.emit('user-connected', message.sender); + } + } + + if (listOfUsers[message.sender].connectedWith[message.remoteUserId] && listOfUsers[socket.userid]) { + message.extra = listOfUsers[socket.userid].extra; + listOfUsers[message.sender].connectedWith[message.remoteUserId].emit(socketMessageEvent, message); + } + } catch (e) {} + } + + var numberOfPasswordTries = 0; + socket.on(socketMessageEvent, function(message, callback) { + if (message.remoteUserId && message.remoteUserId === socket.userid) { + // remoteUserId MUST be unique + return; + } + + try { + if (message.remoteUserId && message.remoteUserId != 'system' && message.message.newParticipationRequest) { + if (listOfUsers[message.remoteUserId] && listOfUsers[message.remoteUserId].password) { + if (numberOfPasswordTries > 3) { + socket.emit('password-max-tries-over', message.remoteUserId); + return; + } + + if (!message.password) { + numberOfPasswordTries++; + socket.emit('join-with-password', message.remoteUserId); + return; + } + + if (message.password != listOfUsers[message.remoteUserId].password) { + numberOfPasswordTries++; + socket.emit('invalid-password', message.remoteUserId, message.password); + return; + } + } + } + + if (message.message.shiftedModerationControl) { + if (!message.message.firedOnLeave) { + onMessageCallback(message); + return; + } + shiftedModerationControls[message.sender] = message; + return; + } + + if (message.remoteUserId == 'system') { + if (message.message.detectPresence) { + if (message.message.userid === socket.userid) { + callback(false, socket.userid); + return; + } + + callback(!!listOfUsers[message.message.userid], message.message.userid); + return; + } + } + + if (!listOfUsers[message.sender]) { + listOfUsers[message.sender] = { + socket: socket, + connectedWith: {}, + isPublic: false, + extra: {} + }; + } + + // if someone tries to join a person who is absent + if (message.message.newParticipationRequest) { + var waitFor = 120; // 2 minutes + var invokedTimes = 0; + (function repeater() { + invokedTimes++; + if (invokedTimes > waitFor) { + socket.emit('user-not-found', message.remoteUserId); + return; + } + + if (listOfUsers[message.remoteUserId] && listOfUsers[message.remoteUserId].socket) { + onMessageCallback(message); + return; + } + + setTimeout(repeater, 1000); + })(); + + return; + } + + onMessageCallback(message); + } catch (e) {} + }); + + socket.on('disconnect', function() { + try { + var meetingID = users[this.id].meetingID; + + delete socket.namespace.sockets[this.id]; + delete users[this.id]; + delete listOfUsers[this.id]; + socket.broadcast.to(meetingID).emit('onUserLeftMeeting', meetingID, this.id, this.username, this.session); + socket.emit('onSelfLeftMeeting', meetingID, this.id, this.username, this.session); + } catch (e) {} + + try { + var message = shiftedModerationControls[socket.userid]; + + if (message) { + delete shiftedModerationControls[message.userid]; + onMessageCallback(message); + } + } catch (e) {} + + try { + // inform all connected users + if (listOfUsers[socket.userid]) { + for (var s in listOfUsers[socket.userid].connectedWith) { + listOfUsers[socket.userid].connectedWith[s].emit('user-disconnected', socket.userid); + + if (listOfUsers[s] && listOfUsers[s].connectedWith[socket.userid]) { + delete listOfUsers[s].connectedWith[socket.userid]; + listOfUsers[s].socket.emit('user-disconnected', socket.userid); + } + } + } + } catch (e) {} + + delete listOfUsers[socket.userid]; + }); + + if (socketCallback) { + socketCallback(socket); + } + } +}; \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..01d8638 --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "socketURL": "https://avrtc.herokuapp.com:9001/", + "socketMessageEvent": "RTCMultiConnection-Message", + "socketCustomEvent": "RTCMultiConnection-Custom-Message" +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..b64249f --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "rtcsignaling.io", + "preferGlobal": false, + "version": "1.0.0", + "author": { + "name": "AVSPEED", + "email": "info@avspeed.com", + "url": "https://avspeed.github.io/" + }, + "description": "Signaling server for the iConfRTC SDK", + "main": "server.js", + "repository": { + "type": "git", + "url": "https://github.com/avspeed/RTCSignaling.io.git" + }, + "keywords": [ + "peer-to-peer", + "peer2peer", + "peer", + "webrtc", + "video-chat" + ], + "dependencies": { + "socket.io": "0.9.17" + }, + "analyze": false, + "license": "MIT", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/avspeed/RTCSignaling.io/issues", + "email": "info@avspeed.com" + }, + "homepage": "", + "devDependencies": { + "grunt": "0.4.5", + "grunt-bump": "0.7.0", + "grunt-cli": "0.1.13", + "grunt-contrib-clean": "0.6.0", + "grunt-contrib-concat": "0.5.1", + "grunt-contrib-copy": "0.8.2", + "grunt-contrib-uglify": "0.11.0", + "grunt-jsbeautifier": "0.2.10", + "grunt-replace": "0.11.0", + "load-grunt-tasks": "3.4.0", + "socket.io": "^0.9.17" + } +} diff --git a/res/socket.io.min.js b/res/socket.io.min.js new file mode 100644 index 0000000..1c1cb28 --- /dev/null +++ b/res/socket.io.min.js @@ -0,0 +1,25 @@ +!function (e) { if ("object" == typeof exports && "undefined" != typeof module) module.exports = e(); else if ("function" == typeof define && define.amd) define([], e); else { var f; "undefined" != typeof window ? f = window : "undefined" != typeof global ? f = global : "undefined" != typeof self && (f = self), f.io = 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 < r.length; o++) s(r[o]); return s }({ + 1: [function (_dereq_, module, exports) { module.exports = _dereq_("./lib/") }, { "./lib/": 2 }], 2: [function (_dereq_, module, exports) { var url = _dereq_("./url"); var parser = _dereq_("socket.io-parser"); var Manager = _dereq_("./manager"); var debug = _dereq_("debug")("socket.io-client"); module.exports = exports = lookup; var cache = exports.managers = {}; function lookup(uri, opts) { if (typeof uri == "object") { opts = uri; uri = undefined } opts = opts || {}; var parsed = url(uri); var source = parsed.source; var id = parsed.id; var io; if (opts.forceNew || opts["force new connection"] || false === opts.multiplex) { debug("ignoring socket cache for %s", source); io = Manager(source, opts) } else { if (!cache[id]) { debug("new io instance for %s", source); cache[id] = Manager(source, opts) } io = cache[id] } return io.socket(parsed.path) } exports.protocol = parser.protocol; exports.connect = lookup; exports.Manager = _dereq_("./manager"); exports.Socket = _dereq_("./socket") }, { "./manager": 3, "./socket": 5, "./url": 6, debug: 10, "socket.io-parser": 46 }], 3: [function (_dereq_, module, exports) { var url = _dereq_("./url"); var eio = _dereq_("engine.io-client"); var Socket = _dereq_("./socket"); var Emitter = _dereq_("component-emitter"); var parser = _dereq_("socket.io-parser"); var on = _dereq_("./on"); var bind = _dereq_("component-bind"); var object = _dereq_("object-component"); var debug = _dereq_("debug")("socket.io-client:manager"); var indexOf = _dereq_("indexof"); var Backoff = _dereq_("backo2"); module.exports = Manager; function Manager(uri, opts) { if (!(this instanceof Manager)) return new Manager(uri, opts); if (uri && "object" == typeof uri) { opts = uri; uri = undefined } opts = opts || {}; opts.path = opts.path || "/socket.io"; this.nsps = {}; this.subs = []; this.opts = opts; this.reconnection(opts.reconnection !== false); this.reconnectionAttempts(opts.reconnectionAttempts || Infinity); this.reconnectionDelay(opts.reconnectionDelay || 1e3); this.reconnectionDelayMax(opts.reconnectionDelayMax || 5e3); this.randomizationFactor(opts.randomizationFactor || .5); this.backoff = new Backoff({ min: this.reconnectionDelay(), max: this.reconnectionDelayMax(), jitter: this.randomizationFactor() }); this.timeout(null == opts.timeout ? 2e4 : opts.timeout); this.readyState = "closed"; this.uri = uri; this.connected = []; this.encoding = false; this.packetBuffer = []; this.encoder = new parser.Encoder; this.decoder = new parser.Decoder; this.autoConnect = opts.autoConnect !== false; if (this.autoConnect) this.open() } Manager.prototype.emitAll = function () { this.emit.apply(this, arguments); for (var nsp in this.nsps) { this.nsps[nsp].emit.apply(this.nsps[nsp], arguments) } }; Manager.prototype.updateSocketIds = function () { for (var nsp in this.nsps) { this.nsps[nsp].id = this.engine.id } }; Emitter(Manager.prototype); Manager.prototype.reconnection = function (v) { if (!arguments.length) return this._reconnection; this._reconnection = !!v; return this }; Manager.prototype.reconnectionAttempts = function (v) { if (!arguments.length) return this._reconnectionAttempts; this._reconnectionAttempts = v; return this }; Manager.prototype.reconnectionDelay = function (v) { if (!arguments.length) return this._reconnectionDelay; this._reconnectionDelay = v; this.backoff && this.backoff.setMin(v); return this }; Manager.prototype.randomizationFactor = function (v) { if (!arguments.length) return this._randomizationFactor; this._randomizationFactor = v; this.backoff && this.backoff.setJitter(v); return this }; Manager.prototype.reconnectionDelayMax = function (v) { if (!arguments.length) return this._reconnectionDelayMax; this._reconnectionDelayMax = v; this.backoff && this.backoff.setMax(v); return this }; Manager.prototype.timeout = function (v) { if (!arguments.length) return this._timeout; this._timeout = v; return this }; Manager.prototype.maybeReconnectOnOpen = function () { if (!this.reconnecting && this._reconnection && this.backoff.attempts === 0) { this.reconnect() } }; Manager.prototype.open = Manager.prototype.connect = function (fn) { debug("readyState %s", this.readyState); if (~this.readyState.indexOf("open")) return this; debug("opening %s", this.uri); this.engine = eio(this.uri, this.opts); var socket = this.engine; var self = this; this.readyState = "opening"; this.skipReconnect = false; var openSub = on(socket, "open", function () { self.onopen(); fn && fn() }); var errorSub = on(socket, "error", function (data) { debug("connect_error"); self.cleanup(); self.readyState = "closed"; self.emitAll("connect_error", data); if (fn) { var err = new Error("Connection error"); err.data = data; fn(err) } else { self.maybeReconnectOnOpen() } }); if (false !== this._timeout) { var timeout = this._timeout; debug("connect attempt will timeout after %d", timeout); var timer = setTimeout(function () { debug("connect attempt timed out after %d", timeout); openSub.destroy(); socket.close(); socket.emit("error", "timeout"); self.emitAll("connect_timeout", timeout) }, timeout); this.subs.push({ destroy: function () { clearTimeout(timer) } }) } this.subs.push(openSub); this.subs.push(errorSub); return this }; Manager.prototype.onopen = function () { debug("open"); this.cleanup(); this.readyState = "open"; this.emit("open"); var socket = this.engine; this.subs.push(on(socket, "data", bind(this, "ondata"))); this.subs.push(on(this.decoder, "decoded", bind(this, "ondecoded"))); this.subs.push(on(socket, "error", bind(this, "onerror"))); this.subs.push(on(socket, "close", bind(this, "onclose"))) }; Manager.prototype.ondata = function (data) { this.decoder.add(data) }; Manager.prototype.ondecoded = function (packet) { this.emit("packet", packet) }; Manager.prototype.onerror = function (err) { debug("error", err); this.emitAll("error", err) }; Manager.prototype.socket = function (nsp) { var socket = this.nsps[nsp]; if (!socket) { socket = new Socket(this, nsp); this.nsps[nsp] = socket; var self = this; socket.on("connect", function () { socket.id = self.engine.id; if (!~indexOf(self.connected, socket)) { self.connected.push(socket) } }) } return socket }; Manager.prototype.destroy = function (socket) { var index = indexOf(this.connected, socket); if (~index) this.connected.splice(index, 1); if (this.connected.length) return; this.close() }; Manager.prototype.packet = function (packet) { debug("writing packet %j", packet); var self = this; if (!self.encoding) { self.encoding = true; this.encoder.encode(packet, function (encodedPackets) { for (var i = 0; i < encodedPackets.length; i++) { self.engine.write(encodedPackets[i]) } self.encoding = false; self.processPacketQueue() }) } else { self.packetBuffer.push(packet) } }; Manager.prototype.processPacketQueue = function () { if (this.packetBuffer.length > 0 && !this.encoding) { var pack = this.packetBuffer.shift(); this.packet(pack) } }; Manager.prototype.cleanup = function () { var sub; while (sub = this.subs.shift()) sub.destroy(); this.packetBuffer = []; this.encoding = false; this.decoder.destroy() }; Manager.prototype.close = Manager.prototype.disconnect = function () { this.skipReconnect = true; this.backoff.reset(); this.readyState = "closed"; this.engine && this.engine.close() }; Manager.prototype.onclose = function (reason) { debug("close"); this.cleanup(); this.backoff.reset(); this.readyState = "closed"; this.emit("close", reason); if (this._reconnection && !this.skipReconnect) { this.reconnect() } }; Manager.prototype.reconnect = function () { if (this.reconnecting || this.skipReconnect) return this; var self = this; if (this.backoff.attempts >= this._reconnectionAttempts) { debug("reconnect failed"); this.backoff.reset(); this.emitAll("reconnect_failed"); this.reconnecting = false } else { var delay = this.backoff.duration(); debug("will wait %dms before reconnect attempt", delay); this.reconnecting = true; var timer = setTimeout(function () { if (self.skipReconnect) return; debug("attempting reconnect"); self.emitAll("reconnect_attempt", self.backoff.attempts); self.emitAll("reconnecting", self.backoff.attempts); if (self.skipReconnect) return; self.open(function (err) { if (err) { debug("reconnect attempt error"); self.reconnecting = false; self.reconnect(); self.emitAll("reconnect_error", err.data) } else { debug("reconnect success"); self.onreconnect() } }) }, delay); this.subs.push({ destroy: function () { clearTimeout(timer) } }) } }; Manager.prototype.onreconnect = function () { var attempt = this.backoff.attempts; this.reconnecting = false; this.backoff.reset(); this.updateSocketIds(); this.emitAll("reconnect", attempt) } }, { "./on": 4, "./socket": 5, "./url": 6, backo2: 7, "component-bind": 8, "component-emitter": 9, debug: 10, "engine.io-client": 11, indexof: 42, "object-component": 43, "socket.io-parser": 46 }], 4: [function (_dereq_, module, exports) { module.exports = on; function on(obj, ev, fn) { obj.on(ev, fn); return { destroy: function () { obj.removeListener(ev, fn) } } } }, {}], 5: [function (_dereq_, module, exports) { var parser = _dereq_("socket.io-parser"); var Emitter = _dereq_("component-emitter"); var toArray = _dereq_("to-array"); var on = _dereq_("./on"); var bind = _dereq_("component-bind"); var debug = _dereq_("debug")("socket.io-client:socket"); var hasBin = _dereq_("has-binary"); module.exports = exports = Socket; var events = { connect: 1, connect_error: 1, connect_timeout: 1, disconnect: 1, error: 1, reconnect: 1, reconnect_attempt: 1, reconnect_failed: 1, reconnect_error: 1, reconnecting: 1 }; var emit = Emitter.prototype.emit; function Socket(io, nsp) { this.io = io; this.nsp = nsp; this.json = this; this.ids = 0; this.acks = {}; if (this.io.autoConnect) this.open(); this.receiveBuffer = []; this.sendBuffer = []; this.connected = false; this.disconnected = true } Emitter(Socket.prototype); Socket.prototype.subEvents = function () { if (this.subs) return; var io = this.io; this.subs = [on(io, "open", bind(this, "onopen")), on(io, "packet", bind(this, "onpacket")), on(io, "close", bind(this, "onclose"))] }; Socket.prototype.open = Socket.prototype.connect = function () { if (this.connected) return this; this.subEvents(); this.io.open(); if ("open" == this.io.readyState) this.onopen(); return this }; Socket.prototype.send = function () { var args = toArray(arguments); args.unshift("message"); this.emit.apply(this, args); return this }; Socket.prototype.emit = function (ev) { if (events.hasOwnProperty(ev)) { emit.apply(this, arguments); return this } var args = toArray(arguments); var parserType = parser.EVENT; if (hasBin(args)) { parserType = parser.BINARY_EVENT } var packet = { type: parserType, data: args }; if ("function" == typeof args[args.length - 1]) { debug("emitting packet with ack id %d", this.ids); this.acks[this.ids] = args.pop(); packet.id = this.ids++ } if (this.connected) { this.packet(packet) } else { this.sendBuffer.push(packet) } return this }; Socket.prototype.packet = function (packet) { packet.nsp = this.nsp; this.io.packet(packet) }; Socket.prototype.onopen = function () { debug("transport is open - connecting"); if ("/" != this.nsp) { this.packet({ type: parser.CONNECT }) } }; Socket.prototype.onclose = function (reason) { debug("close (%s)", reason); this.connected = false; this.disconnected = true; delete this.id; this.emit("disconnect", reason) }; Socket.prototype.onpacket = function (packet) { if (packet.nsp != this.nsp) return; switch (packet.type) { case parser.CONNECT: this.onconnect(); break; case parser.EVENT: this.onevent(packet); break; case parser.BINARY_EVENT: this.onevent(packet); break; case parser.ACK: this.onack(packet); break; case parser.BINARY_ACK: this.onack(packet); break; case parser.DISCONNECT: this.ondisconnect(); break; case parser.ERROR: this.emit("error", packet.data); break } }; Socket.prototype.onevent = function (packet) { var args = packet.data || []; debug("emitting event %j", args); if (null != packet.id) { debug("attaching ack callback to event"); args.push(this.ack(packet.id)) } if (this.connected) { emit.apply(this, args) } else { this.receiveBuffer.push(args) } }; Socket.prototype.ack = function (id) { var self = this; var sent = false; return function () { if (sent) return; sent = true; var args = toArray(arguments); debug("sending ack %j", args); var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK; self.packet({ type: type, id: id, data: args }) } }; Socket.prototype.onack = function (packet) { debug("calling ack %s with %j", packet.id, packet.data); var fn = this.acks[packet.id]; fn.apply(this, packet.data); delete this.acks[packet.id] }; Socket.prototype.onconnect = function () { this.connected = true; this.disconnected = false; this.emit("connect"); this.emitBuffered() }; Socket.prototype.emitBuffered = function () { var i; for (i = 0; i < this.receiveBuffer.length; i++) { emit.apply(this, this.receiveBuffer[i]) } this.receiveBuffer = []; for (i = 0; i < this.sendBuffer.length; i++) { this.packet(this.sendBuffer[i]) } this.sendBuffer = [] }; Socket.prototype.ondisconnect = function () { debug("server disconnect (%s)", this.nsp); this.destroy(); this.onclose("io server disconnect") }; Socket.prototype.destroy = function () { if (this.subs) { for (var i = 0; i < this.subs.length; i++) { this.subs[i].destroy() } this.subs = null } this.io.destroy(this) }; Socket.prototype.close = Socket.prototype.disconnect = function () { if (this.connected) { debug("performing disconnect (%s)", this.nsp); this.packet({ type: parser.DISCONNECT }) } this.destroy(); if (this.connected) { this.onclose("io client disconnect") } return this } }, { "./on": 4, "component-bind": 8, "component-emitter": 9, debug: 10, "has-binary": 38, "socket.io-parser": 46, "to-array": 50 }], 6: [function (_dereq_, module, exports) { (function (global) { var parseuri = _dereq_("parseuri"); var debug = _dereq_("debug")("socket.io-client:url"); module.exports = url; function url(uri, loc) { var obj = uri; var loc = loc || global.location; if (null == uri) uri = loc.protocol + "//" + loc.host; if ("string" == typeof uri) { if ("/" == uri.charAt(0)) { if ("/" == uri.charAt(1)) { uri = loc.protocol + uri } else { uri = loc.hostname + uri } } if (!/^(https?|wss?):\/\//.test(uri)) { debug("protocol-less url %s", uri); if ("undefined" != typeof loc) { uri = loc.protocol + "//" + uri } else { uri = "https://" + uri } } debug("parse %s", uri); obj = parseuri(uri) } if (!obj.port) { if (/^(http|ws)$/.test(obj.protocol)) { obj.port = "80" } else if (/^(http|ws)s$/.test(obj.protocol)) { obj.port = "443" } } obj.path = obj.path || "/"; obj.id = obj.protocol + "://" + obj.host + ":" + obj.port; obj.href = obj.protocol + "://" + obj.host + (loc && loc.port == obj.port ? "" : ":" + obj.port); return obj } }).call(this, typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) }, { debug: 10, parseuri: 44 }], 7: [function (_dereq_, module, exports) { module.exports = Backoff; function Backoff(opts) { opts = opts || {}; this.ms = opts.min || 100; this.max = opts.max || 1e4; this.factor = opts.factor || 2; this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0; this.attempts = 0 } Backoff.prototype.duration = function () { var ms = this.ms * Math.pow(this.factor, this.attempts++); if (this.jitter) { var rand = Math.random(); var deviation = Math.floor(rand * this.jitter * ms); ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation } return Math.min(ms, this.max) | 0 }; Backoff.prototype.reset = function () { this.attempts = 0 }; Backoff.prototype.setMin = function (min) { this.ms = min }; Backoff.prototype.setMax = function (max) { this.max = max }; Backoff.prototype.setJitter = function (jitter) { this.jitter = jitter } }, {}], 8: [function (_dereq_, module, exports) { var slice = [].slice; module.exports = function (obj, fn) { if ("string" == typeof fn) fn = obj[fn]; if ("function" != typeof fn) throw new Error("bind() requires a function"); var args = slice.call(arguments, 2); return function () { return fn.apply(obj, args.concat(slice.call(arguments))) } } }, {}], 9: [function (_dereq_, module, exports) { module.exports = Emitter; function Emitter(obj) { if (obj) return mixin(obj) } function mixin(obj) { for (var key in Emitter.prototype) { obj[key] = Emitter.prototype[key] } return obj } Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) { this._callbacks = this._callbacks || {}; (this._callbacks[event] = this._callbacks[event] || []).push(fn); return this }; Emitter.prototype.once = function (event, fn) { var self = this; this._callbacks = this._callbacks || {}; function on() { self.off(event, on); fn.apply(this, arguments) } on.fn = fn; this.on(event, on); return this }; Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) { this._callbacks = this._callbacks || {}; if (0 == arguments.length) { this._callbacks = {}; return this } var callbacks = this._callbacks[event]; if (!callbacks) return this; if (1 == arguments.length) { delete this._callbacks[event]; return this } var cb; for (var i = 0; i < callbacks.length; i++) { cb = callbacks[i]; if (cb === fn || cb.fn === fn) { callbacks.splice(i, 1); break } } return this }; Emitter.prototype.emit = function (event) { this._callbacks = this._callbacks || {}; var args = [].slice.call(arguments, 1), callbacks = this._callbacks[event]; if (callbacks) { callbacks = callbacks.slice(0); for (var i = 0, len = callbacks.length; i < len; ++i) { callbacks[i].apply(this, args) } } return this }; Emitter.prototype.listeners = function (event) { this._callbacks = this._callbacks || {}; return this._callbacks[event] || [] }; Emitter.prototype.hasListeners = function (event) { return !!this.listeners(event).length } }, {}], 10: [function (_dereq_, module, exports) { module.exports = debug; function debug(name) { if (!debug.enabled(name)) return function () { }; return function (fmt) { fmt = coerce(fmt); var curr = new Date; var ms = curr - (debug[name] || curr); debug[name] = curr; fmt = name + " " + fmt + " +" + debug.humanize(ms); window.console && console.log && Function.prototype.apply.call(console.log, console, arguments) } } debug.names = []; debug.skips = []; debug.enable = function (name) { try { localStorage.debug = name } catch (e) { } var split = (name || "").split(/[\s,]+/), len = split.length; for (var i = 0; i < len; i++) { name = split[i].replace("*", ".*?"); if (name[0] === "-") { debug.skips.push(new RegExp("^" + name.substr(1) + "$")) } else { debug.names.push(new RegExp("^" + name + "$")) } } }; debug.disable = function () { debug.enable("") }; debug.humanize = function (ms) { var sec = 1e3, min = 60 * 1e3, 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" }; 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 } } return false }; function coerce(val) { if (val instanceof Error) return val.stack || val.message; return val } try { if (window.localStorage) debug.enable(localStorage.debug) } catch (e) { } }, {}], 11: [function (_dereq_, module, exports) { module.exports = _dereq_("./lib/") }, { "./lib/": 12 }], 12: [function (_dereq_, module, exports) { module.exports = _dereq_("./socket"); module.exports.parser = _dereq_("engine.io-parser") }, { "./socket": 13, "engine.io-parser": 25 }], 13: [function (_dereq_, module, exports) { (function (global) { var transports = _dereq_("./transports"); var Emitter = _dereq_("component-emitter"); var debug = _dereq_("debug")("engine.io-client:socket"); var index = _dereq_("indexof"); var parser = _dereq_("engine.io-parser"); var parseuri = _dereq_("parseuri"); var parsejson = _dereq_("parsejson"); var parseqs = _dereq_("parseqs"); module.exports = Socket; function noop() { } function Socket(uri, opts) { if (!(this instanceof Socket)) return new Socket(uri, opts); opts = opts || {}; if (uri && "object" == typeof uri) { opts = uri; uri = null } if (uri) { uri = 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 } this.secure = null != opts.secure ? opts.secure : global.location && "https:" == location.protocol; if (opts.host) { var pieces = opts.host.split(":"); opts.hostname = pieces.shift(); if (pieces.length) { opts.port = pieces.pop() } else if (!opts.port) { opts.port = this.secure ? "443" : "80" } } this.agent = opts.agent || false; 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 = parseqs.decode(this.query); this.upgrade = false !== opts.upgrade; this.path = (opts.path || "/engine.io").replace(/\/$/, "") + "/"; this.forceJSONP = !!opts.forceJSONP; this.jsonp = false !== opts.jsonp; this.forceBase64 = !!opts.forceBase64; this.enablesXDR = !!opts.enablesXDR; this.timestampParam = opts.timestampParam || "t"; this.timestampRequests = opts.timestampRequests; this.transports = opts.transports || ["polling", "websocket"]; this.readyState = ""; this.writeBuffer = []; this.callbackBuffer = []; this.policyPort = opts.policyPort || 843; this.rememberUpgrade = opts.rememberUpgrade || false; this.binaryType = null; this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades; this.pfx = opts.pfx || null; this.key = opts.key || null; this.passphrase = opts.passphrase || null; this.cert = opts.cert || null; this.ca = opts.ca || null; this.ciphers = opts.ciphers || null; this.rejectUnauthorized = opts.rejectUnauthorized || null; this.open() } Socket.priorWebsocketSuccess = false; Emitter(Socket.prototype); Socket.protocol = parser.protocol; Socket.Socket = Socket; Socket.Transport = _dereq_("./transport"); Socket.transports = _dereq_("./transports"); Socket.parser = _dereq_("engine.io-parser"); Socket.prototype.createTransport = function (name) { debug('creating transport "%s"', name); var query = clone(this.query); query.EIO = parser.protocol; query.transport = name; if (this.id) query.sid = this.id; var transport = new transports[name]({ agent: this.agent, hostname: this.hostname, port: this.port, secure: this.secure, path: this.path, query: query, forceJSONP: this.forceJSONP, jsonp: this.jsonp, forceBase64: this.forceBase64, enablesXDR: this.enablesXDR, timestampRequests: this.timestampRequests, timestampParam: this.timestampParam, policyPort: this.policyPort, socket: this, pfx: this.pfx, key: this.key, passphrase: this.passphrase, cert: this.cert, ca: this.ca, ciphers: this.ciphers, rejectUnauthorized: this.rejectUnauthorized }); return transport }; function clone(obj) { var o = {}; for (var i in obj) { if (obj.hasOwnProperty(i)) { o[i] = obj[i] } } return o } Socket.prototype.open = function () { var transport; if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf("websocket") != -1) { transport = "websocket" } else if (0 == this.transports.length) { var self = this; setTimeout(function () { self.emit("error", "No transports available") }, 0); return } else { transport = this.transports[0] } this.readyState = "opening"; var transport; try { transport = this.createTransport(transport) } catch (e) { this.transports.shift(); this.open(); return } transport.open(); this.setTransport(transport) }; Socket.prototype.setTransport = function (transport) { debug("setting transport %s", transport.name); var self = this; if (this.transport) { debug("clearing existing transport %s", this.transport.name); this.transport.removeAllListeners() } this.transport = transport; 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") }) }; Socket.prototype.probe = function (name) { debug('probing transport "%s"', name); var transport = this.createTransport(name, { probe: 1 }), failed = false, self = this; Socket.priorWebsocketSuccess = false; function onTransportOpen() { if (self.onlyBinaryUpgrades) { var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary; failed = failed || upgradeLosesBinary } if (failed) return; 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); if (!transport) return; Socket.priorWebsocketSuccess = "websocket" == transport.name; debug('pausing current transport "%s"', self.transport.name); self.transport.pause(function () { if (failed) return; if ("closed" == self.readyState) return; debug("changing transport and sending upgrade packet"); cleanup(); self.setTransport(transport); transport.send([{ type: "upgrade" }]); self.emit("upgrade", transport); 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) } }) } function freezeTransport() { if (failed) return; failed = true; cleanup(); transport.close(); transport = null } function onerror(err) { var error = new Error("probe error: " + err); error.transport = transport.name; freezeTransport(); debug('probe transport "%s" failed because of error: %s', name, err); self.emit("upgradeError", error) } function onTransportClose() { onerror("transport closed") } function onclose() { onerror("socket closed") } function onupgrade(to) { if (transport && to.name != transport.name) { debug('"%s" works - aborting "%s"', to.name, transport.name); freezeTransport() } } function cleanup() { transport.removeListener("open", onTransportOpen); transport.removeListener("error", onerror); transport.removeListener("close", onTransportClose); self.removeListener("close", onclose); self.removeListener("upgrading", onupgrade) } transport.once("open", onTransportOpen); transport.once("error", onerror); transport.once("close", onTransportClose); this.once("close", onclose); this.once("upgrading", onupgrade); transport.open() }; Socket.prototype.onOpen = function () { debug("socket open"); this.readyState = "open"; Socket.priorWebsocketSuccess = "websocket" == this.transport.name; this.emit("open"); this.flush(); 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]) } } }; Socket.prototype.onPacket = function (packet) { if ("opening" == this.readyState || "open" == this.readyState) { debug('socket receive: type "%s", data "%s"', packet.type, packet.data); this.emit("packet", packet); this.emit("heartbeat"); switch (packet.type) { case "open": this.onHandshake(parsejson(packet.data)); break; case "pong": this.setPing(); break; case "error": var err = new Error("server error"); err.code = packet.data; this.emit("error", err); break; case "message": this.emit("data", packet.data); this.emit("message", packet.data); break } } else { debug('packet received with socket readyState "%s"', this.readyState) } }; 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(); if ("closed" == this.readyState) return; this.setPing(); this.removeListener("heartbeat", this.onHeartbeat); this.on("heartbeat", this.onHeartbeat) }; 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) }; 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) }; Socket.prototype.ping = function () { this.sendPacket("ping") }; Socket.prototype.onDrain = function () { for (var i = 0; i < this.prevBufferLen; i++) { if (this.callbackBuffer[i]) { this.callbackBuffer[i]() } } this.writeBuffer.splice(0, this.prevBufferLen); this.callbackBuffer.splice(0, this.prevBufferLen); this.prevBufferLen = 0; if (this.writeBuffer.length == 0) { this.emit("drain") } else { this.flush() } }; 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); this.prevBufferLen = this.writeBuffer.length; this.emit("flush") } }; Socket.prototype.write = Socket.prototype.send = function (msg, fn) { this.sendPacket("message", msg, fn); return this }; Socket.prototype.sendPacket = function (type, data, fn) { if ("closing" == this.readyState || "closed" == this.readyState) { return } var packet = { type: type, data: data }; this.emit("packetCreate", packet); this.writeBuffer.push(packet); this.callbackBuffer.push(fn); this.flush() }; Socket.prototype.close = function () { if ("opening" == this.readyState || "open" == this.readyState) { this.readyState = "closing"; var self = this; function close() { self.onClose("forced close"); debug("socket closing - telling transport to close"); self.transport.close() } function cleanupAndClose() { self.removeListener("upgrade", cleanupAndClose); self.removeListener("upgradeError", cleanupAndClose); close() } function waitForUpgrade() { self.once("upgrade", cleanupAndClose); self.once("upgradeError", cleanupAndClose) } if (this.writeBuffer.length) { this.once("drain", function () { if (this.upgrading) { waitForUpgrade() } else { close() } }) } else if (this.upgrading) { waitForUpgrade() } else { close() } } return this }; Socket.prototype.onError = function (err) { debug("socket error %j", err); Socket.priorWebsocketSuccess = false; this.emit("error", err); this.onClose("transport error", err) }; Socket.prototype.onClose = function (reason, desc) { if ("opening" == this.readyState || "open" == this.readyState || "closing" == this.readyState) { debug('socket close with reason: "%s"', reason); var self = this; clearTimeout(this.pingIntervalTimer); clearTimeout(this.pingTimeoutTimer); setTimeout(function () { self.writeBuffer = []; self.callbackBuffer = []; self.prevBufferLen = 0 }, 0); this.transport.removeAllListeners("close"); this.transport.close(); this.transport.removeAllListeners(); this.readyState = "closed"; this.id = null; this.emit("close", reason, desc) } }; Socket.prototype.filterUpgrades = function (upgrades) { var filteredUpgrades = []; for (var i = 0, j = upgrades.length; i < j; i++) { if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]) } return filteredUpgrades } }).call(this, typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) }, { "./transport": 14, "./transports": 15, "component-emitter": 9, debug: 22, "engine.io-parser": 25, indexof: 42, parsejson: 34, parseqs: 35, parseuri: 36 }], 14: [function (_dereq_, module, exports) { var parser = _dereq_("engine.io-parser"); var Emitter = _dereq_("component-emitter"); module.exports = Transport; function Transport(opts) { this.path = opts.path; this.hostname = opts.hostname; this.port = opts.port; this.secure = opts.secure; this.query = opts.query; this.timestampParam = opts.timestampParam; this.timestampRequests = opts.timestampRequests; this.readyState = ""; this.agent = opts.agent || false; this.socket = opts.socket; this.enablesXDR = opts.enablesXDR; this.pfx = opts.pfx; this.key = opts.key; this.passphrase = opts.passphrase; this.cert = opts.cert; this.ca = opts.ca; this.ciphers = opts.ciphers; this.rejectUnauthorized = opts.rejectUnauthorized } Emitter(Transport.prototype); Transport.timestamps = 0; Transport.prototype.onError = function (msg, desc) { var err = new Error(msg); err.type = "TransportError"; err.description = desc; this.emit("error", err); return this }; Transport.prototype.open = function () { if ("closed" == this.readyState || "" == this.readyState) { this.readyState = "opening"; this.doOpen() } return this }; Transport.prototype.close = function () { if ("opening" == this.readyState || "open" == this.readyState) { this.doClose(); this.onClose() } return this }; Transport.prototype.send = function (packets) { if ("open" == this.readyState) { this.write(packets) } else { throw new Error("Transport not open") } }; Transport.prototype.onOpen = function () { this.readyState = "open"; this.writable = true; this.emit("open") }; Transport.prototype.onData = function (data) { var packet = parser.decodePacket(data, this.socket.binaryType); this.onPacket(packet) }; Transport.prototype.onPacket = function (packet) { this.emit("packet", packet) }; Transport.prototype.onClose = function () { this.readyState = "closed"; this.emit("close") } }, { "component-emitter": 9, "engine.io-parser": 25 }], 15: [function (_dereq_, module, exports) { (function (global) { var XMLHttpRequest = _dereq_("xmlhttprequest"); var XHR = _dereq_("./polling-xhr"); var JSONP = _dereq_("./polling-jsonp"); var websocket = _dereq_("./websocket"); exports.polling = polling; exports.websocket = websocket; function polling(opts) { var xhr; var xd = false; var xs = false; var jsonp = false !== opts.jsonp; if (global.location) { var isSSL = "https:" == location.protocol; var port = location.port; if (!port) { port = isSSL ? 443 : 80 } xd = opts.hostname != location.hostname || port != opts.port; xs = opts.secure != isSSL } opts.xdomain = xd; opts.xscheme = xs; xhr = new XMLHttpRequest(opts); if ("open" in xhr && !opts.forceJSONP) { return new XHR(opts) } else { if (!jsonp) throw new Error("JSONP disabled"); return new JSONP(opts) } } }).call(this, typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) }, { "./polling-jsonp": 16, "./polling-xhr": 17, "./websocket": 19, xmlhttprequest: 20 }], 16: [function (_dereq_, module, exports) { + (function (global) { + var Polling = _dereq_("./polling"); var inherit = _dereq_("component-inherit"); module.exports = JSONPPolling; var rNewline = /\n/g; var rEscapedNewline = /\\n/g; var callbacks; var index = 0; function empty() { } function JSONPPolling(opts) { + Polling.call(this, opts); + this.query = this.query || {}; if (!callbacks) { if (!global.___eio) global.___eio = []; callbacks = global.___eio } this.index = callbacks.length; var self = this; callbacks.push(function (msg) { self.onData(msg) }); this.query.j = this.index; if (global.document && global.addEventListener) { global.addEventListener("beforeunload", function () { if (self.script) self.script.onerror = empty }, false) } + } inherit(JSONPPolling, Polling); JSONPPolling.prototype.supportsBinary = false; JSONPPolling.prototype.doClose = function () { if (this.script) { this.script.parentNode.removeChild(this.script); this.script = null } if (this.form) { this.form.parentNode.removeChild(this.form); this.form = null; this.iframe = null } Polling.prototype.doClose.call(this) }; JSONPPolling.prototype.doPoll = function () { var self = this; var script = document.createElement("script"); if (this.script) { this.script.parentNode.removeChild(this.script); this.script = null } script.async = true; script.src = this.uri(); script.onerror = function (e) { self.onError("jsonp poll error", e) }; var insertAt = document.getElementsByTagName("script")[0]; insertAt.parentNode.insertBefore(script, insertAt); this.script = script; var isUAgecko = "undefined" != typeof navigator && /gecko/i.test(navigator.userAgent); if (isUAgecko) { setTimeout(function () { var iframe = document.createElement("iframe"); document.body.appendChild(iframe); document.body.removeChild(iframe) }, 100) } }; JSONPPolling.prototype.doWrite = function (data, fn) { var self = this; if (!this.form) { var form = document.createElement("form"); var area = document.createElement("textarea"); var id = this.iframeId = "eio_iframe_" + this.index; var iframe; form.className = "socketio"; form.style.position = "absolute"; form.style.top = "-1000px"; form.style.left = "-1000px"; form.target = id; form.method = "POST"; form.setAttribute("accept-charset", "utf-8"); area.name = "d"; form.appendChild(area); document.body.appendChild(form); this.form = form; this.area = area } this.form.action = this.uri(); function complete() { initIframe(); fn() } function initIframe() { if (self.iframe) { try { self.form.removeChild(self.iframe) } catch (e) { self.onError("jsonp polling iframe removal error", e) } } try { var html = '