This example presents field data from sensor BME280 connecting to cloud, mbed Device Connector.
Please read details at the link. https://github.com/soramame21/connector-api-python-quickstart_4BME280
static/js/socket.io.js@0:a9bcda5b678a, 2017-04-26 (annotated)
- Committer:
- edamame22
- Date:
- Wed Apr 26 03:13:23 2017 +0000
- Revision:
- 0:a9bcda5b678a
Initial commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
edamame22 | 0:a9bcda5b678a | 1 | !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){ |
edamame22 | 0:a9bcda5b678a | 2 | |
edamame22 | 0:a9bcda5b678a | 3 | module.exports = _dereq_('./lib/'); |
edamame22 | 0:a9bcda5b678a | 4 | |
edamame22 | 0:a9bcda5b678a | 5 | },{"./lib/":2}],2:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 6 | |
edamame22 | 0:a9bcda5b678a | 7 | /** |
edamame22 | 0:a9bcda5b678a | 8 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 9 | */ |
edamame22 | 0:a9bcda5b678a | 10 | |
edamame22 | 0:a9bcda5b678a | 11 | var url = _dereq_('./url'); |
edamame22 | 0:a9bcda5b678a | 12 | var parser = _dereq_('socket.io-parser'); |
edamame22 | 0:a9bcda5b678a | 13 | var Manager = _dereq_('./manager'); |
edamame22 | 0:a9bcda5b678a | 14 | var debug = _dereq_('debug')('socket.io-client'); |
edamame22 | 0:a9bcda5b678a | 15 | |
edamame22 | 0:a9bcda5b678a | 16 | /** |
edamame22 | 0:a9bcda5b678a | 17 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 18 | */ |
edamame22 | 0:a9bcda5b678a | 19 | |
edamame22 | 0:a9bcda5b678a | 20 | module.exports = exports = lookup; |
edamame22 | 0:a9bcda5b678a | 21 | |
edamame22 | 0:a9bcda5b678a | 22 | /** |
edamame22 | 0:a9bcda5b678a | 23 | * Managers cache. |
edamame22 | 0:a9bcda5b678a | 24 | */ |
edamame22 | 0:a9bcda5b678a | 25 | |
edamame22 | 0:a9bcda5b678a | 26 | var cache = exports.managers = {}; |
edamame22 | 0:a9bcda5b678a | 27 | |
edamame22 | 0:a9bcda5b678a | 28 | /** |
edamame22 | 0:a9bcda5b678a | 29 | * Looks up an existing `Manager` for multiplexing. |
edamame22 | 0:a9bcda5b678a | 30 | * If the user summons: |
edamame22 | 0:a9bcda5b678a | 31 | * |
edamame22 | 0:a9bcda5b678a | 32 | * `io('http://localhost/a');` |
edamame22 | 0:a9bcda5b678a | 33 | * `io('http://localhost/b');` |
edamame22 | 0:a9bcda5b678a | 34 | * |
edamame22 | 0:a9bcda5b678a | 35 | * We reuse the existing instance based on same scheme/port/host, |
edamame22 | 0:a9bcda5b678a | 36 | * and we initialize sockets for each namespace. |
edamame22 | 0:a9bcda5b678a | 37 | * |
edamame22 | 0:a9bcda5b678a | 38 | * @api public |
edamame22 | 0:a9bcda5b678a | 39 | */ |
edamame22 | 0:a9bcda5b678a | 40 | |
edamame22 | 0:a9bcda5b678a | 41 | function lookup(uri, opts) { |
edamame22 | 0:a9bcda5b678a | 42 | if (typeof uri == 'object') { |
edamame22 | 0:a9bcda5b678a | 43 | opts = uri; |
edamame22 | 0:a9bcda5b678a | 44 | uri = undefined; |
edamame22 | 0:a9bcda5b678a | 45 | } |
edamame22 | 0:a9bcda5b678a | 46 | |
edamame22 | 0:a9bcda5b678a | 47 | opts = opts || {}; |
edamame22 | 0:a9bcda5b678a | 48 | |
edamame22 | 0:a9bcda5b678a | 49 | var parsed = url(uri); |
edamame22 | 0:a9bcda5b678a | 50 | var source = parsed.source; |
edamame22 | 0:a9bcda5b678a | 51 | var id = parsed.id; |
edamame22 | 0:a9bcda5b678a | 52 | var path = parsed.path; |
edamame22 | 0:a9bcda5b678a | 53 | var sameNamespace = (cache[id] && cache[id].nsps[path] && |
edamame22 | 0:a9bcda5b678a | 54 | path == cache[id].nsps[path].nsp); |
edamame22 | 0:a9bcda5b678a | 55 | var newConnection = opts.forceNew || opts['force new connection'] || |
edamame22 | 0:a9bcda5b678a | 56 | false === opts.multiplex || sameNamespace; |
edamame22 | 0:a9bcda5b678a | 57 | |
edamame22 | 0:a9bcda5b678a | 58 | var io; |
edamame22 | 0:a9bcda5b678a | 59 | |
edamame22 | 0:a9bcda5b678a | 60 | if (newConnection) { |
edamame22 | 0:a9bcda5b678a | 61 | debug('ignoring socket cache for %s', source); |
edamame22 | 0:a9bcda5b678a | 62 | io = Manager(source, opts); |
edamame22 | 0:a9bcda5b678a | 63 | } else { |
edamame22 | 0:a9bcda5b678a | 64 | if (!cache[id]) { |
edamame22 | 0:a9bcda5b678a | 65 | debug('new io instance for %s', source); |
edamame22 | 0:a9bcda5b678a | 66 | cache[id] = Manager(source, opts); |
edamame22 | 0:a9bcda5b678a | 67 | } |
edamame22 | 0:a9bcda5b678a | 68 | io = cache[id]; |
edamame22 | 0:a9bcda5b678a | 69 | } |
edamame22 | 0:a9bcda5b678a | 70 | |
edamame22 | 0:a9bcda5b678a | 71 | return io.socket(parsed.path); |
edamame22 | 0:a9bcda5b678a | 72 | } |
edamame22 | 0:a9bcda5b678a | 73 | |
edamame22 | 0:a9bcda5b678a | 74 | /** |
edamame22 | 0:a9bcda5b678a | 75 | * Protocol version. |
edamame22 | 0:a9bcda5b678a | 76 | * |
edamame22 | 0:a9bcda5b678a | 77 | * @api public |
edamame22 | 0:a9bcda5b678a | 78 | */ |
edamame22 | 0:a9bcda5b678a | 79 | |
edamame22 | 0:a9bcda5b678a | 80 | exports.protocol = parser.protocol; |
edamame22 | 0:a9bcda5b678a | 81 | |
edamame22 | 0:a9bcda5b678a | 82 | /** |
edamame22 | 0:a9bcda5b678a | 83 | * `connect`. |
edamame22 | 0:a9bcda5b678a | 84 | * |
edamame22 | 0:a9bcda5b678a | 85 | * @param {String} uri |
edamame22 | 0:a9bcda5b678a | 86 | * @api public |
edamame22 | 0:a9bcda5b678a | 87 | */ |
edamame22 | 0:a9bcda5b678a | 88 | |
edamame22 | 0:a9bcda5b678a | 89 | exports.connect = lookup; |
edamame22 | 0:a9bcda5b678a | 90 | |
edamame22 | 0:a9bcda5b678a | 91 | /** |
edamame22 | 0:a9bcda5b678a | 92 | * Expose constructors for standalone build. |
edamame22 | 0:a9bcda5b678a | 93 | * |
edamame22 | 0:a9bcda5b678a | 94 | * @api public |
edamame22 | 0:a9bcda5b678a | 95 | */ |
edamame22 | 0:a9bcda5b678a | 96 | |
edamame22 | 0:a9bcda5b678a | 97 | exports.Manager = _dereq_('./manager'); |
edamame22 | 0:a9bcda5b678a | 98 | exports.Socket = _dereq_('./socket'); |
edamame22 | 0:a9bcda5b678a | 99 | |
edamame22 | 0:a9bcda5b678a | 100 | },{"./manager":3,"./socket":5,"./url":6,"debug":10,"socket.io-parser":46}],3:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 101 | |
edamame22 | 0:a9bcda5b678a | 102 | /** |
edamame22 | 0:a9bcda5b678a | 103 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 104 | */ |
edamame22 | 0:a9bcda5b678a | 105 | |
edamame22 | 0:a9bcda5b678a | 106 | var url = _dereq_('./url'); |
edamame22 | 0:a9bcda5b678a | 107 | var eio = _dereq_('engine.io-client'); |
edamame22 | 0:a9bcda5b678a | 108 | var Socket = _dereq_('./socket'); |
edamame22 | 0:a9bcda5b678a | 109 | var Emitter = _dereq_('component-emitter'); |
edamame22 | 0:a9bcda5b678a | 110 | var parser = _dereq_('socket.io-parser'); |
edamame22 | 0:a9bcda5b678a | 111 | var on = _dereq_('./on'); |
edamame22 | 0:a9bcda5b678a | 112 | var bind = _dereq_('component-bind'); |
edamame22 | 0:a9bcda5b678a | 113 | var object = _dereq_('object-component'); |
edamame22 | 0:a9bcda5b678a | 114 | var debug = _dereq_('debug')('socket.io-client:manager'); |
edamame22 | 0:a9bcda5b678a | 115 | var indexOf = _dereq_('indexof'); |
edamame22 | 0:a9bcda5b678a | 116 | var Backoff = _dereq_('backo2'); |
edamame22 | 0:a9bcda5b678a | 117 | |
edamame22 | 0:a9bcda5b678a | 118 | /** |
edamame22 | 0:a9bcda5b678a | 119 | * Module exports |
edamame22 | 0:a9bcda5b678a | 120 | */ |
edamame22 | 0:a9bcda5b678a | 121 | |
edamame22 | 0:a9bcda5b678a | 122 | module.exports = Manager; |
edamame22 | 0:a9bcda5b678a | 123 | |
edamame22 | 0:a9bcda5b678a | 124 | /** |
edamame22 | 0:a9bcda5b678a | 125 | * `Manager` constructor. |
edamame22 | 0:a9bcda5b678a | 126 | * |
edamame22 | 0:a9bcda5b678a | 127 | * @param {String} engine instance or engine uri/opts |
edamame22 | 0:a9bcda5b678a | 128 | * @param {Object} options |
edamame22 | 0:a9bcda5b678a | 129 | * @api public |
edamame22 | 0:a9bcda5b678a | 130 | */ |
edamame22 | 0:a9bcda5b678a | 131 | |
edamame22 | 0:a9bcda5b678a | 132 | function Manager(uri, opts){ |
edamame22 | 0:a9bcda5b678a | 133 | if (!(this instanceof Manager)) return new Manager(uri, opts); |
edamame22 | 0:a9bcda5b678a | 134 | if (uri && ('object' == typeof uri)) { |
edamame22 | 0:a9bcda5b678a | 135 | opts = uri; |
edamame22 | 0:a9bcda5b678a | 136 | uri = undefined; |
edamame22 | 0:a9bcda5b678a | 137 | } |
edamame22 | 0:a9bcda5b678a | 138 | opts = opts || {}; |
edamame22 | 0:a9bcda5b678a | 139 | |
edamame22 | 0:a9bcda5b678a | 140 | opts.path = opts.path || '/socket.io'; |
edamame22 | 0:a9bcda5b678a | 141 | this.nsps = {}; |
edamame22 | 0:a9bcda5b678a | 142 | this.subs = []; |
edamame22 | 0:a9bcda5b678a | 143 | this.opts = opts; |
edamame22 | 0:a9bcda5b678a | 144 | this.reconnection(opts.reconnection !== false); |
edamame22 | 0:a9bcda5b678a | 145 | this.reconnectionAttempts(opts.reconnectionAttempts || Infinity); |
edamame22 | 0:a9bcda5b678a | 146 | this.reconnectionDelay(opts.reconnectionDelay || 1000); |
edamame22 | 0:a9bcda5b678a | 147 | this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000); |
edamame22 | 0:a9bcda5b678a | 148 | this.randomizationFactor(opts.randomizationFactor || 0.5); |
edamame22 | 0:a9bcda5b678a | 149 | this.backoff = new Backoff({ |
edamame22 | 0:a9bcda5b678a | 150 | min: this.reconnectionDelay(), |
edamame22 | 0:a9bcda5b678a | 151 | max: this.reconnectionDelayMax(), |
edamame22 | 0:a9bcda5b678a | 152 | jitter: this.randomizationFactor() |
edamame22 | 0:a9bcda5b678a | 153 | }); |
edamame22 | 0:a9bcda5b678a | 154 | this.timeout(null == opts.timeout ? 20000 : opts.timeout); |
edamame22 | 0:a9bcda5b678a | 155 | this.readyState = 'closed'; |
edamame22 | 0:a9bcda5b678a | 156 | this.uri = uri; |
edamame22 | 0:a9bcda5b678a | 157 | this.connected = []; |
edamame22 | 0:a9bcda5b678a | 158 | this.encoding = false; |
edamame22 | 0:a9bcda5b678a | 159 | this.packetBuffer = []; |
edamame22 | 0:a9bcda5b678a | 160 | this.encoder = new parser.Encoder(); |
edamame22 | 0:a9bcda5b678a | 161 | this.decoder = new parser.Decoder(); |
edamame22 | 0:a9bcda5b678a | 162 | this.autoConnect = opts.autoConnect !== false; |
edamame22 | 0:a9bcda5b678a | 163 | if (this.autoConnect) this.open(); |
edamame22 | 0:a9bcda5b678a | 164 | } |
edamame22 | 0:a9bcda5b678a | 165 | |
edamame22 | 0:a9bcda5b678a | 166 | /** |
edamame22 | 0:a9bcda5b678a | 167 | * Propagate given event to sockets and emit on `this` |
edamame22 | 0:a9bcda5b678a | 168 | * |
edamame22 | 0:a9bcda5b678a | 169 | * @api private |
edamame22 | 0:a9bcda5b678a | 170 | */ |
edamame22 | 0:a9bcda5b678a | 171 | |
edamame22 | 0:a9bcda5b678a | 172 | Manager.prototype.emitAll = function() { |
edamame22 | 0:a9bcda5b678a | 173 | this.emit.apply(this, arguments); |
edamame22 | 0:a9bcda5b678a | 174 | for (var nsp in this.nsps) { |
edamame22 | 0:a9bcda5b678a | 175 | this.nsps[nsp].emit.apply(this.nsps[nsp], arguments); |
edamame22 | 0:a9bcda5b678a | 176 | } |
edamame22 | 0:a9bcda5b678a | 177 | }; |
edamame22 | 0:a9bcda5b678a | 178 | |
edamame22 | 0:a9bcda5b678a | 179 | /** |
edamame22 | 0:a9bcda5b678a | 180 | * Update `socket.id` of all sockets |
edamame22 | 0:a9bcda5b678a | 181 | * |
edamame22 | 0:a9bcda5b678a | 182 | * @api private |
edamame22 | 0:a9bcda5b678a | 183 | */ |
edamame22 | 0:a9bcda5b678a | 184 | |
edamame22 | 0:a9bcda5b678a | 185 | Manager.prototype.updateSocketIds = function(){ |
edamame22 | 0:a9bcda5b678a | 186 | for (var nsp in this.nsps) { |
edamame22 | 0:a9bcda5b678a | 187 | this.nsps[nsp].id = this.engine.id; |
edamame22 | 0:a9bcda5b678a | 188 | } |
edamame22 | 0:a9bcda5b678a | 189 | }; |
edamame22 | 0:a9bcda5b678a | 190 | |
edamame22 | 0:a9bcda5b678a | 191 | /** |
edamame22 | 0:a9bcda5b678a | 192 | * Mix in `Emitter`. |
edamame22 | 0:a9bcda5b678a | 193 | */ |
edamame22 | 0:a9bcda5b678a | 194 | |
edamame22 | 0:a9bcda5b678a | 195 | Emitter(Manager.prototype); |
edamame22 | 0:a9bcda5b678a | 196 | |
edamame22 | 0:a9bcda5b678a | 197 | /** |
edamame22 | 0:a9bcda5b678a | 198 | * Sets the `reconnection` config. |
edamame22 | 0:a9bcda5b678a | 199 | * |
edamame22 | 0:a9bcda5b678a | 200 | * @param {Boolean} true/false if it should automatically reconnect |
edamame22 | 0:a9bcda5b678a | 201 | * @return {Manager} self or value |
edamame22 | 0:a9bcda5b678a | 202 | * @api public |
edamame22 | 0:a9bcda5b678a | 203 | */ |
edamame22 | 0:a9bcda5b678a | 204 | |
edamame22 | 0:a9bcda5b678a | 205 | Manager.prototype.reconnection = function(v){ |
edamame22 | 0:a9bcda5b678a | 206 | if (!arguments.length) return this._reconnection; |
edamame22 | 0:a9bcda5b678a | 207 | this._reconnection = !!v; |
edamame22 | 0:a9bcda5b678a | 208 | return this; |
edamame22 | 0:a9bcda5b678a | 209 | }; |
edamame22 | 0:a9bcda5b678a | 210 | |
edamame22 | 0:a9bcda5b678a | 211 | /** |
edamame22 | 0:a9bcda5b678a | 212 | * Sets the reconnection attempts config. |
edamame22 | 0:a9bcda5b678a | 213 | * |
edamame22 | 0:a9bcda5b678a | 214 | * @param {Number} max reconnection attempts before giving up |
edamame22 | 0:a9bcda5b678a | 215 | * @return {Manager} self or value |
edamame22 | 0:a9bcda5b678a | 216 | * @api public |
edamame22 | 0:a9bcda5b678a | 217 | */ |
edamame22 | 0:a9bcda5b678a | 218 | |
edamame22 | 0:a9bcda5b678a | 219 | Manager.prototype.reconnectionAttempts = function(v){ |
edamame22 | 0:a9bcda5b678a | 220 | if (!arguments.length) return this._reconnectionAttempts; |
edamame22 | 0:a9bcda5b678a | 221 | this._reconnectionAttempts = v; |
edamame22 | 0:a9bcda5b678a | 222 | return this; |
edamame22 | 0:a9bcda5b678a | 223 | }; |
edamame22 | 0:a9bcda5b678a | 224 | |
edamame22 | 0:a9bcda5b678a | 225 | /** |
edamame22 | 0:a9bcda5b678a | 226 | * Sets the delay between reconnections. |
edamame22 | 0:a9bcda5b678a | 227 | * |
edamame22 | 0:a9bcda5b678a | 228 | * @param {Number} delay |
edamame22 | 0:a9bcda5b678a | 229 | * @return {Manager} self or value |
edamame22 | 0:a9bcda5b678a | 230 | * @api public |
edamame22 | 0:a9bcda5b678a | 231 | */ |
edamame22 | 0:a9bcda5b678a | 232 | |
edamame22 | 0:a9bcda5b678a | 233 | Manager.prototype.reconnectionDelay = function(v){ |
edamame22 | 0:a9bcda5b678a | 234 | if (!arguments.length) return this._reconnectionDelay; |
edamame22 | 0:a9bcda5b678a | 235 | this._reconnectionDelay = v; |
edamame22 | 0:a9bcda5b678a | 236 | this.backoff && this.backoff.setMin(v); |
edamame22 | 0:a9bcda5b678a | 237 | return this; |
edamame22 | 0:a9bcda5b678a | 238 | }; |
edamame22 | 0:a9bcda5b678a | 239 | |
edamame22 | 0:a9bcda5b678a | 240 | Manager.prototype.randomizationFactor = function(v){ |
edamame22 | 0:a9bcda5b678a | 241 | if (!arguments.length) return this._randomizationFactor; |
edamame22 | 0:a9bcda5b678a | 242 | this._randomizationFactor = v; |
edamame22 | 0:a9bcda5b678a | 243 | this.backoff && this.backoff.setJitter(v); |
edamame22 | 0:a9bcda5b678a | 244 | return this; |
edamame22 | 0:a9bcda5b678a | 245 | }; |
edamame22 | 0:a9bcda5b678a | 246 | |
edamame22 | 0:a9bcda5b678a | 247 | /** |
edamame22 | 0:a9bcda5b678a | 248 | * Sets the maximum delay between reconnections. |
edamame22 | 0:a9bcda5b678a | 249 | * |
edamame22 | 0:a9bcda5b678a | 250 | * @param {Number} delay |
edamame22 | 0:a9bcda5b678a | 251 | * @return {Manager} self or value |
edamame22 | 0:a9bcda5b678a | 252 | * @api public |
edamame22 | 0:a9bcda5b678a | 253 | */ |
edamame22 | 0:a9bcda5b678a | 254 | |
edamame22 | 0:a9bcda5b678a | 255 | Manager.prototype.reconnectionDelayMax = function(v){ |
edamame22 | 0:a9bcda5b678a | 256 | if (!arguments.length) return this._reconnectionDelayMax; |
edamame22 | 0:a9bcda5b678a | 257 | this._reconnectionDelayMax = v; |
edamame22 | 0:a9bcda5b678a | 258 | this.backoff && this.backoff.setMax(v); |
edamame22 | 0:a9bcda5b678a | 259 | return this; |
edamame22 | 0:a9bcda5b678a | 260 | }; |
edamame22 | 0:a9bcda5b678a | 261 | |
edamame22 | 0:a9bcda5b678a | 262 | /** |
edamame22 | 0:a9bcda5b678a | 263 | * Sets the connection timeout. `false` to disable |
edamame22 | 0:a9bcda5b678a | 264 | * |
edamame22 | 0:a9bcda5b678a | 265 | * @return {Manager} self or value |
edamame22 | 0:a9bcda5b678a | 266 | * @api public |
edamame22 | 0:a9bcda5b678a | 267 | */ |
edamame22 | 0:a9bcda5b678a | 268 | |
edamame22 | 0:a9bcda5b678a | 269 | Manager.prototype.timeout = function(v){ |
edamame22 | 0:a9bcda5b678a | 270 | if (!arguments.length) return this._timeout; |
edamame22 | 0:a9bcda5b678a | 271 | this._timeout = v; |
edamame22 | 0:a9bcda5b678a | 272 | return this; |
edamame22 | 0:a9bcda5b678a | 273 | }; |
edamame22 | 0:a9bcda5b678a | 274 | |
edamame22 | 0:a9bcda5b678a | 275 | /** |
edamame22 | 0:a9bcda5b678a | 276 | * Starts trying to reconnect if reconnection is enabled and we have not |
edamame22 | 0:a9bcda5b678a | 277 | * started reconnecting yet |
edamame22 | 0:a9bcda5b678a | 278 | * |
edamame22 | 0:a9bcda5b678a | 279 | * @api private |
edamame22 | 0:a9bcda5b678a | 280 | */ |
edamame22 | 0:a9bcda5b678a | 281 | |
edamame22 | 0:a9bcda5b678a | 282 | Manager.prototype.maybeReconnectOnOpen = function() { |
edamame22 | 0:a9bcda5b678a | 283 | // Only try to reconnect if it's the first time we're connecting |
edamame22 | 0:a9bcda5b678a | 284 | if (!this.reconnecting && this._reconnection && this.backoff.attempts === 0) { |
edamame22 | 0:a9bcda5b678a | 285 | // keeps reconnection from firing twice for the same reconnection loop |
edamame22 | 0:a9bcda5b678a | 286 | this.reconnect(); |
edamame22 | 0:a9bcda5b678a | 287 | } |
edamame22 | 0:a9bcda5b678a | 288 | }; |
edamame22 | 0:a9bcda5b678a | 289 | |
edamame22 | 0:a9bcda5b678a | 290 | |
edamame22 | 0:a9bcda5b678a | 291 | /** |
edamame22 | 0:a9bcda5b678a | 292 | * Sets the current transport `socket`. |
edamame22 | 0:a9bcda5b678a | 293 | * |
edamame22 | 0:a9bcda5b678a | 294 | * @param {Function} optional, callback |
edamame22 | 0:a9bcda5b678a | 295 | * @return {Manager} self |
edamame22 | 0:a9bcda5b678a | 296 | * @api public |
edamame22 | 0:a9bcda5b678a | 297 | */ |
edamame22 | 0:a9bcda5b678a | 298 | |
edamame22 | 0:a9bcda5b678a | 299 | Manager.prototype.open = |
edamame22 | 0:a9bcda5b678a | 300 | Manager.prototype.connect = function(fn){ |
edamame22 | 0:a9bcda5b678a | 301 | debug('readyState %s', this.readyState); |
edamame22 | 0:a9bcda5b678a | 302 | if (~this.readyState.indexOf('open')) return this; |
edamame22 | 0:a9bcda5b678a | 303 | |
edamame22 | 0:a9bcda5b678a | 304 | debug('opening %s', this.uri); |
edamame22 | 0:a9bcda5b678a | 305 | this.engine = eio(this.uri, this.opts); |
edamame22 | 0:a9bcda5b678a | 306 | var socket = this.engine; |
edamame22 | 0:a9bcda5b678a | 307 | var self = this; |
edamame22 | 0:a9bcda5b678a | 308 | this.readyState = 'opening'; |
edamame22 | 0:a9bcda5b678a | 309 | this.skipReconnect = false; |
edamame22 | 0:a9bcda5b678a | 310 | |
edamame22 | 0:a9bcda5b678a | 311 | // emit `open` |
edamame22 | 0:a9bcda5b678a | 312 | var openSub = on(socket, 'open', function() { |
edamame22 | 0:a9bcda5b678a | 313 | self.onopen(); |
edamame22 | 0:a9bcda5b678a | 314 | fn && fn(); |
edamame22 | 0:a9bcda5b678a | 315 | }); |
edamame22 | 0:a9bcda5b678a | 316 | |
edamame22 | 0:a9bcda5b678a | 317 | // emit `connect_error` |
edamame22 | 0:a9bcda5b678a | 318 | var errorSub = on(socket, 'error', function(data){ |
edamame22 | 0:a9bcda5b678a | 319 | debug('connect_error'); |
edamame22 | 0:a9bcda5b678a | 320 | self.cleanup(); |
edamame22 | 0:a9bcda5b678a | 321 | self.readyState = 'closed'; |
edamame22 | 0:a9bcda5b678a | 322 | self.emitAll('connect_error', data); |
edamame22 | 0:a9bcda5b678a | 323 | if (fn) { |
edamame22 | 0:a9bcda5b678a | 324 | var err = new Error('Connection error'); |
edamame22 | 0:a9bcda5b678a | 325 | err.data = data; |
edamame22 | 0:a9bcda5b678a | 326 | fn(err); |
edamame22 | 0:a9bcda5b678a | 327 | } else { |
edamame22 | 0:a9bcda5b678a | 328 | // Only do this if there is no fn to handle the error |
edamame22 | 0:a9bcda5b678a | 329 | self.maybeReconnectOnOpen(); |
edamame22 | 0:a9bcda5b678a | 330 | } |
edamame22 | 0:a9bcda5b678a | 331 | }); |
edamame22 | 0:a9bcda5b678a | 332 | |
edamame22 | 0:a9bcda5b678a | 333 | // emit `connect_timeout` |
edamame22 | 0:a9bcda5b678a | 334 | if (false !== this._timeout) { |
edamame22 | 0:a9bcda5b678a | 335 | var timeout = this._timeout; |
edamame22 | 0:a9bcda5b678a | 336 | debug('connect attempt will timeout after %d', timeout); |
edamame22 | 0:a9bcda5b678a | 337 | |
edamame22 | 0:a9bcda5b678a | 338 | // set timer |
edamame22 | 0:a9bcda5b678a | 339 | var timer = setTimeout(function(){ |
edamame22 | 0:a9bcda5b678a | 340 | debug('connect attempt timed out after %d', timeout); |
edamame22 | 0:a9bcda5b678a | 341 | openSub.destroy(); |
edamame22 | 0:a9bcda5b678a | 342 | socket.close(); |
edamame22 | 0:a9bcda5b678a | 343 | socket.emit('error', 'timeout'); |
edamame22 | 0:a9bcda5b678a | 344 | self.emitAll('connect_timeout', timeout); |
edamame22 | 0:a9bcda5b678a | 345 | }, timeout); |
edamame22 | 0:a9bcda5b678a | 346 | |
edamame22 | 0:a9bcda5b678a | 347 | this.subs.push({ |
edamame22 | 0:a9bcda5b678a | 348 | destroy: function(){ |
edamame22 | 0:a9bcda5b678a | 349 | clearTimeout(timer); |
edamame22 | 0:a9bcda5b678a | 350 | } |
edamame22 | 0:a9bcda5b678a | 351 | }); |
edamame22 | 0:a9bcda5b678a | 352 | } |
edamame22 | 0:a9bcda5b678a | 353 | |
edamame22 | 0:a9bcda5b678a | 354 | this.subs.push(openSub); |
edamame22 | 0:a9bcda5b678a | 355 | this.subs.push(errorSub); |
edamame22 | 0:a9bcda5b678a | 356 | |
edamame22 | 0:a9bcda5b678a | 357 | return this; |
edamame22 | 0:a9bcda5b678a | 358 | }; |
edamame22 | 0:a9bcda5b678a | 359 | |
edamame22 | 0:a9bcda5b678a | 360 | /** |
edamame22 | 0:a9bcda5b678a | 361 | * Called upon transport open. |
edamame22 | 0:a9bcda5b678a | 362 | * |
edamame22 | 0:a9bcda5b678a | 363 | * @api private |
edamame22 | 0:a9bcda5b678a | 364 | */ |
edamame22 | 0:a9bcda5b678a | 365 | |
edamame22 | 0:a9bcda5b678a | 366 | Manager.prototype.onopen = function(){ |
edamame22 | 0:a9bcda5b678a | 367 | debug('open'); |
edamame22 | 0:a9bcda5b678a | 368 | |
edamame22 | 0:a9bcda5b678a | 369 | // clear old subs |
edamame22 | 0:a9bcda5b678a | 370 | this.cleanup(); |
edamame22 | 0:a9bcda5b678a | 371 | |
edamame22 | 0:a9bcda5b678a | 372 | // mark as open |
edamame22 | 0:a9bcda5b678a | 373 | this.readyState = 'open'; |
edamame22 | 0:a9bcda5b678a | 374 | this.emit('open'); |
edamame22 | 0:a9bcda5b678a | 375 | |
edamame22 | 0:a9bcda5b678a | 376 | // add new subs |
edamame22 | 0:a9bcda5b678a | 377 | var socket = this.engine; |
edamame22 | 0:a9bcda5b678a | 378 | this.subs.push(on(socket, 'data', bind(this, 'ondata'))); |
edamame22 | 0:a9bcda5b678a | 379 | this.subs.push(on(this.decoder, 'decoded', bind(this, 'ondecoded'))); |
edamame22 | 0:a9bcda5b678a | 380 | this.subs.push(on(socket, 'error', bind(this, 'onerror'))); |
edamame22 | 0:a9bcda5b678a | 381 | this.subs.push(on(socket, 'close', bind(this, 'onclose'))); |
edamame22 | 0:a9bcda5b678a | 382 | }; |
edamame22 | 0:a9bcda5b678a | 383 | |
edamame22 | 0:a9bcda5b678a | 384 | /** |
edamame22 | 0:a9bcda5b678a | 385 | * Called with data. |
edamame22 | 0:a9bcda5b678a | 386 | * |
edamame22 | 0:a9bcda5b678a | 387 | * @api private |
edamame22 | 0:a9bcda5b678a | 388 | */ |
edamame22 | 0:a9bcda5b678a | 389 | |
edamame22 | 0:a9bcda5b678a | 390 | Manager.prototype.ondata = function(data){ |
edamame22 | 0:a9bcda5b678a | 391 | this.decoder.add(data); |
edamame22 | 0:a9bcda5b678a | 392 | }; |
edamame22 | 0:a9bcda5b678a | 393 | |
edamame22 | 0:a9bcda5b678a | 394 | /** |
edamame22 | 0:a9bcda5b678a | 395 | * Called when parser fully decodes a packet. |
edamame22 | 0:a9bcda5b678a | 396 | * |
edamame22 | 0:a9bcda5b678a | 397 | * @api private |
edamame22 | 0:a9bcda5b678a | 398 | */ |
edamame22 | 0:a9bcda5b678a | 399 | |
edamame22 | 0:a9bcda5b678a | 400 | Manager.prototype.ondecoded = function(packet) { |
edamame22 | 0:a9bcda5b678a | 401 | this.emit('packet', packet); |
edamame22 | 0:a9bcda5b678a | 402 | }; |
edamame22 | 0:a9bcda5b678a | 403 | |
edamame22 | 0:a9bcda5b678a | 404 | /** |
edamame22 | 0:a9bcda5b678a | 405 | * Called upon socket error. |
edamame22 | 0:a9bcda5b678a | 406 | * |
edamame22 | 0:a9bcda5b678a | 407 | * @api private |
edamame22 | 0:a9bcda5b678a | 408 | */ |
edamame22 | 0:a9bcda5b678a | 409 | |
edamame22 | 0:a9bcda5b678a | 410 | Manager.prototype.onerror = function(err){ |
edamame22 | 0:a9bcda5b678a | 411 | debug('error', err); |
edamame22 | 0:a9bcda5b678a | 412 | this.emitAll('error', err); |
edamame22 | 0:a9bcda5b678a | 413 | }; |
edamame22 | 0:a9bcda5b678a | 414 | |
edamame22 | 0:a9bcda5b678a | 415 | /** |
edamame22 | 0:a9bcda5b678a | 416 | * Creates a new socket for the given `nsp`. |
edamame22 | 0:a9bcda5b678a | 417 | * |
edamame22 | 0:a9bcda5b678a | 418 | * @return {Socket} |
edamame22 | 0:a9bcda5b678a | 419 | * @api public |
edamame22 | 0:a9bcda5b678a | 420 | */ |
edamame22 | 0:a9bcda5b678a | 421 | |
edamame22 | 0:a9bcda5b678a | 422 | Manager.prototype.socket = function(nsp){ |
edamame22 | 0:a9bcda5b678a | 423 | var socket = this.nsps[nsp]; |
edamame22 | 0:a9bcda5b678a | 424 | if (!socket) { |
edamame22 | 0:a9bcda5b678a | 425 | socket = new Socket(this, nsp); |
edamame22 | 0:a9bcda5b678a | 426 | this.nsps[nsp] = socket; |
edamame22 | 0:a9bcda5b678a | 427 | var self = this; |
edamame22 | 0:a9bcda5b678a | 428 | socket.on('connect', function(){ |
edamame22 | 0:a9bcda5b678a | 429 | socket.id = self.engine.id; |
edamame22 | 0:a9bcda5b678a | 430 | if (!~indexOf(self.connected, socket)) { |
edamame22 | 0:a9bcda5b678a | 431 | self.connected.push(socket); |
edamame22 | 0:a9bcda5b678a | 432 | } |
edamame22 | 0:a9bcda5b678a | 433 | }); |
edamame22 | 0:a9bcda5b678a | 434 | } |
edamame22 | 0:a9bcda5b678a | 435 | return socket; |
edamame22 | 0:a9bcda5b678a | 436 | }; |
edamame22 | 0:a9bcda5b678a | 437 | |
edamame22 | 0:a9bcda5b678a | 438 | /** |
edamame22 | 0:a9bcda5b678a | 439 | * Called upon a socket close. |
edamame22 | 0:a9bcda5b678a | 440 | * |
edamame22 | 0:a9bcda5b678a | 441 | * @param {Socket} socket |
edamame22 | 0:a9bcda5b678a | 442 | */ |
edamame22 | 0:a9bcda5b678a | 443 | |
edamame22 | 0:a9bcda5b678a | 444 | Manager.prototype.destroy = function(socket){ |
edamame22 | 0:a9bcda5b678a | 445 | var index = indexOf(this.connected, socket); |
edamame22 | 0:a9bcda5b678a | 446 | if (~index) this.connected.splice(index, 1); |
edamame22 | 0:a9bcda5b678a | 447 | if (this.connected.length) return; |
edamame22 | 0:a9bcda5b678a | 448 | |
edamame22 | 0:a9bcda5b678a | 449 | this.close(); |
edamame22 | 0:a9bcda5b678a | 450 | }; |
edamame22 | 0:a9bcda5b678a | 451 | |
edamame22 | 0:a9bcda5b678a | 452 | /** |
edamame22 | 0:a9bcda5b678a | 453 | * Writes a packet. |
edamame22 | 0:a9bcda5b678a | 454 | * |
edamame22 | 0:a9bcda5b678a | 455 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 456 | * @api private |
edamame22 | 0:a9bcda5b678a | 457 | */ |
edamame22 | 0:a9bcda5b678a | 458 | |
edamame22 | 0:a9bcda5b678a | 459 | Manager.prototype.packet = function(packet){ |
edamame22 | 0:a9bcda5b678a | 460 | debug('writing packet %j', packet); |
edamame22 | 0:a9bcda5b678a | 461 | var self = this; |
edamame22 | 0:a9bcda5b678a | 462 | |
edamame22 | 0:a9bcda5b678a | 463 | if (!self.encoding) { |
edamame22 | 0:a9bcda5b678a | 464 | // encode, then write to engine with result |
edamame22 | 0:a9bcda5b678a | 465 | self.encoding = true; |
edamame22 | 0:a9bcda5b678a | 466 | this.encoder.encode(packet, function(encodedPackets) { |
edamame22 | 0:a9bcda5b678a | 467 | for (var i = 0; i < encodedPackets.length; i++) { |
edamame22 | 0:a9bcda5b678a | 468 | self.engine.write(encodedPackets[i]); |
edamame22 | 0:a9bcda5b678a | 469 | } |
edamame22 | 0:a9bcda5b678a | 470 | self.encoding = false; |
edamame22 | 0:a9bcda5b678a | 471 | self.processPacketQueue(); |
edamame22 | 0:a9bcda5b678a | 472 | }); |
edamame22 | 0:a9bcda5b678a | 473 | } else { // add packet to the queue |
edamame22 | 0:a9bcda5b678a | 474 | self.packetBuffer.push(packet); |
edamame22 | 0:a9bcda5b678a | 475 | } |
edamame22 | 0:a9bcda5b678a | 476 | }; |
edamame22 | 0:a9bcda5b678a | 477 | |
edamame22 | 0:a9bcda5b678a | 478 | /** |
edamame22 | 0:a9bcda5b678a | 479 | * If packet buffer is non-empty, begins encoding the |
edamame22 | 0:a9bcda5b678a | 480 | * next packet in line. |
edamame22 | 0:a9bcda5b678a | 481 | * |
edamame22 | 0:a9bcda5b678a | 482 | * @api private |
edamame22 | 0:a9bcda5b678a | 483 | */ |
edamame22 | 0:a9bcda5b678a | 484 | |
edamame22 | 0:a9bcda5b678a | 485 | Manager.prototype.processPacketQueue = function() { |
edamame22 | 0:a9bcda5b678a | 486 | if (this.packetBuffer.length > 0 && !this.encoding) { |
edamame22 | 0:a9bcda5b678a | 487 | var pack = this.packetBuffer.shift(); |
edamame22 | 0:a9bcda5b678a | 488 | this.packet(pack); |
edamame22 | 0:a9bcda5b678a | 489 | } |
edamame22 | 0:a9bcda5b678a | 490 | }; |
edamame22 | 0:a9bcda5b678a | 491 | |
edamame22 | 0:a9bcda5b678a | 492 | /** |
edamame22 | 0:a9bcda5b678a | 493 | * Clean up transport subscriptions and packet buffer. |
edamame22 | 0:a9bcda5b678a | 494 | * |
edamame22 | 0:a9bcda5b678a | 495 | * @api private |
edamame22 | 0:a9bcda5b678a | 496 | */ |
edamame22 | 0:a9bcda5b678a | 497 | |
edamame22 | 0:a9bcda5b678a | 498 | Manager.prototype.cleanup = function(){ |
edamame22 | 0:a9bcda5b678a | 499 | var sub; |
edamame22 | 0:a9bcda5b678a | 500 | while (sub = this.subs.shift()) sub.destroy(); |
edamame22 | 0:a9bcda5b678a | 501 | |
edamame22 | 0:a9bcda5b678a | 502 | this.packetBuffer = []; |
edamame22 | 0:a9bcda5b678a | 503 | this.encoding = false; |
edamame22 | 0:a9bcda5b678a | 504 | |
edamame22 | 0:a9bcda5b678a | 505 | this.decoder.destroy(); |
edamame22 | 0:a9bcda5b678a | 506 | }; |
edamame22 | 0:a9bcda5b678a | 507 | |
edamame22 | 0:a9bcda5b678a | 508 | /** |
edamame22 | 0:a9bcda5b678a | 509 | * Close the current socket. |
edamame22 | 0:a9bcda5b678a | 510 | * |
edamame22 | 0:a9bcda5b678a | 511 | * @api private |
edamame22 | 0:a9bcda5b678a | 512 | */ |
edamame22 | 0:a9bcda5b678a | 513 | |
edamame22 | 0:a9bcda5b678a | 514 | Manager.prototype.close = |
edamame22 | 0:a9bcda5b678a | 515 | Manager.prototype.disconnect = function(){ |
edamame22 | 0:a9bcda5b678a | 516 | this.skipReconnect = true; |
edamame22 | 0:a9bcda5b678a | 517 | this.backoff.reset(); |
edamame22 | 0:a9bcda5b678a | 518 | this.readyState = 'closed'; |
edamame22 | 0:a9bcda5b678a | 519 | this.engine && this.engine.close(); |
edamame22 | 0:a9bcda5b678a | 520 | }; |
edamame22 | 0:a9bcda5b678a | 521 | |
edamame22 | 0:a9bcda5b678a | 522 | /** |
edamame22 | 0:a9bcda5b678a | 523 | * Called upon engine close. |
edamame22 | 0:a9bcda5b678a | 524 | * |
edamame22 | 0:a9bcda5b678a | 525 | * @api private |
edamame22 | 0:a9bcda5b678a | 526 | */ |
edamame22 | 0:a9bcda5b678a | 527 | |
edamame22 | 0:a9bcda5b678a | 528 | Manager.prototype.onclose = function(reason){ |
edamame22 | 0:a9bcda5b678a | 529 | debug('close'); |
edamame22 | 0:a9bcda5b678a | 530 | this.cleanup(); |
edamame22 | 0:a9bcda5b678a | 531 | this.backoff.reset(); |
edamame22 | 0:a9bcda5b678a | 532 | this.readyState = 'closed'; |
edamame22 | 0:a9bcda5b678a | 533 | this.emit('close', reason); |
edamame22 | 0:a9bcda5b678a | 534 | if (this._reconnection && !this.skipReconnect) { |
edamame22 | 0:a9bcda5b678a | 535 | this.reconnect(); |
edamame22 | 0:a9bcda5b678a | 536 | } |
edamame22 | 0:a9bcda5b678a | 537 | }; |
edamame22 | 0:a9bcda5b678a | 538 | |
edamame22 | 0:a9bcda5b678a | 539 | /** |
edamame22 | 0:a9bcda5b678a | 540 | * Attempt a reconnection. |
edamame22 | 0:a9bcda5b678a | 541 | * |
edamame22 | 0:a9bcda5b678a | 542 | * @api private |
edamame22 | 0:a9bcda5b678a | 543 | */ |
edamame22 | 0:a9bcda5b678a | 544 | |
edamame22 | 0:a9bcda5b678a | 545 | Manager.prototype.reconnect = function(){ |
edamame22 | 0:a9bcda5b678a | 546 | if (this.reconnecting || this.skipReconnect) return this; |
edamame22 | 0:a9bcda5b678a | 547 | |
edamame22 | 0:a9bcda5b678a | 548 | var self = this; |
edamame22 | 0:a9bcda5b678a | 549 | |
edamame22 | 0:a9bcda5b678a | 550 | if (this.backoff.attempts >= this._reconnectionAttempts) { |
edamame22 | 0:a9bcda5b678a | 551 | debug('reconnect failed'); |
edamame22 | 0:a9bcda5b678a | 552 | this.backoff.reset(); |
edamame22 | 0:a9bcda5b678a | 553 | this.emitAll('reconnect_failed'); |
edamame22 | 0:a9bcda5b678a | 554 | this.reconnecting = false; |
edamame22 | 0:a9bcda5b678a | 555 | } else { |
edamame22 | 0:a9bcda5b678a | 556 | var delay = this.backoff.duration(); |
edamame22 | 0:a9bcda5b678a | 557 | debug('will wait %dms before reconnect attempt', delay); |
edamame22 | 0:a9bcda5b678a | 558 | |
edamame22 | 0:a9bcda5b678a | 559 | this.reconnecting = true; |
edamame22 | 0:a9bcda5b678a | 560 | var timer = setTimeout(function(){ |
edamame22 | 0:a9bcda5b678a | 561 | if (self.skipReconnect) return; |
edamame22 | 0:a9bcda5b678a | 562 | |
edamame22 | 0:a9bcda5b678a | 563 | debug('attempting reconnect'); |
edamame22 | 0:a9bcda5b678a | 564 | self.emitAll('reconnect_attempt', self.backoff.attempts); |
edamame22 | 0:a9bcda5b678a | 565 | self.emitAll('reconnecting', self.backoff.attempts); |
edamame22 | 0:a9bcda5b678a | 566 | |
edamame22 | 0:a9bcda5b678a | 567 | // check again for the case socket closed in above events |
edamame22 | 0:a9bcda5b678a | 568 | if (self.skipReconnect) return; |
edamame22 | 0:a9bcda5b678a | 569 | |
edamame22 | 0:a9bcda5b678a | 570 | self.open(function(err){ |
edamame22 | 0:a9bcda5b678a | 571 | if (err) { |
edamame22 | 0:a9bcda5b678a | 572 | debug('reconnect attempt error'); |
edamame22 | 0:a9bcda5b678a | 573 | self.reconnecting = false; |
edamame22 | 0:a9bcda5b678a | 574 | self.reconnect(); |
edamame22 | 0:a9bcda5b678a | 575 | self.emitAll('reconnect_error', err.data); |
edamame22 | 0:a9bcda5b678a | 576 | } else { |
edamame22 | 0:a9bcda5b678a | 577 | debug('reconnect success'); |
edamame22 | 0:a9bcda5b678a | 578 | self.onreconnect(); |
edamame22 | 0:a9bcda5b678a | 579 | } |
edamame22 | 0:a9bcda5b678a | 580 | }); |
edamame22 | 0:a9bcda5b678a | 581 | }, delay); |
edamame22 | 0:a9bcda5b678a | 582 | |
edamame22 | 0:a9bcda5b678a | 583 | this.subs.push({ |
edamame22 | 0:a9bcda5b678a | 584 | destroy: function(){ |
edamame22 | 0:a9bcda5b678a | 585 | clearTimeout(timer); |
edamame22 | 0:a9bcda5b678a | 586 | } |
edamame22 | 0:a9bcda5b678a | 587 | }); |
edamame22 | 0:a9bcda5b678a | 588 | } |
edamame22 | 0:a9bcda5b678a | 589 | }; |
edamame22 | 0:a9bcda5b678a | 590 | |
edamame22 | 0:a9bcda5b678a | 591 | /** |
edamame22 | 0:a9bcda5b678a | 592 | * Called upon successful reconnect. |
edamame22 | 0:a9bcda5b678a | 593 | * |
edamame22 | 0:a9bcda5b678a | 594 | * @api private |
edamame22 | 0:a9bcda5b678a | 595 | */ |
edamame22 | 0:a9bcda5b678a | 596 | |
edamame22 | 0:a9bcda5b678a | 597 | Manager.prototype.onreconnect = function(){ |
edamame22 | 0:a9bcda5b678a | 598 | var attempt = this.backoff.attempts; |
edamame22 | 0:a9bcda5b678a | 599 | this.reconnecting = false; |
edamame22 | 0:a9bcda5b678a | 600 | this.backoff.reset(); |
edamame22 | 0:a9bcda5b678a | 601 | this.updateSocketIds(); |
edamame22 | 0:a9bcda5b678a | 602 | this.emitAll('reconnect', attempt); |
edamame22 | 0:a9bcda5b678a | 603 | }; |
edamame22 | 0:a9bcda5b678a | 604 | |
edamame22 | 0:a9bcda5b678a | 605 | },{"./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){ |
edamame22 | 0:a9bcda5b678a | 606 | |
edamame22 | 0:a9bcda5b678a | 607 | /** |
edamame22 | 0:a9bcda5b678a | 608 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 609 | */ |
edamame22 | 0:a9bcda5b678a | 610 | |
edamame22 | 0:a9bcda5b678a | 611 | module.exports = on; |
edamame22 | 0:a9bcda5b678a | 612 | |
edamame22 | 0:a9bcda5b678a | 613 | /** |
edamame22 | 0:a9bcda5b678a | 614 | * Helper for subscriptions. |
edamame22 | 0:a9bcda5b678a | 615 | * |
edamame22 | 0:a9bcda5b678a | 616 | * @param {Object|EventEmitter} obj with `Emitter` mixin or `EventEmitter` |
edamame22 | 0:a9bcda5b678a | 617 | * @param {String} event name |
edamame22 | 0:a9bcda5b678a | 618 | * @param {Function} callback |
edamame22 | 0:a9bcda5b678a | 619 | * @api public |
edamame22 | 0:a9bcda5b678a | 620 | */ |
edamame22 | 0:a9bcda5b678a | 621 | |
edamame22 | 0:a9bcda5b678a | 622 | function on(obj, ev, fn) { |
edamame22 | 0:a9bcda5b678a | 623 | obj.on(ev, fn); |
edamame22 | 0:a9bcda5b678a | 624 | return { |
edamame22 | 0:a9bcda5b678a | 625 | destroy: function(){ |
edamame22 | 0:a9bcda5b678a | 626 | obj.removeListener(ev, fn); |
edamame22 | 0:a9bcda5b678a | 627 | } |
edamame22 | 0:a9bcda5b678a | 628 | }; |
edamame22 | 0:a9bcda5b678a | 629 | } |
edamame22 | 0:a9bcda5b678a | 630 | |
edamame22 | 0:a9bcda5b678a | 631 | },{}],5:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 632 | |
edamame22 | 0:a9bcda5b678a | 633 | /** |
edamame22 | 0:a9bcda5b678a | 634 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 635 | */ |
edamame22 | 0:a9bcda5b678a | 636 | |
edamame22 | 0:a9bcda5b678a | 637 | var parser = _dereq_('socket.io-parser'); |
edamame22 | 0:a9bcda5b678a | 638 | var Emitter = _dereq_('component-emitter'); |
edamame22 | 0:a9bcda5b678a | 639 | var toArray = _dereq_('to-array'); |
edamame22 | 0:a9bcda5b678a | 640 | var on = _dereq_('./on'); |
edamame22 | 0:a9bcda5b678a | 641 | var bind = _dereq_('component-bind'); |
edamame22 | 0:a9bcda5b678a | 642 | var debug = _dereq_('debug')('socket.io-client:socket'); |
edamame22 | 0:a9bcda5b678a | 643 | var hasBin = _dereq_('has-binary'); |
edamame22 | 0:a9bcda5b678a | 644 | |
edamame22 | 0:a9bcda5b678a | 645 | /** |
edamame22 | 0:a9bcda5b678a | 646 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 647 | */ |
edamame22 | 0:a9bcda5b678a | 648 | |
edamame22 | 0:a9bcda5b678a | 649 | module.exports = exports = Socket; |
edamame22 | 0:a9bcda5b678a | 650 | |
edamame22 | 0:a9bcda5b678a | 651 | /** |
edamame22 | 0:a9bcda5b678a | 652 | * Internal events (blacklisted). |
edamame22 | 0:a9bcda5b678a | 653 | * These events can't be emitted by the user. |
edamame22 | 0:a9bcda5b678a | 654 | * |
edamame22 | 0:a9bcda5b678a | 655 | * @api private |
edamame22 | 0:a9bcda5b678a | 656 | */ |
edamame22 | 0:a9bcda5b678a | 657 | |
edamame22 | 0:a9bcda5b678a | 658 | var events = { |
edamame22 | 0:a9bcda5b678a | 659 | connect: 1, |
edamame22 | 0:a9bcda5b678a | 660 | connect_error: 1, |
edamame22 | 0:a9bcda5b678a | 661 | connect_timeout: 1, |
edamame22 | 0:a9bcda5b678a | 662 | disconnect: 1, |
edamame22 | 0:a9bcda5b678a | 663 | error: 1, |
edamame22 | 0:a9bcda5b678a | 664 | reconnect: 1, |
edamame22 | 0:a9bcda5b678a | 665 | reconnect_attempt: 1, |
edamame22 | 0:a9bcda5b678a | 666 | reconnect_failed: 1, |
edamame22 | 0:a9bcda5b678a | 667 | reconnect_error: 1, |
edamame22 | 0:a9bcda5b678a | 668 | reconnecting: 1 |
edamame22 | 0:a9bcda5b678a | 669 | }; |
edamame22 | 0:a9bcda5b678a | 670 | |
edamame22 | 0:a9bcda5b678a | 671 | /** |
edamame22 | 0:a9bcda5b678a | 672 | * Shortcut to `Emitter#emit`. |
edamame22 | 0:a9bcda5b678a | 673 | */ |
edamame22 | 0:a9bcda5b678a | 674 | |
edamame22 | 0:a9bcda5b678a | 675 | var emit = Emitter.prototype.emit; |
edamame22 | 0:a9bcda5b678a | 676 | |
edamame22 | 0:a9bcda5b678a | 677 | /** |
edamame22 | 0:a9bcda5b678a | 678 | * `Socket` constructor. |
edamame22 | 0:a9bcda5b678a | 679 | * |
edamame22 | 0:a9bcda5b678a | 680 | * @api public |
edamame22 | 0:a9bcda5b678a | 681 | */ |
edamame22 | 0:a9bcda5b678a | 682 | |
edamame22 | 0:a9bcda5b678a | 683 | function Socket(io, nsp){ |
edamame22 | 0:a9bcda5b678a | 684 | this.io = io; |
edamame22 | 0:a9bcda5b678a | 685 | this.nsp = nsp; |
edamame22 | 0:a9bcda5b678a | 686 | this.json = this; // compat |
edamame22 | 0:a9bcda5b678a | 687 | this.ids = 0; |
edamame22 | 0:a9bcda5b678a | 688 | this.acks = {}; |
edamame22 | 0:a9bcda5b678a | 689 | if (this.io.autoConnect) this.open(); |
edamame22 | 0:a9bcda5b678a | 690 | this.receiveBuffer = []; |
edamame22 | 0:a9bcda5b678a | 691 | this.sendBuffer = []; |
edamame22 | 0:a9bcda5b678a | 692 | this.connected = false; |
edamame22 | 0:a9bcda5b678a | 693 | this.disconnected = true; |
edamame22 | 0:a9bcda5b678a | 694 | } |
edamame22 | 0:a9bcda5b678a | 695 | |
edamame22 | 0:a9bcda5b678a | 696 | /** |
edamame22 | 0:a9bcda5b678a | 697 | * Mix in `Emitter`. |
edamame22 | 0:a9bcda5b678a | 698 | */ |
edamame22 | 0:a9bcda5b678a | 699 | |
edamame22 | 0:a9bcda5b678a | 700 | Emitter(Socket.prototype); |
edamame22 | 0:a9bcda5b678a | 701 | |
edamame22 | 0:a9bcda5b678a | 702 | /** |
edamame22 | 0:a9bcda5b678a | 703 | * Subscribe to open, close and packet events |
edamame22 | 0:a9bcda5b678a | 704 | * |
edamame22 | 0:a9bcda5b678a | 705 | * @api private |
edamame22 | 0:a9bcda5b678a | 706 | */ |
edamame22 | 0:a9bcda5b678a | 707 | |
edamame22 | 0:a9bcda5b678a | 708 | Socket.prototype.subEvents = function() { |
edamame22 | 0:a9bcda5b678a | 709 | if (this.subs) return; |
edamame22 | 0:a9bcda5b678a | 710 | |
edamame22 | 0:a9bcda5b678a | 711 | var io = this.io; |
edamame22 | 0:a9bcda5b678a | 712 | this.subs = [ |
edamame22 | 0:a9bcda5b678a | 713 | on(io, 'open', bind(this, 'onopen')), |
edamame22 | 0:a9bcda5b678a | 714 | on(io, 'packet', bind(this, 'onpacket')), |
edamame22 | 0:a9bcda5b678a | 715 | on(io, 'close', bind(this, 'onclose')) |
edamame22 | 0:a9bcda5b678a | 716 | ]; |
edamame22 | 0:a9bcda5b678a | 717 | }; |
edamame22 | 0:a9bcda5b678a | 718 | |
edamame22 | 0:a9bcda5b678a | 719 | /** |
edamame22 | 0:a9bcda5b678a | 720 | * "Opens" the socket. |
edamame22 | 0:a9bcda5b678a | 721 | * |
edamame22 | 0:a9bcda5b678a | 722 | * @api public |
edamame22 | 0:a9bcda5b678a | 723 | */ |
edamame22 | 0:a9bcda5b678a | 724 | |
edamame22 | 0:a9bcda5b678a | 725 | Socket.prototype.open = |
edamame22 | 0:a9bcda5b678a | 726 | Socket.prototype.connect = function(){ |
edamame22 | 0:a9bcda5b678a | 727 | if (this.connected) return this; |
edamame22 | 0:a9bcda5b678a | 728 | |
edamame22 | 0:a9bcda5b678a | 729 | this.subEvents(); |
edamame22 | 0:a9bcda5b678a | 730 | this.io.open(); // ensure open |
edamame22 | 0:a9bcda5b678a | 731 | if ('open' == this.io.readyState) this.onopen(); |
edamame22 | 0:a9bcda5b678a | 732 | return this; |
edamame22 | 0:a9bcda5b678a | 733 | }; |
edamame22 | 0:a9bcda5b678a | 734 | |
edamame22 | 0:a9bcda5b678a | 735 | /** |
edamame22 | 0:a9bcda5b678a | 736 | * Sends a `message` event. |
edamame22 | 0:a9bcda5b678a | 737 | * |
edamame22 | 0:a9bcda5b678a | 738 | * @return {Socket} self |
edamame22 | 0:a9bcda5b678a | 739 | * @api public |
edamame22 | 0:a9bcda5b678a | 740 | */ |
edamame22 | 0:a9bcda5b678a | 741 | |
edamame22 | 0:a9bcda5b678a | 742 | Socket.prototype.send = function(){ |
edamame22 | 0:a9bcda5b678a | 743 | var args = toArray(arguments); |
edamame22 | 0:a9bcda5b678a | 744 | args.unshift('message'); |
edamame22 | 0:a9bcda5b678a | 745 | this.emit.apply(this, args); |
edamame22 | 0:a9bcda5b678a | 746 | return this; |
edamame22 | 0:a9bcda5b678a | 747 | }; |
edamame22 | 0:a9bcda5b678a | 748 | |
edamame22 | 0:a9bcda5b678a | 749 | /** |
edamame22 | 0:a9bcda5b678a | 750 | * Override `emit`. |
edamame22 | 0:a9bcda5b678a | 751 | * If the event is in `events`, it's emitted normally. |
edamame22 | 0:a9bcda5b678a | 752 | * |
edamame22 | 0:a9bcda5b678a | 753 | * @param {String} event name |
edamame22 | 0:a9bcda5b678a | 754 | * @return {Socket} self |
edamame22 | 0:a9bcda5b678a | 755 | * @api public |
edamame22 | 0:a9bcda5b678a | 756 | */ |
edamame22 | 0:a9bcda5b678a | 757 | |
edamame22 | 0:a9bcda5b678a | 758 | Socket.prototype.emit = function(ev){ |
edamame22 | 0:a9bcda5b678a | 759 | if (events.hasOwnProperty(ev)) { |
edamame22 | 0:a9bcda5b678a | 760 | emit.apply(this, arguments); |
edamame22 | 0:a9bcda5b678a | 761 | return this; |
edamame22 | 0:a9bcda5b678a | 762 | } |
edamame22 | 0:a9bcda5b678a | 763 | |
edamame22 | 0:a9bcda5b678a | 764 | var args = toArray(arguments); |
edamame22 | 0:a9bcda5b678a | 765 | var parserType = parser.EVENT; // default |
edamame22 | 0:a9bcda5b678a | 766 | if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary |
edamame22 | 0:a9bcda5b678a | 767 | var packet = { type: parserType, data: args }; |
edamame22 | 0:a9bcda5b678a | 768 | |
edamame22 | 0:a9bcda5b678a | 769 | // event ack callback |
edamame22 | 0:a9bcda5b678a | 770 | if ('function' == typeof args[args.length - 1]) { |
edamame22 | 0:a9bcda5b678a | 771 | debug('emitting packet with ack id %d', this.ids); |
edamame22 | 0:a9bcda5b678a | 772 | this.acks[this.ids] = args.pop(); |
edamame22 | 0:a9bcda5b678a | 773 | packet.id = this.ids++; |
edamame22 | 0:a9bcda5b678a | 774 | } |
edamame22 | 0:a9bcda5b678a | 775 | |
edamame22 | 0:a9bcda5b678a | 776 | if (this.connected) { |
edamame22 | 0:a9bcda5b678a | 777 | this.packet(packet); |
edamame22 | 0:a9bcda5b678a | 778 | } else { |
edamame22 | 0:a9bcda5b678a | 779 | this.sendBuffer.push(packet); |
edamame22 | 0:a9bcda5b678a | 780 | } |
edamame22 | 0:a9bcda5b678a | 781 | |
edamame22 | 0:a9bcda5b678a | 782 | return this; |
edamame22 | 0:a9bcda5b678a | 783 | }; |
edamame22 | 0:a9bcda5b678a | 784 | |
edamame22 | 0:a9bcda5b678a | 785 | /** |
edamame22 | 0:a9bcda5b678a | 786 | * Sends a packet. |
edamame22 | 0:a9bcda5b678a | 787 | * |
edamame22 | 0:a9bcda5b678a | 788 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 789 | * @api private |
edamame22 | 0:a9bcda5b678a | 790 | */ |
edamame22 | 0:a9bcda5b678a | 791 | |
edamame22 | 0:a9bcda5b678a | 792 | Socket.prototype.packet = function(packet){ |
edamame22 | 0:a9bcda5b678a | 793 | packet.nsp = this.nsp; |
edamame22 | 0:a9bcda5b678a | 794 | this.io.packet(packet); |
edamame22 | 0:a9bcda5b678a | 795 | }; |
edamame22 | 0:a9bcda5b678a | 796 | |
edamame22 | 0:a9bcda5b678a | 797 | /** |
edamame22 | 0:a9bcda5b678a | 798 | * Called upon engine `open`. |
edamame22 | 0:a9bcda5b678a | 799 | * |
edamame22 | 0:a9bcda5b678a | 800 | * @api private |
edamame22 | 0:a9bcda5b678a | 801 | */ |
edamame22 | 0:a9bcda5b678a | 802 | |
edamame22 | 0:a9bcda5b678a | 803 | Socket.prototype.onopen = function(){ |
edamame22 | 0:a9bcda5b678a | 804 | debug('transport is open - connecting'); |
edamame22 | 0:a9bcda5b678a | 805 | |
edamame22 | 0:a9bcda5b678a | 806 | // write connect packet if necessary |
edamame22 | 0:a9bcda5b678a | 807 | if ('/' != this.nsp) { |
edamame22 | 0:a9bcda5b678a | 808 | this.packet({ type: parser.CONNECT }); |
edamame22 | 0:a9bcda5b678a | 809 | } |
edamame22 | 0:a9bcda5b678a | 810 | }; |
edamame22 | 0:a9bcda5b678a | 811 | |
edamame22 | 0:a9bcda5b678a | 812 | /** |
edamame22 | 0:a9bcda5b678a | 813 | * Called upon engine `close`. |
edamame22 | 0:a9bcda5b678a | 814 | * |
edamame22 | 0:a9bcda5b678a | 815 | * @param {String} reason |
edamame22 | 0:a9bcda5b678a | 816 | * @api private |
edamame22 | 0:a9bcda5b678a | 817 | */ |
edamame22 | 0:a9bcda5b678a | 818 | |
edamame22 | 0:a9bcda5b678a | 819 | Socket.prototype.onclose = function(reason){ |
edamame22 | 0:a9bcda5b678a | 820 | debug('close (%s)', reason); |
edamame22 | 0:a9bcda5b678a | 821 | this.connected = false; |
edamame22 | 0:a9bcda5b678a | 822 | this.disconnected = true; |
edamame22 | 0:a9bcda5b678a | 823 | delete this.id; |
edamame22 | 0:a9bcda5b678a | 824 | this.emit('disconnect', reason); |
edamame22 | 0:a9bcda5b678a | 825 | }; |
edamame22 | 0:a9bcda5b678a | 826 | |
edamame22 | 0:a9bcda5b678a | 827 | /** |
edamame22 | 0:a9bcda5b678a | 828 | * Called with socket packet. |
edamame22 | 0:a9bcda5b678a | 829 | * |
edamame22 | 0:a9bcda5b678a | 830 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 831 | * @api private |
edamame22 | 0:a9bcda5b678a | 832 | */ |
edamame22 | 0:a9bcda5b678a | 833 | |
edamame22 | 0:a9bcda5b678a | 834 | Socket.prototype.onpacket = function(packet){ |
edamame22 | 0:a9bcda5b678a | 835 | if (packet.nsp != this.nsp) return; |
edamame22 | 0:a9bcda5b678a | 836 | |
edamame22 | 0:a9bcda5b678a | 837 | switch (packet.type) { |
edamame22 | 0:a9bcda5b678a | 838 | case parser.CONNECT: |
edamame22 | 0:a9bcda5b678a | 839 | this.onconnect(); |
edamame22 | 0:a9bcda5b678a | 840 | break; |
edamame22 | 0:a9bcda5b678a | 841 | |
edamame22 | 0:a9bcda5b678a | 842 | case parser.EVENT: |
edamame22 | 0:a9bcda5b678a | 843 | this.onevent(packet); |
edamame22 | 0:a9bcda5b678a | 844 | break; |
edamame22 | 0:a9bcda5b678a | 845 | |
edamame22 | 0:a9bcda5b678a | 846 | case parser.BINARY_EVENT: |
edamame22 | 0:a9bcda5b678a | 847 | this.onevent(packet); |
edamame22 | 0:a9bcda5b678a | 848 | break; |
edamame22 | 0:a9bcda5b678a | 849 | |
edamame22 | 0:a9bcda5b678a | 850 | case parser.ACK: |
edamame22 | 0:a9bcda5b678a | 851 | this.onack(packet); |
edamame22 | 0:a9bcda5b678a | 852 | break; |
edamame22 | 0:a9bcda5b678a | 853 | |
edamame22 | 0:a9bcda5b678a | 854 | case parser.BINARY_ACK: |
edamame22 | 0:a9bcda5b678a | 855 | this.onack(packet); |
edamame22 | 0:a9bcda5b678a | 856 | break; |
edamame22 | 0:a9bcda5b678a | 857 | |
edamame22 | 0:a9bcda5b678a | 858 | case parser.DISCONNECT: |
edamame22 | 0:a9bcda5b678a | 859 | this.ondisconnect(); |
edamame22 | 0:a9bcda5b678a | 860 | break; |
edamame22 | 0:a9bcda5b678a | 861 | |
edamame22 | 0:a9bcda5b678a | 862 | case parser.ERROR: |
edamame22 | 0:a9bcda5b678a | 863 | this.emit('error', packet.data); |
edamame22 | 0:a9bcda5b678a | 864 | break; |
edamame22 | 0:a9bcda5b678a | 865 | } |
edamame22 | 0:a9bcda5b678a | 866 | }; |
edamame22 | 0:a9bcda5b678a | 867 | |
edamame22 | 0:a9bcda5b678a | 868 | /** |
edamame22 | 0:a9bcda5b678a | 869 | * Called upon a server event. |
edamame22 | 0:a9bcda5b678a | 870 | * |
edamame22 | 0:a9bcda5b678a | 871 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 872 | * @api private |
edamame22 | 0:a9bcda5b678a | 873 | */ |
edamame22 | 0:a9bcda5b678a | 874 | |
edamame22 | 0:a9bcda5b678a | 875 | Socket.prototype.onevent = function(packet){ |
edamame22 | 0:a9bcda5b678a | 876 | var args = packet.data || []; |
edamame22 | 0:a9bcda5b678a | 877 | debug('emitting event %j', args); |
edamame22 | 0:a9bcda5b678a | 878 | |
edamame22 | 0:a9bcda5b678a | 879 | if (null != packet.id) { |
edamame22 | 0:a9bcda5b678a | 880 | debug('attaching ack callback to event'); |
edamame22 | 0:a9bcda5b678a | 881 | args.push(this.ack(packet.id)); |
edamame22 | 0:a9bcda5b678a | 882 | } |
edamame22 | 0:a9bcda5b678a | 883 | |
edamame22 | 0:a9bcda5b678a | 884 | if (this.connected) { |
edamame22 | 0:a9bcda5b678a | 885 | emit.apply(this, args); |
edamame22 | 0:a9bcda5b678a | 886 | } else { |
edamame22 | 0:a9bcda5b678a | 887 | this.receiveBuffer.push(args); |
edamame22 | 0:a9bcda5b678a | 888 | } |
edamame22 | 0:a9bcda5b678a | 889 | }; |
edamame22 | 0:a9bcda5b678a | 890 | |
edamame22 | 0:a9bcda5b678a | 891 | /** |
edamame22 | 0:a9bcda5b678a | 892 | * Produces an ack callback to emit with an event. |
edamame22 | 0:a9bcda5b678a | 893 | * |
edamame22 | 0:a9bcda5b678a | 894 | * @api private |
edamame22 | 0:a9bcda5b678a | 895 | */ |
edamame22 | 0:a9bcda5b678a | 896 | |
edamame22 | 0:a9bcda5b678a | 897 | Socket.prototype.ack = function(id){ |
edamame22 | 0:a9bcda5b678a | 898 | var self = this; |
edamame22 | 0:a9bcda5b678a | 899 | var sent = false; |
edamame22 | 0:a9bcda5b678a | 900 | return function(){ |
edamame22 | 0:a9bcda5b678a | 901 | // prevent double callbacks |
edamame22 | 0:a9bcda5b678a | 902 | if (sent) return; |
edamame22 | 0:a9bcda5b678a | 903 | sent = true; |
edamame22 | 0:a9bcda5b678a | 904 | var args = toArray(arguments); |
edamame22 | 0:a9bcda5b678a | 905 | debug('sending ack %j', args); |
edamame22 | 0:a9bcda5b678a | 906 | |
edamame22 | 0:a9bcda5b678a | 907 | var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK; |
edamame22 | 0:a9bcda5b678a | 908 | self.packet({ |
edamame22 | 0:a9bcda5b678a | 909 | type: type, |
edamame22 | 0:a9bcda5b678a | 910 | id: id, |
edamame22 | 0:a9bcda5b678a | 911 | data: args |
edamame22 | 0:a9bcda5b678a | 912 | }); |
edamame22 | 0:a9bcda5b678a | 913 | }; |
edamame22 | 0:a9bcda5b678a | 914 | }; |
edamame22 | 0:a9bcda5b678a | 915 | |
edamame22 | 0:a9bcda5b678a | 916 | /** |
edamame22 | 0:a9bcda5b678a | 917 | * Called upon a server acknowlegement. |
edamame22 | 0:a9bcda5b678a | 918 | * |
edamame22 | 0:a9bcda5b678a | 919 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 920 | * @api private |
edamame22 | 0:a9bcda5b678a | 921 | */ |
edamame22 | 0:a9bcda5b678a | 922 | |
edamame22 | 0:a9bcda5b678a | 923 | Socket.prototype.onack = function(packet){ |
edamame22 | 0:a9bcda5b678a | 924 | debug('calling ack %s with %j', packet.id, packet.data); |
edamame22 | 0:a9bcda5b678a | 925 | var fn = this.acks[packet.id]; |
edamame22 | 0:a9bcda5b678a | 926 | fn.apply(this, packet.data); |
edamame22 | 0:a9bcda5b678a | 927 | delete this.acks[packet.id]; |
edamame22 | 0:a9bcda5b678a | 928 | }; |
edamame22 | 0:a9bcda5b678a | 929 | |
edamame22 | 0:a9bcda5b678a | 930 | /** |
edamame22 | 0:a9bcda5b678a | 931 | * Called upon server connect. |
edamame22 | 0:a9bcda5b678a | 932 | * |
edamame22 | 0:a9bcda5b678a | 933 | * @api private |
edamame22 | 0:a9bcda5b678a | 934 | */ |
edamame22 | 0:a9bcda5b678a | 935 | |
edamame22 | 0:a9bcda5b678a | 936 | Socket.prototype.onconnect = function(){ |
edamame22 | 0:a9bcda5b678a | 937 | this.connected = true; |
edamame22 | 0:a9bcda5b678a | 938 | this.disconnected = false; |
edamame22 | 0:a9bcda5b678a | 939 | this.emit('connect'); |
edamame22 | 0:a9bcda5b678a | 940 | this.emitBuffered(); |
edamame22 | 0:a9bcda5b678a | 941 | }; |
edamame22 | 0:a9bcda5b678a | 942 | |
edamame22 | 0:a9bcda5b678a | 943 | /** |
edamame22 | 0:a9bcda5b678a | 944 | * Emit buffered events (received and emitted). |
edamame22 | 0:a9bcda5b678a | 945 | * |
edamame22 | 0:a9bcda5b678a | 946 | * @api private |
edamame22 | 0:a9bcda5b678a | 947 | */ |
edamame22 | 0:a9bcda5b678a | 948 | |
edamame22 | 0:a9bcda5b678a | 949 | Socket.prototype.emitBuffered = function(){ |
edamame22 | 0:a9bcda5b678a | 950 | var i; |
edamame22 | 0:a9bcda5b678a | 951 | for (i = 0; i < this.receiveBuffer.length; i++) { |
edamame22 | 0:a9bcda5b678a | 952 | emit.apply(this, this.receiveBuffer[i]); |
edamame22 | 0:a9bcda5b678a | 953 | } |
edamame22 | 0:a9bcda5b678a | 954 | this.receiveBuffer = []; |
edamame22 | 0:a9bcda5b678a | 955 | |
edamame22 | 0:a9bcda5b678a | 956 | for (i = 0; i < this.sendBuffer.length; i++) { |
edamame22 | 0:a9bcda5b678a | 957 | this.packet(this.sendBuffer[i]); |
edamame22 | 0:a9bcda5b678a | 958 | } |
edamame22 | 0:a9bcda5b678a | 959 | this.sendBuffer = []; |
edamame22 | 0:a9bcda5b678a | 960 | }; |
edamame22 | 0:a9bcda5b678a | 961 | |
edamame22 | 0:a9bcda5b678a | 962 | /** |
edamame22 | 0:a9bcda5b678a | 963 | * Called upon server disconnect. |
edamame22 | 0:a9bcda5b678a | 964 | * |
edamame22 | 0:a9bcda5b678a | 965 | * @api private |
edamame22 | 0:a9bcda5b678a | 966 | */ |
edamame22 | 0:a9bcda5b678a | 967 | |
edamame22 | 0:a9bcda5b678a | 968 | Socket.prototype.ondisconnect = function(){ |
edamame22 | 0:a9bcda5b678a | 969 | debug('server disconnect (%s)', this.nsp); |
edamame22 | 0:a9bcda5b678a | 970 | this.destroy(); |
edamame22 | 0:a9bcda5b678a | 971 | this.onclose('io server disconnect'); |
edamame22 | 0:a9bcda5b678a | 972 | }; |
edamame22 | 0:a9bcda5b678a | 973 | |
edamame22 | 0:a9bcda5b678a | 974 | /** |
edamame22 | 0:a9bcda5b678a | 975 | * Called upon forced client/server side disconnections, |
edamame22 | 0:a9bcda5b678a | 976 | * this method ensures the manager stops tracking us and |
edamame22 | 0:a9bcda5b678a | 977 | * that reconnections don't get triggered for this. |
edamame22 | 0:a9bcda5b678a | 978 | * |
edamame22 | 0:a9bcda5b678a | 979 | * @api private. |
edamame22 | 0:a9bcda5b678a | 980 | */ |
edamame22 | 0:a9bcda5b678a | 981 | |
edamame22 | 0:a9bcda5b678a | 982 | Socket.prototype.destroy = function(){ |
edamame22 | 0:a9bcda5b678a | 983 | if (this.subs) { |
edamame22 | 0:a9bcda5b678a | 984 | // clean subscriptions to avoid reconnections |
edamame22 | 0:a9bcda5b678a | 985 | for (var i = 0; i < this.subs.length; i++) { |
edamame22 | 0:a9bcda5b678a | 986 | this.subs[i].destroy(); |
edamame22 | 0:a9bcda5b678a | 987 | } |
edamame22 | 0:a9bcda5b678a | 988 | this.subs = null; |
edamame22 | 0:a9bcda5b678a | 989 | } |
edamame22 | 0:a9bcda5b678a | 990 | |
edamame22 | 0:a9bcda5b678a | 991 | this.io.destroy(this); |
edamame22 | 0:a9bcda5b678a | 992 | }; |
edamame22 | 0:a9bcda5b678a | 993 | |
edamame22 | 0:a9bcda5b678a | 994 | /** |
edamame22 | 0:a9bcda5b678a | 995 | * Disconnects the socket manually. |
edamame22 | 0:a9bcda5b678a | 996 | * |
edamame22 | 0:a9bcda5b678a | 997 | * @return {Socket} self |
edamame22 | 0:a9bcda5b678a | 998 | * @api public |
edamame22 | 0:a9bcda5b678a | 999 | */ |
edamame22 | 0:a9bcda5b678a | 1000 | |
edamame22 | 0:a9bcda5b678a | 1001 | Socket.prototype.close = |
edamame22 | 0:a9bcda5b678a | 1002 | Socket.prototype.disconnect = function(){ |
edamame22 | 0:a9bcda5b678a | 1003 | if (this.connected) { |
edamame22 | 0:a9bcda5b678a | 1004 | debug('performing disconnect (%s)', this.nsp); |
edamame22 | 0:a9bcda5b678a | 1005 | this.packet({ type: parser.DISCONNECT }); |
edamame22 | 0:a9bcda5b678a | 1006 | } |
edamame22 | 0:a9bcda5b678a | 1007 | |
edamame22 | 0:a9bcda5b678a | 1008 | // remove socket from pool |
edamame22 | 0:a9bcda5b678a | 1009 | this.destroy(); |
edamame22 | 0:a9bcda5b678a | 1010 | |
edamame22 | 0:a9bcda5b678a | 1011 | if (this.connected) { |
edamame22 | 0:a9bcda5b678a | 1012 | // fire events |
edamame22 | 0:a9bcda5b678a | 1013 | this.onclose('io client disconnect'); |
edamame22 | 0:a9bcda5b678a | 1014 | } |
edamame22 | 0:a9bcda5b678a | 1015 | return this; |
edamame22 | 0:a9bcda5b678a | 1016 | }; |
edamame22 | 0:a9bcda5b678a | 1017 | |
edamame22 | 0:a9bcda5b678a | 1018 | },{"./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){ |
edamame22 | 0:a9bcda5b678a | 1019 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 1020 | |
edamame22 | 0:a9bcda5b678a | 1021 | /** |
edamame22 | 0:a9bcda5b678a | 1022 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 1023 | */ |
edamame22 | 0:a9bcda5b678a | 1024 | |
edamame22 | 0:a9bcda5b678a | 1025 | var parseuri = _dereq_('parseuri'); |
edamame22 | 0:a9bcda5b678a | 1026 | var debug = _dereq_('debug')('socket.io-client:url'); |
edamame22 | 0:a9bcda5b678a | 1027 | |
edamame22 | 0:a9bcda5b678a | 1028 | /** |
edamame22 | 0:a9bcda5b678a | 1029 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 1030 | */ |
edamame22 | 0:a9bcda5b678a | 1031 | |
edamame22 | 0:a9bcda5b678a | 1032 | module.exports = url; |
edamame22 | 0:a9bcda5b678a | 1033 | |
edamame22 | 0:a9bcda5b678a | 1034 | /** |
edamame22 | 0:a9bcda5b678a | 1035 | * URL parser. |
edamame22 | 0:a9bcda5b678a | 1036 | * |
edamame22 | 0:a9bcda5b678a | 1037 | * @param {String} url |
edamame22 | 0:a9bcda5b678a | 1038 | * @param {Object} An object meant to mimic window.location. |
edamame22 | 0:a9bcda5b678a | 1039 | * Defaults to window.location. |
edamame22 | 0:a9bcda5b678a | 1040 | * @api public |
edamame22 | 0:a9bcda5b678a | 1041 | */ |
edamame22 | 0:a9bcda5b678a | 1042 | |
edamame22 | 0:a9bcda5b678a | 1043 | function url(uri, loc){ |
edamame22 | 0:a9bcda5b678a | 1044 | var obj = uri; |
edamame22 | 0:a9bcda5b678a | 1045 | |
edamame22 | 0:a9bcda5b678a | 1046 | // default to window.location |
edamame22 | 0:a9bcda5b678a | 1047 | var loc = loc || global.location; |
edamame22 | 0:a9bcda5b678a | 1048 | if (null == uri) uri = loc.protocol + '//' + loc.host; |
edamame22 | 0:a9bcda5b678a | 1049 | |
edamame22 | 0:a9bcda5b678a | 1050 | // relative path support |
edamame22 | 0:a9bcda5b678a | 1051 | if ('string' == typeof uri) { |
edamame22 | 0:a9bcda5b678a | 1052 | if ('/' == uri.charAt(0)) { |
edamame22 | 0:a9bcda5b678a | 1053 | if ('/' == uri.charAt(1)) { |
edamame22 | 0:a9bcda5b678a | 1054 | uri = loc.protocol + uri; |
edamame22 | 0:a9bcda5b678a | 1055 | } else { |
edamame22 | 0:a9bcda5b678a | 1056 | uri = loc.hostname + uri; |
edamame22 | 0:a9bcda5b678a | 1057 | } |
edamame22 | 0:a9bcda5b678a | 1058 | } |
edamame22 | 0:a9bcda5b678a | 1059 | |
edamame22 | 0:a9bcda5b678a | 1060 | if (!/^(https?|wss?):\/\//.test(uri)) { |
edamame22 | 0:a9bcda5b678a | 1061 | debug('protocol-less url %s', uri); |
edamame22 | 0:a9bcda5b678a | 1062 | if ('undefined' != typeof loc) { |
edamame22 | 0:a9bcda5b678a | 1063 | uri = loc.protocol + '//' + uri; |
edamame22 | 0:a9bcda5b678a | 1064 | } else { |
edamame22 | 0:a9bcda5b678a | 1065 | uri = 'https://' + uri; |
edamame22 | 0:a9bcda5b678a | 1066 | } |
edamame22 | 0:a9bcda5b678a | 1067 | } |
edamame22 | 0:a9bcda5b678a | 1068 | |
edamame22 | 0:a9bcda5b678a | 1069 | // parse |
edamame22 | 0:a9bcda5b678a | 1070 | debug('parse %s', uri); |
edamame22 | 0:a9bcda5b678a | 1071 | obj = parseuri(uri); |
edamame22 | 0:a9bcda5b678a | 1072 | } |
edamame22 | 0:a9bcda5b678a | 1073 | |
edamame22 | 0:a9bcda5b678a | 1074 | // make sure we treat `localhost:80` and `localhost` equally |
edamame22 | 0:a9bcda5b678a | 1075 | if (!obj.port) { |
edamame22 | 0:a9bcda5b678a | 1076 | if (/^(http|ws)$/.test(obj.protocol)) { |
edamame22 | 0:a9bcda5b678a | 1077 | obj.port = '80'; |
edamame22 | 0:a9bcda5b678a | 1078 | } |
edamame22 | 0:a9bcda5b678a | 1079 | else if (/^(http|ws)s$/.test(obj.protocol)) { |
edamame22 | 0:a9bcda5b678a | 1080 | obj.port = '443'; |
edamame22 | 0:a9bcda5b678a | 1081 | } |
edamame22 | 0:a9bcda5b678a | 1082 | } |
edamame22 | 0:a9bcda5b678a | 1083 | |
edamame22 | 0:a9bcda5b678a | 1084 | obj.path = obj.path || '/'; |
edamame22 | 0:a9bcda5b678a | 1085 | |
edamame22 | 0:a9bcda5b678a | 1086 | // define unique id |
edamame22 | 0:a9bcda5b678a | 1087 | obj.id = obj.protocol + '://' + obj.host + ':' + obj.port; |
edamame22 | 0:a9bcda5b678a | 1088 | // define href |
edamame22 | 0:a9bcda5b678a | 1089 | obj.href = obj.protocol + '://' + obj.host + (loc && loc.port == obj.port ? '' : (':' + obj.port)); |
edamame22 | 0:a9bcda5b678a | 1090 | |
edamame22 | 0:a9bcda5b678a | 1091 | return obj; |
edamame22 | 0:a9bcda5b678a | 1092 | } |
edamame22 | 0:a9bcda5b678a | 1093 | |
edamame22 | 0:a9bcda5b678a | 1094 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 1095 | },{"debug":10,"parseuri":44}],7:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1096 | |
edamame22 | 0:a9bcda5b678a | 1097 | /** |
edamame22 | 0:a9bcda5b678a | 1098 | * Expose `Backoff`. |
edamame22 | 0:a9bcda5b678a | 1099 | */ |
edamame22 | 0:a9bcda5b678a | 1100 | |
edamame22 | 0:a9bcda5b678a | 1101 | module.exports = Backoff; |
edamame22 | 0:a9bcda5b678a | 1102 | |
edamame22 | 0:a9bcda5b678a | 1103 | /** |
edamame22 | 0:a9bcda5b678a | 1104 | * Initialize backoff timer with `opts`. |
edamame22 | 0:a9bcda5b678a | 1105 | * |
edamame22 | 0:a9bcda5b678a | 1106 | * - `min` initial timeout in milliseconds [100] |
edamame22 | 0:a9bcda5b678a | 1107 | * - `max` max timeout [10000] |
edamame22 | 0:a9bcda5b678a | 1108 | * - `jitter` [0] |
edamame22 | 0:a9bcda5b678a | 1109 | * - `factor` [2] |
edamame22 | 0:a9bcda5b678a | 1110 | * |
edamame22 | 0:a9bcda5b678a | 1111 | * @param {Object} opts |
edamame22 | 0:a9bcda5b678a | 1112 | * @api public |
edamame22 | 0:a9bcda5b678a | 1113 | */ |
edamame22 | 0:a9bcda5b678a | 1114 | |
edamame22 | 0:a9bcda5b678a | 1115 | function Backoff(opts) { |
edamame22 | 0:a9bcda5b678a | 1116 | opts = opts || {}; |
edamame22 | 0:a9bcda5b678a | 1117 | this.ms = opts.min || 100; |
edamame22 | 0:a9bcda5b678a | 1118 | this.max = opts.max || 10000; |
edamame22 | 0:a9bcda5b678a | 1119 | this.factor = opts.factor || 2; |
edamame22 | 0:a9bcda5b678a | 1120 | this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0; |
edamame22 | 0:a9bcda5b678a | 1121 | this.attempts = 0; |
edamame22 | 0:a9bcda5b678a | 1122 | } |
edamame22 | 0:a9bcda5b678a | 1123 | |
edamame22 | 0:a9bcda5b678a | 1124 | /** |
edamame22 | 0:a9bcda5b678a | 1125 | * Return the backoff duration. |
edamame22 | 0:a9bcda5b678a | 1126 | * |
edamame22 | 0:a9bcda5b678a | 1127 | * @return {Number} |
edamame22 | 0:a9bcda5b678a | 1128 | * @api public |
edamame22 | 0:a9bcda5b678a | 1129 | */ |
edamame22 | 0:a9bcda5b678a | 1130 | |
edamame22 | 0:a9bcda5b678a | 1131 | Backoff.prototype.duration = function(){ |
edamame22 | 0:a9bcda5b678a | 1132 | var ms = this.ms * Math.pow(this.factor, this.attempts++); |
edamame22 | 0:a9bcda5b678a | 1133 | if (this.jitter) { |
edamame22 | 0:a9bcda5b678a | 1134 | var rand = Math.random(); |
edamame22 | 0:a9bcda5b678a | 1135 | var deviation = Math.floor(rand * this.jitter * ms); |
edamame22 | 0:a9bcda5b678a | 1136 | ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation; |
edamame22 | 0:a9bcda5b678a | 1137 | } |
edamame22 | 0:a9bcda5b678a | 1138 | return Math.min(ms, this.max) | 0; |
edamame22 | 0:a9bcda5b678a | 1139 | }; |
edamame22 | 0:a9bcda5b678a | 1140 | |
edamame22 | 0:a9bcda5b678a | 1141 | /** |
edamame22 | 0:a9bcda5b678a | 1142 | * Reset the number of attempts. |
edamame22 | 0:a9bcda5b678a | 1143 | * |
edamame22 | 0:a9bcda5b678a | 1144 | * @api public |
edamame22 | 0:a9bcda5b678a | 1145 | */ |
edamame22 | 0:a9bcda5b678a | 1146 | |
edamame22 | 0:a9bcda5b678a | 1147 | Backoff.prototype.reset = function(){ |
edamame22 | 0:a9bcda5b678a | 1148 | this.attempts = 0; |
edamame22 | 0:a9bcda5b678a | 1149 | }; |
edamame22 | 0:a9bcda5b678a | 1150 | |
edamame22 | 0:a9bcda5b678a | 1151 | /** |
edamame22 | 0:a9bcda5b678a | 1152 | * Set the minimum duration |
edamame22 | 0:a9bcda5b678a | 1153 | * |
edamame22 | 0:a9bcda5b678a | 1154 | * @api public |
edamame22 | 0:a9bcda5b678a | 1155 | */ |
edamame22 | 0:a9bcda5b678a | 1156 | |
edamame22 | 0:a9bcda5b678a | 1157 | Backoff.prototype.setMin = function(min){ |
edamame22 | 0:a9bcda5b678a | 1158 | this.ms = min; |
edamame22 | 0:a9bcda5b678a | 1159 | }; |
edamame22 | 0:a9bcda5b678a | 1160 | |
edamame22 | 0:a9bcda5b678a | 1161 | /** |
edamame22 | 0:a9bcda5b678a | 1162 | * Set the maximum duration |
edamame22 | 0:a9bcda5b678a | 1163 | * |
edamame22 | 0:a9bcda5b678a | 1164 | * @api public |
edamame22 | 0:a9bcda5b678a | 1165 | */ |
edamame22 | 0:a9bcda5b678a | 1166 | |
edamame22 | 0:a9bcda5b678a | 1167 | Backoff.prototype.setMax = function(max){ |
edamame22 | 0:a9bcda5b678a | 1168 | this.max = max; |
edamame22 | 0:a9bcda5b678a | 1169 | }; |
edamame22 | 0:a9bcda5b678a | 1170 | |
edamame22 | 0:a9bcda5b678a | 1171 | /** |
edamame22 | 0:a9bcda5b678a | 1172 | * Set the jitter |
edamame22 | 0:a9bcda5b678a | 1173 | * |
edamame22 | 0:a9bcda5b678a | 1174 | * @api public |
edamame22 | 0:a9bcda5b678a | 1175 | */ |
edamame22 | 0:a9bcda5b678a | 1176 | |
edamame22 | 0:a9bcda5b678a | 1177 | Backoff.prototype.setJitter = function(jitter){ |
edamame22 | 0:a9bcda5b678a | 1178 | this.jitter = jitter; |
edamame22 | 0:a9bcda5b678a | 1179 | }; |
edamame22 | 0:a9bcda5b678a | 1180 | |
edamame22 | 0:a9bcda5b678a | 1181 | |
edamame22 | 0:a9bcda5b678a | 1182 | },{}],8:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1183 | /** |
edamame22 | 0:a9bcda5b678a | 1184 | * Slice reference. |
edamame22 | 0:a9bcda5b678a | 1185 | */ |
edamame22 | 0:a9bcda5b678a | 1186 | |
edamame22 | 0:a9bcda5b678a | 1187 | var slice = [].slice; |
edamame22 | 0:a9bcda5b678a | 1188 | |
edamame22 | 0:a9bcda5b678a | 1189 | /** |
edamame22 | 0:a9bcda5b678a | 1190 | * Bind `obj` to `fn`. |
edamame22 | 0:a9bcda5b678a | 1191 | * |
edamame22 | 0:a9bcda5b678a | 1192 | * @param {Object} obj |
edamame22 | 0:a9bcda5b678a | 1193 | * @param {Function|String} fn or string |
edamame22 | 0:a9bcda5b678a | 1194 | * @return {Function} |
edamame22 | 0:a9bcda5b678a | 1195 | * @api public |
edamame22 | 0:a9bcda5b678a | 1196 | */ |
edamame22 | 0:a9bcda5b678a | 1197 | |
edamame22 | 0:a9bcda5b678a | 1198 | module.exports = function(obj, fn){ |
edamame22 | 0:a9bcda5b678a | 1199 | if ('string' == typeof fn) fn = obj[fn]; |
edamame22 | 0:a9bcda5b678a | 1200 | if ('function' != typeof fn) throw new Error('bind() requires a function'); |
edamame22 | 0:a9bcda5b678a | 1201 | var args = slice.call(arguments, 2); |
edamame22 | 0:a9bcda5b678a | 1202 | return function(){ |
edamame22 | 0:a9bcda5b678a | 1203 | return fn.apply(obj, args.concat(slice.call(arguments))); |
edamame22 | 0:a9bcda5b678a | 1204 | } |
edamame22 | 0:a9bcda5b678a | 1205 | }; |
edamame22 | 0:a9bcda5b678a | 1206 | |
edamame22 | 0:a9bcda5b678a | 1207 | },{}],9:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1208 | |
edamame22 | 0:a9bcda5b678a | 1209 | /** |
edamame22 | 0:a9bcda5b678a | 1210 | * Expose `Emitter`. |
edamame22 | 0:a9bcda5b678a | 1211 | */ |
edamame22 | 0:a9bcda5b678a | 1212 | |
edamame22 | 0:a9bcda5b678a | 1213 | module.exports = Emitter; |
edamame22 | 0:a9bcda5b678a | 1214 | |
edamame22 | 0:a9bcda5b678a | 1215 | /** |
edamame22 | 0:a9bcda5b678a | 1216 | * Initialize a new `Emitter`. |
edamame22 | 0:a9bcda5b678a | 1217 | * |
edamame22 | 0:a9bcda5b678a | 1218 | * @api public |
edamame22 | 0:a9bcda5b678a | 1219 | */ |
edamame22 | 0:a9bcda5b678a | 1220 | |
edamame22 | 0:a9bcda5b678a | 1221 | function Emitter(obj) { |
edamame22 | 0:a9bcda5b678a | 1222 | if (obj) return mixin(obj); |
edamame22 | 0:a9bcda5b678a | 1223 | }; |
edamame22 | 0:a9bcda5b678a | 1224 | |
edamame22 | 0:a9bcda5b678a | 1225 | /** |
edamame22 | 0:a9bcda5b678a | 1226 | * Mixin the emitter properties. |
edamame22 | 0:a9bcda5b678a | 1227 | * |
edamame22 | 0:a9bcda5b678a | 1228 | * @param {Object} obj |
edamame22 | 0:a9bcda5b678a | 1229 | * @return {Object} |
edamame22 | 0:a9bcda5b678a | 1230 | * @api private |
edamame22 | 0:a9bcda5b678a | 1231 | */ |
edamame22 | 0:a9bcda5b678a | 1232 | |
edamame22 | 0:a9bcda5b678a | 1233 | function mixin(obj) { |
edamame22 | 0:a9bcda5b678a | 1234 | for (var key in Emitter.prototype) { |
edamame22 | 0:a9bcda5b678a | 1235 | obj[key] = Emitter.prototype[key]; |
edamame22 | 0:a9bcda5b678a | 1236 | } |
edamame22 | 0:a9bcda5b678a | 1237 | return obj; |
edamame22 | 0:a9bcda5b678a | 1238 | } |
edamame22 | 0:a9bcda5b678a | 1239 | |
edamame22 | 0:a9bcda5b678a | 1240 | /** |
edamame22 | 0:a9bcda5b678a | 1241 | * Listen on the given `event` with `fn`. |
edamame22 | 0:a9bcda5b678a | 1242 | * |
edamame22 | 0:a9bcda5b678a | 1243 | * @param {String} event |
edamame22 | 0:a9bcda5b678a | 1244 | * @param {Function} fn |
edamame22 | 0:a9bcda5b678a | 1245 | * @return {Emitter} |
edamame22 | 0:a9bcda5b678a | 1246 | * @api public |
edamame22 | 0:a9bcda5b678a | 1247 | */ |
edamame22 | 0:a9bcda5b678a | 1248 | |
edamame22 | 0:a9bcda5b678a | 1249 | Emitter.prototype.on = |
edamame22 | 0:a9bcda5b678a | 1250 | Emitter.prototype.addEventListener = function(event, fn){ |
edamame22 | 0:a9bcda5b678a | 1251 | this._callbacks = this._callbacks || {}; |
edamame22 | 0:a9bcda5b678a | 1252 | (this._callbacks[event] = this._callbacks[event] || []) |
edamame22 | 0:a9bcda5b678a | 1253 | .push(fn); |
edamame22 | 0:a9bcda5b678a | 1254 | return this; |
edamame22 | 0:a9bcda5b678a | 1255 | }; |
edamame22 | 0:a9bcda5b678a | 1256 | |
edamame22 | 0:a9bcda5b678a | 1257 | /** |
edamame22 | 0:a9bcda5b678a | 1258 | * Adds an `event` listener that will be invoked a single |
edamame22 | 0:a9bcda5b678a | 1259 | * time then automatically removed. |
edamame22 | 0:a9bcda5b678a | 1260 | * |
edamame22 | 0:a9bcda5b678a | 1261 | * @param {String} event |
edamame22 | 0:a9bcda5b678a | 1262 | * @param {Function} fn |
edamame22 | 0:a9bcda5b678a | 1263 | * @return {Emitter} |
edamame22 | 0:a9bcda5b678a | 1264 | * @api public |
edamame22 | 0:a9bcda5b678a | 1265 | */ |
edamame22 | 0:a9bcda5b678a | 1266 | |
edamame22 | 0:a9bcda5b678a | 1267 | Emitter.prototype.once = function(event, fn){ |
edamame22 | 0:a9bcda5b678a | 1268 | var self = this; |
edamame22 | 0:a9bcda5b678a | 1269 | this._callbacks = this._callbacks || {}; |
edamame22 | 0:a9bcda5b678a | 1270 | |
edamame22 | 0:a9bcda5b678a | 1271 | function on() { |
edamame22 | 0:a9bcda5b678a | 1272 | self.off(event, on); |
edamame22 | 0:a9bcda5b678a | 1273 | fn.apply(this, arguments); |
edamame22 | 0:a9bcda5b678a | 1274 | } |
edamame22 | 0:a9bcda5b678a | 1275 | |
edamame22 | 0:a9bcda5b678a | 1276 | on.fn = fn; |
edamame22 | 0:a9bcda5b678a | 1277 | this.on(event, on); |
edamame22 | 0:a9bcda5b678a | 1278 | return this; |
edamame22 | 0:a9bcda5b678a | 1279 | }; |
edamame22 | 0:a9bcda5b678a | 1280 | |
edamame22 | 0:a9bcda5b678a | 1281 | /** |
edamame22 | 0:a9bcda5b678a | 1282 | * Remove the given callback for `event` or all |
edamame22 | 0:a9bcda5b678a | 1283 | * registered callbacks. |
edamame22 | 0:a9bcda5b678a | 1284 | * |
edamame22 | 0:a9bcda5b678a | 1285 | * @param {String} event |
edamame22 | 0:a9bcda5b678a | 1286 | * @param {Function} fn |
edamame22 | 0:a9bcda5b678a | 1287 | * @return {Emitter} |
edamame22 | 0:a9bcda5b678a | 1288 | * @api public |
edamame22 | 0:a9bcda5b678a | 1289 | */ |
edamame22 | 0:a9bcda5b678a | 1290 | |
edamame22 | 0:a9bcda5b678a | 1291 | Emitter.prototype.off = |
edamame22 | 0:a9bcda5b678a | 1292 | Emitter.prototype.removeListener = |
edamame22 | 0:a9bcda5b678a | 1293 | Emitter.prototype.removeAllListeners = |
edamame22 | 0:a9bcda5b678a | 1294 | Emitter.prototype.removeEventListener = function(event, fn){ |
edamame22 | 0:a9bcda5b678a | 1295 | this._callbacks = this._callbacks || {}; |
edamame22 | 0:a9bcda5b678a | 1296 | |
edamame22 | 0:a9bcda5b678a | 1297 | // all |
edamame22 | 0:a9bcda5b678a | 1298 | if (0 == arguments.length) { |
edamame22 | 0:a9bcda5b678a | 1299 | this._callbacks = {}; |
edamame22 | 0:a9bcda5b678a | 1300 | return this; |
edamame22 | 0:a9bcda5b678a | 1301 | } |
edamame22 | 0:a9bcda5b678a | 1302 | |
edamame22 | 0:a9bcda5b678a | 1303 | // specific event |
edamame22 | 0:a9bcda5b678a | 1304 | var callbacks = this._callbacks[event]; |
edamame22 | 0:a9bcda5b678a | 1305 | if (!callbacks) return this; |
edamame22 | 0:a9bcda5b678a | 1306 | |
edamame22 | 0:a9bcda5b678a | 1307 | // remove all handlers |
edamame22 | 0:a9bcda5b678a | 1308 | if (1 == arguments.length) { |
edamame22 | 0:a9bcda5b678a | 1309 | delete this._callbacks[event]; |
edamame22 | 0:a9bcda5b678a | 1310 | return this; |
edamame22 | 0:a9bcda5b678a | 1311 | } |
edamame22 | 0:a9bcda5b678a | 1312 | |
edamame22 | 0:a9bcda5b678a | 1313 | // remove specific handler |
edamame22 | 0:a9bcda5b678a | 1314 | var cb; |
edamame22 | 0:a9bcda5b678a | 1315 | for (var i = 0; i < callbacks.length; i++) { |
edamame22 | 0:a9bcda5b678a | 1316 | cb = callbacks[i]; |
edamame22 | 0:a9bcda5b678a | 1317 | if (cb === fn || cb.fn === fn) { |
edamame22 | 0:a9bcda5b678a | 1318 | callbacks.splice(i, 1); |
edamame22 | 0:a9bcda5b678a | 1319 | break; |
edamame22 | 0:a9bcda5b678a | 1320 | } |
edamame22 | 0:a9bcda5b678a | 1321 | } |
edamame22 | 0:a9bcda5b678a | 1322 | return this; |
edamame22 | 0:a9bcda5b678a | 1323 | }; |
edamame22 | 0:a9bcda5b678a | 1324 | |
edamame22 | 0:a9bcda5b678a | 1325 | /** |
edamame22 | 0:a9bcda5b678a | 1326 | * Emit `event` with the given args. |
edamame22 | 0:a9bcda5b678a | 1327 | * |
edamame22 | 0:a9bcda5b678a | 1328 | * @param {String} event |
edamame22 | 0:a9bcda5b678a | 1329 | * @param {Mixed} ... |
edamame22 | 0:a9bcda5b678a | 1330 | * @return {Emitter} |
edamame22 | 0:a9bcda5b678a | 1331 | */ |
edamame22 | 0:a9bcda5b678a | 1332 | |
edamame22 | 0:a9bcda5b678a | 1333 | Emitter.prototype.emit = function(event){ |
edamame22 | 0:a9bcda5b678a | 1334 | this._callbacks = this._callbacks || {}; |
edamame22 | 0:a9bcda5b678a | 1335 | var args = [].slice.call(arguments, 1) |
edamame22 | 0:a9bcda5b678a | 1336 | , callbacks = this._callbacks[event]; |
edamame22 | 0:a9bcda5b678a | 1337 | |
edamame22 | 0:a9bcda5b678a | 1338 | if (callbacks) { |
edamame22 | 0:a9bcda5b678a | 1339 | callbacks = callbacks.slice(0); |
edamame22 | 0:a9bcda5b678a | 1340 | for (var i = 0, len = callbacks.length; i < len; ++i) { |
edamame22 | 0:a9bcda5b678a | 1341 | callbacks[i].apply(this, args); |
edamame22 | 0:a9bcda5b678a | 1342 | } |
edamame22 | 0:a9bcda5b678a | 1343 | } |
edamame22 | 0:a9bcda5b678a | 1344 | |
edamame22 | 0:a9bcda5b678a | 1345 | return this; |
edamame22 | 0:a9bcda5b678a | 1346 | }; |
edamame22 | 0:a9bcda5b678a | 1347 | |
edamame22 | 0:a9bcda5b678a | 1348 | /** |
edamame22 | 0:a9bcda5b678a | 1349 | * Return array of callbacks for `event`. |
edamame22 | 0:a9bcda5b678a | 1350 | * |
edamame22 | 0:a9bcda5b678a | 1351 | * @param {String} event |
edamame22 | 0:a9bcda5b678a | 1352 | * @return {Array} |
edamame22 | 0:a9bcda5b678a | 1353 | * @api public |
edamame22 | 0:a9bcda5b678a | 1354 | */ |
edamame22 | 0:a9bcda5b678a | 1355 | |
edamame22 | 0:a9bcda5b678a | 1356 | Emitter.prototype.listeners = function(event){ |
edamame22 | 0:a9bcda5b678a | 1357 | this._callbacks = this._callbacks || {}; |
edamame22 | 0:a9bcda5b678a | 1358 | return this._callbacks[event] || []; |
edamame22 | 0:a9bcda5b678a | 1359 | }; |
edamame22 | 0:a9bcda5b678a | 1360 | |
edamame22 | 0:a9bcda5b678a | 1361 | /** |
edamame22 | 0:a9bcda5b678a | 1362 | * Check if this emitter has `event` handlers. |
edamame22 | 0:a9bcda5b678a | 1363 | * |
edamame22 | 0:a9bcda5b678a | 1364 | * @param {String} event |
edamame22 | 0:a9bcda5b678a | 1365 | * @return {Boolean} |
edamame22 | 0:a9bcda5b678a | 1366 | * @api public |
edamame22 | 0:a9bcda5b678a | 1367 | */ |
edamame22 | 0:a9bcda5b678a | 1368 | |
edamame22 | 0:a9bcda5b678a | 1369 | Emitter.prototype.hasListeners = function(event){ |
edamame22 | 0:a9bcda5b678a | 1370 | return !! this.listeners(event).length; |
edamame22 | 0:a9bcda5b678a | 1371 | }; |
edamame22 | 0:a9bcda5b678a | 1372 | |
edamame22 | 0:a9bcda5b678a | 1373 | },{}],10:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1374 | |
edamame22 | 0:a9bcda5b678a | 1375 | /** |
edamame22 | 0:a9bcda5b678a | 1376 | * Expose `debug()` as the module. |
edamame22 | 0:a9bcda5b678a | 1377 | */ |
edamame22 | 0:a9bcda5b678a | 1378 | |
edamame22 | 0:a9bcda5b678a | 1379 | module.exports = debug; |
edamame22 | 0:a9bcda5b678a | 1380 | |
edamame22 | 0:a9bcda5b678a | 1381 | /** |
edamame22 | 0:a9bcda5b678a | 1382 | * Create a debugger with the given `name`. |
edamame22 | 0:a9bcda5b678a | 1383 | * |
edamame22 | 0:a9bcda5b678a | 1384 | * @param {String} name |
edamame22 | 0:a9bcda5b678a | 1385 | * @return {Type} |
edamame22 | 0:a9bcda5b678a | 1386 | * @api public |
edamame22 | 0:a9bcda5b678a | 1387 | */ |
edamame22 | 0:a9bcda5b678a | 1388 | |
edamame22 | 0:a9bcda5b678a | 1389 | function debug(name) { |
edamame22 | 0:a9bcda5b678a | 1390 | if (!debug.enabled(name)) return function(){}; |
edamame22 | 0:a9bcda5b678a | 1391 | |
edamame22 | 0:a9bcda5b678a | 1392 | return function(fmt){ |
edamame22 | 0:a9bcda5b678a | 1393 | fmt = coerce(fmt); |
edamame22 | 0:a9bcda5b678a | 1394 | |
edamame22 | 0:a9bcda5b678a | 1395 | var curr = new Date; |
edamame22 | 0:a9bcda5b678a | 1396 | var ms = curr - (debug[name] || curr); |
edamame22 | 0:a9bcda5b678a | 1397 | debug[name] = curr; |
edamame22 | 0:a9bcda5b678a | 1398 | |
edamame22 | 0:a9bcda5b678a | 1399 | fmt = name |
edamame22 | 0:a9bcda5b678a | 1400 | + ' ' |
edamame22 | 0:a9bcda5b678a | 1401 | + fmt |
edamame22 | 0:a9bcda5b678a | 1402 | + ' +' + debug.humanize(ms); |
edamame22 | 0:a9bcda5b678a | 1403 | |
edamame22 | 0:a9bcda5b678a | 1404 | // This hackery is required for IE8 |
edamame22 | 0:a9bcda5b678a | 1405 | // where `console.log` doesn't have 'apply' |
edamame22 | 0:a9bcda5b678a | 1406 | window.console |
edamame22 | 0:a9bcda5b678a | 1407 | && console.log |
edamame22 | 0:a9bcda5b678a | 1408 | && Function.prototype.apply.call(console.log, console, arguments); |
edamame22 | 0:a9bcda5b678a | 1409 | } |
edamame22 | 0:a9bcda5b678a | 1410 | } |
edamame22 | 0:a9bcda5b678a | 1411 | |
edamame22 | 0:a9bcda5b678a | 1412 | /** |
edamame22 | 0:a9bcda5b678a | 1413 | * The currently active debug mode names. |
edamame22 | 0:a9bcda5b678a | 1414 | */ |
edamame22 | 0:a9bcda5b678a | 1415 | |
edamame22 | 0:a9bcda5b678a | 1416 | debug.names = []; |
edamame22 | 0:a9bcda5b678a | 1417 | debug.skips = []; |
edamame22 | 0:a9bcda5b678a | 1418 | |
edamame22 | 0:a9bcda5b678a | 1419 | /** |
edamame22 | 0:a9bcda5b678a | 1420 | * Enables a debug mode by name. This can include modes |
edamame22 | 0:a9bcda5b678a | 1421 | * separated by a colon and wildcards. |
edamame22 | 0:a9bcda5b678a | 1422 | * |
edamame22 | 0:a9bcda5b678a | 1423 | * @param {String} name |
edamame22 | 0:a9bcda5b678a | 1424 | * @api public |
edamame22 | 0:a9bcda5b678a | 1425 | */ |
edamame22 | 0:a9bcda5b678a | 1426 | |
edamame22 | 0:a9bcda5b678a | 1427 | debug.enable = function(name) { |
edamame22 | 0:a9bcda5b678a | 1428 | try { |
edamame22 | 0:a9bcda5b678a | 1429 | localStorage.debug = name; |
edamame22 | 0:a9bcda5b678a | 1430 | } catch(e){} |
edamame22 | 0:a9bcda5b678a | 1431 | |
edamame22 | 0:a9bcda5b678a | 1432 | var split = (name || '').split(/[\s,]+/) |
edamame22 | 0:a9bcda5b678a | 1433 | , len = split.length; |
edamame22 | 0:a9bcda5b678a | 1434 | |
edamame22 | 0:a9bcda5b678a | 1435 | for (var i = 0; i < len; i++) { |
edamame22 | 0:a9bcda5b678a | 1436 | name = split[i].replace('*', '.*?'); |
edamame22 | 0:a9bcda5b678a | 1437 | if (name[0] === '-') { |
edamame22 | 0:a9bcda5b678a | 1438 | debug.skips.push(new RegExp('^' + name.substr(1) + '$')); |
edamame22 | 0:a9bcda5b678a | 1439 | } |
edamame22 | 0:a9bcda5b678a | 1440 | else { |
edamame22 | 0:a9bcda5b678a | 1441 | debug.names.push(new RegExp('^' + name + '$')); |
edamame22 | 0:a9bcda5b678a | 1442 | } |
edamame22 | 0:a9bcda5b678a | 1443 | } |
edamame22 | 0:a9bcda5b678a | 1444 | }; |
edamame22 | 0:a9bcda5b678a | 1445 | |
edamame22 | 0:a9bcda5b678a | 1446 | /** |
edamame22 | 0:a9bcda5b678a | 1447 | * Disable debug output. |
edamame22 | 0:a9bcda5b678a | 1448 | * |
edamame22 | 0:a9bcda5b678a | 1449 | * @api public |
edamame22 | 0:a9bcda5b678a | 1450 | */ |
edamame22 | 0:a9bcda5b678a | 1451 | |
edamame22 | 0:a9bcda5b678a | 1452 | debug.disable = function(){ |
edamame22 | 0:a9bcda5b678a | 1453 | debug.enable(''); |
edamame22 | 0:a9bcda5b678a | 1454 | }; |
edamame22 | 0:a9bcda5b678a | 1455 | |
edamame22 | 0:a9bcda5b678a | 1456 | /** |
edamame22 | 0:a9bcda5b678a | 1457 | * Humanize the given `ms`. |
edamame22 | 0:a9bcda5b678a | 1458 | * |
edamame22 | 0:a9bcda5b678a | 1459 | * @param {Number} m |
edamame22 | 0:a9bcda5b678a | 1460 | * @return {String} |
edamame22 | 0:a9bcda5b678a | 1461 | * @api private |
edamame22 | 0:a9bcda5b678a | 1462 | */ |
edamame22 | 0:a9bcda5b678a | 1463 | |
edamame22 | 0:a9bcda5b678a | 1464 | debug.humanize = function(ms) { |
edamame22 | 0:a9bcda5b678a | 1465 | var sec = 1000 |
edamame22 | 0:a9bcda5b678a | 1466 | , min = 60 * 1000 |
edamame22 | 0:a9bcda5b678a | 1467 | , hour = 60 * min; |
edamame22 | 0:a9bcda5b678a | 1468 | |
edamame22 | 0:a9bcda5b678a | 1469 | if (ms >= hour) return (ms / hour).toFixed(1) + 'h'; |
edamame22 | 0:a9bcda5b678a | 1470 | if (ms >= min) return (ms / min).toFixed(1) + 'm'; |
edamame22 | 0:a9bcda5b678a | 1471 | if (ms >= sec) return (ms / sec | 0) + 's'; |
edamame22 | 0:a9bcda5b678a | 1472 | return ms + 'ms'; |
edamame22 | 0:a9bcda5b678a | 1473 | }; |
edamame22 | 0:a9bcda5b678a | 1474 | |
edamame22 | 0:a9bcda5b678a | 1475 | /** |
edamame22 | 0:a9bcda5b678a | 1476 | * Returns true if the given mode name is enabled, false otherwise. |
edamame22 | 0:a9bcda5b678a | 1477 | * |
edamame22 | 0:a9bcda5b678a | 1478 | * @param {String} name |
edamame22 | 0:a9bcda5b678a | 1479 | * @return {Boolean} |
edamame22 | 0:a9bcda5b678a | 1480 | * @api public |
edamame22 | 0:a9bcda5b678a | 1481 | */ |
edamame22 | 0:a9bcda5b678a | 1482 | |
edamame22 | 0:a9bcda5b678a | 1483 | debug.enabled = function(name) { |
edamame22 | 0:a9bcda5b678a | 1484 | for (var i = 0, len = debug.skips.length; i < len; i++) { |
edamame22 | 0:a9bcda5b678a | 1485 | if (debug.skips[i].test(name)) { |
edamame22 | 0:a9bcda5b678a | 1486 | return false; |
edamame22 | 0:a9bcda5b678a | 1487 | } |
edamame22 | 0:a9bcda5b678a | 1488 | } |
edamame22 | 0:a9bcda5b678a | 1489 | for (var i = 0, len = debug.names.length; i < len; i++) { |
edamame22 | 0:a9bcda5b678a | 1490 | if (debug.names[i].test(name)) { |
edamame22 | 0:a9bcda5b678a | 1491 | return true; |
edamame22 | 0:a9bcda5b678a | 1492 | } |
edamame22 | 0:a9bcda5b678a | 1493 | } |
edamame22 | 0:a9bcda5b678a | 1494 | return false; |
edamame22 | 0:a9bcda5b678a | 1495 | }; |
edamame22 | 0:a9bcda5b678a | 1496 | |
edamame22 | 0:a9bcda5b678a | 1497 | /** |
edamame22 | 0:a9bcda5b678a | 1498 | * Coerce `val`. |
edamame22 | 0:a9bcda5b678a | 1499 | */ |
edamame22 | 0:a9bcda5b678a | 1500 | |
edamame22 | 0:a9bcda5b678a | 1501 | function coerce(val) { |
edamame22 | 0:a9bcda5b678a | 1502 | if (val instanceof Error) return val.stack || val.message; |
edamame22 | 0:a9bcda5b678a | 1503 | return val; |
edamame22 | 0:a9bcda5b678a | 1504 | } |
edamame22 | 0:a9bcda5b678a | 1505 | |
edamame22 | 0:a9bcda5b678a | 1506 | // persist |
edamame22 | 0:a9bcda5b678a | 1507 | |
edamame22 | 0:a9bcda5b678a | 1508 | try { |
edamame22 | 0:a9bcda5b678a | 1509 | if (window.localStorage) debug.enable(localStorage.debug); |
edamame22 | 0:a9bcda5b678a | 1510 | } catch(e){} |
edamame22 | 0:a9bcda5b678a | 1511 | |
edamame22 | 0:a9bcda5b678a | 1512 | },{}],11:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1513 | |
edamame22 | 0:a9bcda5b678a | 1514 | module.exports = _dereq_('./lib/'); |
edamame22 | 0:a9bcda5b678a | 1515 | |
edamame22 | 0:a9bcda5b678a | 1516 | },{"./lib/":12}],12:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1517 | |
edamame22 | 0:a9bcda5b678a | 1518 | module.exports = _dereq_('./socket'); |
edamame22 | 0:a9bcda5b678a | 1519 | |
edamame22 | 0:a9bcda5b678a | 1520 | /** |
edamame22 | 0:a9bcda5b678a | 1521 | * Exports parser |
edamame22 | 0:a9bcda5b678a | 1522 | * |
edamame22 | 0:a9bcda5b678a | 1523 | * @api public |
edamame22 | 0:a9bcda5b678a | 1524 | * |
edamame22 | 0:a9bcda5b678a | 1525 | */ |
edamame22 | 0:a9bcda5b678a | 1526 | module.exports.parser = _dereq_('engine.io-parser'); |
edamame22 | 0:a9bcda5b678a | 1527 | |
edamame22 | 0:a9bcda5b678a | 1528 | },{"./socket":13,"engine.io-parser":25}],13:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 1529 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 1530 | /** |
edamame22 | 0:a9bcda5b678a | 1531 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 1532 | */ |
edamame22 | 0:a9bcda5b678a | 1533 | |
edamame22 | 0:a9bcda5b678a | 1534 | var transports = _dereq_('./transports'); |
edamame22 | 0:a9bcda5b678a | 1535 | var Emitter = _dereq_('component-emitter'); |
edamame22 | 0:a9bcda5b678a | 1536 | var debug = _dereq_('debug')('engine.io-client:socket'); |
edamame22 | 0:a9bcda5b678a | 1537 | var index = _dereq_('indexof'); |
edamame22 | 0:a9bcda5b678a | 1538 | var parser = _dereq_('engine.io-parser'); |
edamame22 | 0:a9bcda5b678a | 1539 | var parseuri = _dereq_('parseuri'); |
edamame22 | 0:a9bcda5b678a | 1540 | var parsejson = _dereq_('parsejson'); |
edamame22 | 0:a9bcda5b678a | 1541 | var parseqs = _dereq_('parseqs'); |
edamame22 | 0:a9bcda5b678a | 1542 | |
edamame22 | 0:a9bcda5b678a | 1543 | /** |
edamame22 | 0:a9bcda5b678a | 1544 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 1545 | */ |
edamame22 | 0:a9bcda5b678a | 1546 | |
edamame22 | 0:a9bcda5b678a | 1547 | module.exports = Socket; |
edamame22 | 0:a9bcda5b678a | 1548 | |
edamame22 | 0:a9bcda5b678a | 1549 | /** |
edamame22 | 0:a9bcda5b678a | 1550 | * Noop function. |
edamame22 | 0:a9bcda5b678a | 1551 | * |
edamame22 | 0:a9bcda5b678a | 1552 | * @api private |
edamame22 | 0:a9bcda5b678a | 1553 | */ |
edamame22 | 0:a9bcda5b678a | 1554 | |
edamame22 | 0:a9bcda5b678a | 1555 | function noop(){} |
edamame22 | 0:a9bcda5b678a | 1556 | |
edamame22 | 0:a9bcda5b678a | 1557 | /** |
edamame22 | 0:a9bcda5b678a | 1558 | * Socket constructor. |
edamame22 | 0:a9bcda5b678a | 1559 | * |
edamame22 | 0:a9bcda5b678a | 1560 | * @param {String|Object} uri or options |
edamame22 | 0:a9bcda5b678a | 1561 | * @param {Object} options |
edamame22 | 0:a9bcda5b678a | 1562 | * @api public |
edamame22 | 0:a9bcda5b678a | 1563 | */ |
edamame22 | 0:a9bcda5b678a | 1564 | |
edamame22 | 0:a9bcda5b678a | 1565 | function Socket(uri, opts){ |
edamame22 | 0:a9bcda5b678a | 1566 | if (!(this instanceof Socket)) return new Socket(uri, opts); |
edamame22 | 0:a9bcda5b678a | 1567 | |
edamame22 | 0:a9bcda5b678a | 1568 | opts = opts || {}; |
edamame22 | 0:a9bcda5b678a | 1569 | |
edamame22 | 0:a9bcda5b678a | 1570 | if (uri && 'object' == typeof uri) { |
edamame22 | 0:a9bcda5b678a | 1571 | opts = uri; |
edamame22 | 0:a9bcda5b678a | 1572 | uri = null; |
edamame22 | 0:a9bcda5b678a | 1573 | } |
edamame22 | 0:a9bcda5b678a | 1574 | |
edamame22 | 0:a9bcda5b678a | 1575 | if (uri) { |
edamame22 | 0:a9bcda5b678a | 1576 | uri = parseuri(uri); |
edamame22 | 0:a9bcda5b678a | 1577 | opts.host = uri.host; |
edamame22 | 0:a9bcda5b678a | 1578 | opts.secure = uri.protocol == 'https' || uri.protocol == 'wss'; |
edamame22 | 0:a9bcda5b678a | 1579 | opts.port = uri.port; |
edamame22 | 0:a9bcda5b678a | 1580 | if (uri.query) opts.query = uri.query; |
edamame22 | 0:a9bcda5b678a | 1581 | } |
edamame22 | 0:a9bcda5b678a | 1582 | |
edamame22 | 0:a9bcda5b678a | 1583 | this.secure = null != opts.secure ? opts.secure : |
edamame22 | 0:a9bcda5b678a | 1584 | (global.location && 'https:' == location.protocol); |
edamame22 | 0:a9bcda5b678a | 1585 | |
edamame22 | 0:a9bcda5b678a | 1586 | if (opts.host) { |
edamame22 | 0:a9bcda5b678a | 1587 | var pieces = opts.host.split(':'); |
edamame22 | 0:a9bcda5b678a | 1588 | opts.hostname = pieces.shift(); |
edamame22 | 0:a9bcda5b678a | 1589 | if (pieces.length) { |
edamame22 | 0:a9bcda5b678a | 1590 | opts.port = pieces.pop(); |
edamame22 | 0:a9bcda5b678a | 1591 | } else if (!opts.port) { |
edamame22 | 0:a9bcda5b678a | 1592 | // if no port is specified manually, use the protocol default |
edamame22 | 0:a9bcda5b678a | 1593 | opts.port = this.secure ? '443' : '80'; |
edamame22 | 0:a9bcda5b678a | 1594 | } |
edamame22 | 0:a9bcda5b678a | 1595 | } |
edamame22 | 0:a9bcda5b678a | 1596 | |
edamame22 | 0:a9bcda5b678a | 1597 | this.agent = opts.agent || false; |
edamame22 | 0:a9bcda5b678a | 1598 | this.hostname = opts.hostname || |
edamame22 | 0:a9bcda5b678a | 1599 | (global.location ? location.hostname : 'localhost'); |
edamame22 | 0:a9bcda5b678a | 1600 | this.port = opts.port || (global.location && location.port ? |
edamame22 | 0:a9bcda5b678a | 1601 | location.port : |
edamame22 | 0:a9bcda5b678a | 1602 | (this.secure ? 443 : 80)); |
edamame22 | 0:a9bcda5b678a | 1603 | this.query = opts.query || {}; |
edamame22 | 0:a9bcda5b678a | 1604 | if ('string' == typeof this.query) this.query = parseqs.decode(this.query); |
edamame22 | 0:a9bcda5b678a | 1605 | this.upgrade = false !== opts.upgrade; |
edamame22 | 0:a9bcda5b678a | 1606 | this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/'; |
edamame22 | 0:a9bcda5b678a | 1607 | this.forceJSONP = !!opts.forceJSONP; |
edamame22 | 0:a9bcda5b678a | 1608 | this.jsonp = false !== opts.jsonp; |
edamame22 | 0:a9bcda5b678a | 1609 | this.forceBase64 = !!opts.forceBase64; |
edamame22 | 0:a9bcda5b678a | 1610 | this.enablesXDR = !!opts.enablesXDR; |
edamame22 | 0:a9bcda5b678a | 1611 | this.timestampParam = opts.timestampParam || 't'; |
edamame22 | 0:a9bcda5b678a | 1612 | this.timestampRequests = opts.timestampRequests; |
edamame22 | 0:a9bcda5b678a | 1613 | this.transports = opts.transports || ['polling', 'websocket']; |
edamame22 | 0:a9bcda5b678a | 1614 | this.readyState = ''; |
edamame22 | 0:a9bcda5b678a | 1615 | this.writeBuffer = []; |
edamame22 | 0:a9bcda5b678a | 1616 | this.callbackBuffer = []; |
edamame22 | 0:a9bcda5b678a | 1617 | this.policyPort = opts.policyPort || 843; |
edamame22 | 0:a9bcda5b678a | 1618 | this.rememberUpgrade = opts.rememberUpgrade || false; |
edamame22 | 0:a9bcda5b678a | 1619 | this.binaryType = null; |
edamame22 | 0:a9bcda5b678a | 1620 | this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades; |
edamame22 | 0:a9bcda5b678a | 1621 | |
edamame22 | 0:a9bcda5b678a | 1622 | // SSL options for Node.js client |
edamame22 | 0:a9bcda5b678a | 1623 | this.pfx = opts.pfx || null; |
edamame22 | 0:a9bcda5b678a | 1624 | this.key = opts.key || null; |
edamame22 | 0:a9bcda5b678a | 1625 | this.passphrase = opts.passphrase || null; |
edamame22 | 0:a9bcda5b678a | 1626 | this.cert = opts.cert || null; |
edamame22 | 0:a9bcda5b678a | 1627 | this.ca = opts.ca || null; |
edamame22 | 0:a9bcda5b678a | 1628 | this.ciphers = opts.ciphers || null; |
edamame22 | 0:a9bcda5b678a | 1629 | this.rejectUnauthorized = opts.rejectUnauthorized || null; |
edamame22 | 0:a9bcda5b678a | 1630 | |
edamame22 | 0:a9bcda5b678a | 1631 | this.open(); |
edamame22 | 0:a9bcda5b678a | 1632 | } |
edamame22 | 0:a9bcda5b678a | 1633 | |
edamame22 | 0:a9bcda5b678a | 1634 | Socket.priorWebsocketSuccess = false; |
edamame22 | 0:a9bcda5b678a | 1635 | |
edamame22 | 0:a9bcda5b678a | 1636 | /** |
edamame22 | 0:a9bcda5b678a | 1637 | * Mix in `Emitter`. |
edamame22 | 0:a9bcda5b678a | 1638 | */ |
edamame22 | 0:a9bcda5b678a | 1639 | |
edamame22 | 0:a9bcda5b678a | 1640 | Emitter(Socket.prototype); |
edamame22 | 0:a9bcda5b678a | 1641 | |
edamame22 | 0:a9bcda5b678a | 1642 | /** |
edamame22 | 0:a9bcda5b678a | 1643 | * Protocol version. |
edamame22 | 0:a9bcda5b678a | 1644 | * |
edamame22 | 0:a9bcda5b678a | 1645 | * @api public |
edamame22 | 0:a9bcda5b678a | 1646 | */ |
edamame22 | 0:a9bcda5b678a | 1647 | |
edamame22 | 0:a9bcda5b678a | 1648 | Socket.protocol = parser.protocol; // this is an int |
edamame22 | 0:a9bcda5b678a | 1649 | |
edamame22 | 0:a9bcda5b678a | 1650 | /** |
edamame22 | 0:a9bcda5b678a | 1651 | * Expose deps for legacy compatibility |
edamame22 | 0:a9bcda5b678a | 1652 | * and standalone browser access. |
edamame22 | 0:a9bcda5b678a | 1653 | */ |
edamame22 | 0:a9bcda5b678a | 1654 | |
edamame22 | 0:a9bcda5b678a | 1655 | Socket.Socket = Socket; |
edamame22 | 0:a9bcda5b678a | 1656 | Socket.Transport = _dereq_('./transport'); |
edamame22 | 0:a9bcda5b678a | 1657 | Socket.transports = _dereq_('./transports'); |
edamame22 | 0:a9bcda5b678a | 1658 | Socket.parser = _dereq_('engine.io-parser'); |
edamame22 | 0:a9bcda5b678a | 1659 | |
edamame22 | 0:a9bcda5b678a | 1660 | /** |
edamame22 | 0:a9bcda5b678a | 1661 | * Creates transport of the given type. |
edamame22 | 0:a9bcda5b678a | 1662 | * |
edamame22 | 0:a9bcda5b678a | 1663 | * @param {String} transport name |
edamame22 | 0:a9bcda5b678a | 1664 | * @return {Transport} |
edamame22 | 0:a9bcda5b678a | 1665 | * @api private |
edamame22 | 0:a9bcda5b678a | 1666 | */ |
edamame22 | 0:a9bcda5b678a | 1667 | |
edamame22 | 0:a9bcda5b678a | 1668 | Socket.prototype.createTransport = function (name) { |
edamame22 | 0:a9bcda5b678a | 1669 | debug('creating transport "%s"', name); |
edamame22 | 0:a9bcda5b678a | 1670 | var query = clone(this.query); |
edamame22 | 0:a9bcda5b678a | 1671 | |
edamame22 | 0:a9bcda5b678a | 1672 | // append engine.io protocol identifier |
edamame22 | 0:a9bcda5b678a | 1673 | query.EIO = parser.protocol; |
edamame22 | 0:a9bcda5b678a | 1674 | |
edamame22 | 0:a9bcda5b678a | 1675 | // transport name |
edamame22 | 0:a9bcda5b678a | 1676 | query.transport = name; |
edamame22 | 0:a9bcda5b678a | 1677 | |
edamame22 | 0:a9bcda5b678a | 1678 | // session id if we already have one |
edamame22 | 0:a9bcda5b678a | 1679 | if (this.id) query.sid = this.id; |
edamame22 | 0:a9bcda5b678a | 1680 | |
edamame22 | 0:a9bcda5b678a | 1681 | var transport = new transports[name]({ |
edamame22 | 0:a9bcda5b678a | 1682 | agent: this.agent, |
edamame22 | 0:a9bcda5b678a | 1683 | hostname: this.hostname, |
edamame22 | 0:a9bcda5b678a | 1684 | port: this.port, |
edamame22 | 0:a9bcda5b678a | 1685 | secure: this.secure, |
edamame22 | 0:a9bcda5b678a | 1686 | path: this.path, |
edamame22 | 0:a9bcda5b678a | 1687 | query: query, |
edamame22 | 0:a9bcda5b678a | 1688 | forceJSONP: this.forceJSONP, |
edamame22 | 0:a9bcda5b678a | 1689 | jsonp: this.jsonp, |
edamame22 | 0:a9bcda5b678a | 1690 | forceBase64: this.forceBase64, |
edamame22 | 0:a9bcda5b678a | 1691 | enablesXDR: this.enablesXDR, |
edamame22 | 0:a9bcda5b678a | 1692 | timestampRequests: this.timestampRequests, |
edamame22 | 0:a9bcda5b678a | 1693 | timestampParam: this.timestampParam, |
edamame22 | 0:a9bcda5b678a | 1694 | policyPort: this.policyPort, |
edamame22 | 0:a9bcda5b678a | 1695 | socket: this, |
edamame22 | 0:a9bcda5b678a | 1696 | pfx: this.pfx, |
edamame22 | 0:a9bcda5b678a | 1697 | key: this.key, |
edamame22 | 0:a9bcda5b678a | 1698 | passphrase: this.passphrase, |
edamame22 | 0:a9bcda5b678a | 1699 | cert: this.cert, |
edamame22 | 0:a9bcda5b678a | 1700 | ca: this.ca, |
edamame22 | 0:a9bcda5b678a | 1701 | ciphers: this.ciphers, |
edamame22 | 0:a9bcda5b678a | 1702 | rejectUnauthorized: this.rejectUnauthorized |
edamame22 | 0:a9bcda5b678a | 1703 | }); |
edamame22 | 0:a9bcda5b678a | 1704 | |
edamame22 | 0:a9bcda5b678a | 1705 | return transport; |
edamame22 | 0:a9bcda5b678a | 1706 | }; |
edamame22 | 0:a9bcda5b678a | 1707 | |
edamame22 | 0:a9bcda5b678a | 1708 | function clone (obj) { |
edamame22 | 0:a9bcda5b678a | 1709 | var o = {}; |
edamame22 | 0:a9bcda5b678a | 1710 | for (var i in obj) { |
edamame22 | 0:a9bcda5b678a | 1711 | if (obj.hasOwnProperty(i)) { |
edamame22 | 0:a9bcda5b678a | 1712 | o[i] = obj[i]; |
edamame22 | 0:a9bcda5b678a | 1713 | } |
edamame22 | 0:a9bcda5b678a | 1714 | } |
edamame22 | 0:a9bcda5b678a | 1715 | return o; |
edamame22 | 0:a9bcda5b678a | 1716 | } |
edamame22 | 0:a9bcda5b678a | 1717 | |
edamame22 | 0:a9bcda5b678a | 1718 | /** |
edamame22 | 0:a9bcda5b678a | 1719 | * Initializes transport to use and starts probe. |
edamame22 | 0:a9bcda5b678a | 1720 | * |
edamame22 | 0:a9bcda5b678a | 1721 | * @api private |
edamame22 | 0:a9bcda5b678a | 1722 | */ |
edamame22 | 0:a9bcda5b678a | 1723 | Socket.prototype.open = function () { |
edamame22 | 0:a9bcda5b678a | 1724 | var transport; |
edamame22 | 0:a9bcda5b678a | 1725 | if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) { |
edamame22 | 0:a9bcda5b678a | 1726 | transport = 'websocket'; |
edamame22 | 0:a9bcda5b678a | 1727 | } else if (0 == this.transports.length) { |
edamame22 | 0:a9bcda5b678a | 1728 | // Emit error on next tick so it can be listened to |
edamame22 | 0:a9bcda5b678a | 1729 | var self = this; |
edamame22 | 0:a9bcda5b678a | 1730 | setTimeout(function() { |
edamame22 | 0:a9bcda5b678a | 1731 | self.emit('error', 'No transports available'); |
edamame22 | 0:a9bcda5b678a | 1732 | }, 0); |
edamame22 | 0:a9bcda5b678a | 1733 | return; |
edamame22 | 0:a9bcda5b678a | 1734 | } else { |
edamame22 | 0:a9bcda5b678a | 1735 | transport = this.transports[0]; |
edamame22 | 0:a9bcda5b678a | 1736 | } |
edamame22 | 0:a9bcda5b678a | 1737 | this.readyState = 'opening'; |
edamame22 | 0:a9bcda5b678a | 1738 | |
edamame22 | 0:a9bcda5b678a | 1739 | // Retry with the next transport if the transport is disabled (jsonp: false) |
edamame22 | 0:a9bcda5b678a | 1740 | var transport; |
edamame22 | 0:a9bcda5b678a | 1741 | try { |
edamame22 | 0:a9bcda5b678a | 1742 | transport = this.createTransport(transport); |
edamame22 | 0:a9bcda5b678a | 1743 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 1744 | this.transports.shift(); |
edamame22 | 0:a9bcda5b678a | 1745 | this.open(); |
edamame22 | 0:a9bcda5b678a | 1746 | return; |
edamame22 | 0:a9bcda5b678a | 1747 | } |
edamame22 | 0:a9bcda5b678a | 1748 | |
edamame22 | 0:a9bcda5b678a | 1749 | transport.open(); |
edamame22 | 0:a9bcda5b678a | 1750 | this.setTransport(transport); |
edamame22 | 0:a9bcda5b678a | 1751 | }; |
edamame22 | 0:a9bcda5b678a | 1752 | |
edamame22 | 0:a9bcda5b678a | 1753 | /** |
edamame22 | 0:a9bcda5b678a | 1754 | * Sets the current transport. Disables the existing one (if any). |
edamame22 | 0:a9bcda5b678a | 1755 | * |
edamame22 | 0:a9bcda5b678a | 1756 | * @api private |
edamame22 | 0:a9bcda5b678a | 1757 | */ |
edamame22 | 0:a9bcda5b678a | 1758 | |
edamame22 | 0:a9bcda5b678a | 1759 | Socket.prototype.setTransport = function(transport){ |
edamame22 | 0:a9bcda5b678a | 1760 | debug('setting transport %s', transport.name); |
edamame22 | 0:a9bcda5b678a | 1761 | var self = this; |
edamame22 | 0:a9bcda5b678a | 1762 | |
edamame22 | 0:a9bcda5b678a | 1763 | if (this.transport) { |
edamame22 | 0:a9bcda5b678a | 1764 | debug('clearing existing transport %s', this.transport.name); |
edamame22 | 0:a9bcda5b678a | 1765 | this.transport.removeAllListeners(); |
edamame22 | 0:a9bcda5b678a | 1766 | } |
edamame22 | 0:a9bcda5b678a | 1767 | |
edamame22 | 0:a9bcda5b678a | 1768 | // set up transport |
edamame22 | 0:a9bcda5b678a | 1769 | this.transport = transport; |
edamame22 | 0:a9bcda5b678a | 1770 | |
edamame22 | 0:a9bcda5b678a | 1771 | // set up transport listeners |
edamame22 | 0:a9bcda5b678a | 1772 | transport |
edamame22 | 0:a9bcda5b678a | 1773 | .on('drain', function(){ |
edamame22 | 0:a9bcda5b678a | 1774 | self.onDrain(); |
edamame22 | 0:a9bcda5b678a | 1775 | }) |
edamame22 | 0:a9bcda5b678a | 1776 | .on('packet', function(packet){ |
edamame22 | 0:a9bcda5b678a | 1777 | self.onPacket(packet); |
edamame22 | 0:a9bcda5b678a | 1778 | }) |
edamame22 | 0:a9bcda5b678a | 1779 | .on('error', function(e){ |
edamame22 | 0:a9bcda5b678a | 1780 | self.onError(e); |
edamame22 | 0:a9bcda5b678a | 1781 | }) |
edamame22 | 0:a9bcda5b678a | 1782 | .on('close', function(){ |
edamame22 | 0:a9bcda5b678a | 1783 | self.onClose('transport close'); |
edamame22 | 0:a9bcda5b678a | 1784 | }); |
edamame22 | 0:a9bcda5b678a | 1785 | }; |
edamame22 | 0:a9bcda5b678a | 1786 | |
edamame22 | 0:a9bcda5b678a | 1787 | /** |
edamame22 | 0:a9bcda5b678a | 1788 | * Probes a transport. |
edamame22 | 0:a9bcda5b678a | 1789 | * |
edamame22 | 0:a9bcda5b678a | 1790 | * @param {String} transport name |
edamame22 | 0:a9bcda5b678a | 1791 | * @api private |
edamame22 | 0:a9bcda5b678a | 1792 | */ |
edamame22 | 0:a9bcda5b678a | 1793 | |
edamame22 | 0:a9bcda5b678a | 1794 | Socket.prototype.probe = function (name) { |
edamame22 | 0:a9bcda5b678a | 1795 | debug('probing transport "%s"', name); |
edamame22 | 0:a9bcda5b678a | 1796 | var transport = this.createTransport(name, { probe: 1 }) |
edamame22 | 0:a9bcda5b678a | 1797 | , failed = false |
edamame22 | 0:a9bcda5b678a | 1798 | , self = this; |
edamame22 | 0:a9bcda5b678a | 1799 | |
edamame22 | 0:a9bcda5b678a | 1800 | Socket.priorWebsocketSuccess = false; |
edamame22 | 0:a9bcda5b678a | 1801 | |
edamame22 | 0:a9bcda5b678a | 1802 | function onTransportOpen(){ |
edamame22 | 0:a9bcda5b678a | 1803 | if (self.onlyBinaryUpgrades) { |
edamame22 | 0:a9bcda5b678a | 1804 | var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary; |
edamame22 | 0:a9bcda5b678a | 1805 | failed = failed || upgradeLosesBinary; |
edamame22 | 0:a9bcda5b678a | 1806 | } |
edamame22 | 0:a9bcda5b678a | 1807 | if (failed) return; |
edamame22 | 0:a9bcda5b678a | 1808 | |
edamame22 | 0:a9bcda5b678a | 1809 | debug('probe transport "%s" opened', name); |
edamame22 | 0:a9bcda5b678a | 1810 | transport.send([{ type: 'ping', data: 'probe' }]); |
edamame22 | 0:a9bcda5b678a | 1811 | transport.once('packet', function (msg) { |
edamame22 | 0:a9bcda5b678a | 1812 | if (failed) return; |
edamame22 | 0:a9bcda5b678a | 1813 | if ('pong' == msg.type && 'probe' == msg.data) { |
edamame22 | 0:a9bcda5b678a | 1814 | debug('probe transport "%s" pong', name); |
edamame22 | 0:a9bcda5b678a | 1815 | self.upgrading = true; |
edamame22 | 0:a9bcda5b678a | 1816 | self.emit('upgrading', transport); |
edamame22 | 0:a9bcda5b678a | 1817 | if (!transport) return; |
edamame22 | 0:a9bcda5b678a | 1818 | Socket.priorWebsocketSuccess = 'websocket' == transport.name; |
edamame22 | 0:a9bcda5b678a | 1819 | |
edamame22 | 0:a9bcda5b678a | 1820 | debug('pausing current transport "%s"', self.transport.name); |
edamame22 | 0:a9bcda5b678a | 1821 | self.transport.pause(function () { |
edamame22 | 0:a9bcda5b678a | 1822 | if (failed) return; |
edamame22 | 0:a9bcda5b678a | 1823 | if ('closed' == self.readyState) return; |
edamame22 | 0:a9bcda5b678a | 1824 | debug('changing transport and sending upgrade packet'); |
edamame22 | 0:a9bcda5b678a | 1825 | |
edamame22 | 0:a9bcda5b678a | 1826 | cleanup(); |
edamame22 | 0:a9bcda5b678a | 1827 | |
edamame22 | 0:a9bcda5b678a | 1828 | self.setTransport(transport); |
edamame22 | 0:a9bcda5b678a | 1829 | transport.send([{ type: 'upgrade' }]); |
edamame22 | 0:a9bcda5b678a | 1830 | self.emit('upgrade', transport); |
edamame22 | 0:a9bcda5b678a | 1831 | transport = null; |
edamame22 | 0:a9bcda5b678a | 1832 | self.upgrading = false; |
edamame22 | 0:a9bcda5b678a | 1833 | self.flush(); |
edamame22 | 0:a9bcda5b678a | 1834 | }); |
edamame22 | 0:a9bcda5b678a | 1835 | } else { |
edamame22 | 0:a9bcda5b678a | 1836 | debug('probe transport "%s" failed', name); |
edamame22 | 0:a9bcda5b678a | 1837 | var err = new Error('probe error'); |
edamame22 | 0:a9bcda5b678a | 1838 | err.transport = transport.name; |
edamame22 | 0:a9bcda5b678a | 1839 | self.emit('upgradeError', err); |
edamame22 | 0:a9bcda5b678a | 1840 | } |
edamame22 | 0:a9bcda5b678a | 1841 | }); |
edamame22 | 0:a9bcda5b678a | 1842 | } |
edamame22 | 0:a9bcda5b678a | 1843 | |
edamame22 | 0:a9bcda5b678a | 1844 | function freezeTransport() { |
edamame22 | 0:a9bcda5b678a | 1845 | if (failed) return; |
edamame22 | 0:a9bcda5b678a | 1846 | |
edamame22 | 0:a9bcda5b678a | 1847 | // Any callback called by transport should be ignored since now |
edamame22 | 0:a9bcda5b678a | 1848 | failed = true; |
edamame22 | 0:a9bcda5b678a | 1849 | |
edamame22 | 0:a9bcda5b678a | 1850 | cleanup(); |
edamame22 | 0:a9bcda5b678a | 1851 | |
edamame22 | 0:a9bcda5b678a | 1852 | transport.close(); |
edamame22 | 0:a9bcda5b678a | 1853 | transport = null; |
edamame22 | 0:a9bcda5b678a | 1854 | } |
edamame22 | 0:a9bcda5b678a | 1855 | |
edamame22 | 0:a9bcda5b678a | 1856 | //Handle any error that happens while probing |
edamame22 | 0:a9bcda5b678a | 1857 | function onerror(err) { |
edamame22 | 0:a9bcda5b678a | 1858 | var error = new Error('probe error: ' + err); |
edamame22 | 0:a9bcda5b678a | 1859 | error.transport = transport.name; |
edamame22 | 0:a9bcda5b678a | 1860 | |
edamame22 | 0:a9bcda5b678a | 1861 | freezeTransport(); |
edamame22 | 0:a9bcda5b678a | 1862 | |
edamame22 | 0:a9bcda5b678a | 1863 | debug('probe transport "%s" failed because of error: %s', name, err); |
edamame22 | 0:a9bcda5b678a | 1864 | |
edamame22 | 0:a9bcda5b678a | 1865 | self.emit('upgradeError', error); |
edamame22 | 0:a9bcda5b678a | 1866 | } |
edamame22 | 0:a9bcda5b678a | 1867 | |
edamame22 | 0:a9bcda5b678a | 1868 | function onTransportClose(){ |
edamame22 | 0:a9bcda5b678a | 1869 | onerror("transport closed"); |
edamame22 | 0:a9bcda5b678a | 1870 | } |
edamame22 | 0:a9bcda5b678a | 1871 | |
edamame22 | 0:a9bcda5b678a | 1872 | //When the socket is closed while we're probing |
edamame22 | 0:a9bcda5b678a | 1873 | function onclose(){ |
edamame22 | 0:a9bcda5b678a | 1874 | onerror("socket closed"); |
edamame22 | 0:a9bcda5b678a | 1875 | } |
edamame22 | 0:a9bcda5b678a | 1876 | |
edamame22 | 0:a9bcda5b678a | 1877 | //When the socket is upgraded while we're probing |
edamame22 | 0:a9bcda5b678a | 1878 | function onupgrade(to){ |
edamame22 | 0:a9bcda5b678a | 1879 | if (transport && to.name != transport.name) { |
edamame22 | 0:a9bcda5b678a | 1880 | debug('"%s" works - aborting "%s"', to.name, transport.name); |
edamame22 | 0:a9bcda5b678a | 1881 | freezeTransport(); |
edamame22 | 0:a9bcda5b678a | 1882 | } |
edamame22 | 0:a9bcda5b678a | 1883 | } |
edamame22 | 0:a9bcda5b678a | 1884 | |
edamame22 | 0:a9bcda5b678a | 1885 | //Remove all listeners on the transport and on self |
edamame22 | 0:a9bcda5b678a | 1886 | function cleanup(){ |
edamame22 | 0:a9bcda5b678a | 1887 | transport.removeListener('open', onTransportOpen); |
edamame22 | 0:a9bcda5b678a | 1888 | transport.removeListener('error', onerror); |
edamame22 | 0:a9bcda5b678a | 1889 | transport.removeListener('close', onTransportClose); |
edamame22 | 0:a9bcda5b678a | 1890 | self.removeListener('close', onclose); |
edamame22 | 0:a9bcda5b678a | 1891 | self.removeListener('upgrading', onupgrade); |
edamame22 | 0:a9bcda5b678a | 1892 | } |
edamame22 | 0:a9bcda5b678a | 1893 | |
edamame22 | 0:a9bcda5b678a | 1894 | transport.once('open', onTransportOpen); |
edamame22 | 0:a9bcda5b678a | 1895 | transport.once('error', onerror); |
edamame22 | 0:a9bcda5b678a | 1896 | transport.once('close', onTransportClose); |
edamame22 | 0:a9bcda5b678a | 1897 | |
edamame22 | 0:a9bcda5b678a | 1898 | this.once('close', onclose); |
edamame22 | 0:a9bcda5b678a | 1899 | this.once('upgrading', onupgrade); |
edamame22 | 0:a9bcda5b678a | 1900 | |
edamame22 | 0:a9bcda5b678a | 1901 | transport.open(); |
edamame22 | 0:a9bcda5b678a | 1902 | |
edamame22 | 0:a9bcda5b678a | 1903 | }; |
edamame22 | 0:a9bcda5b678a | 1904 | |
edamame22 | 0:a9bcda5b678a | 1905 | /** |
edamame22 | 0:a9bcda5b678a | 1906 | * Called when connection is deemed open. |
edamame22 | 0:a9bcda5b678a | 1907 | * |
edamame22 | 0:a9bcda5b678a | 1908 | * @api public |
edamame22 | 0:a9bcda5b678a | 1909 | */ |
edamame22 | 0:a9bcda5b678a | 1910 | |
edamame22 | 0:a9bcda5b678a | 1911 | Socket.prototype.onOpen = function () { |
edamame22 | 0:a9bcda5b678a | 1912 | debug('socket open'); |
edamame22 | 0:a9bcda5b678a | 1913 | this.readyState = 'open'; |
edamame22 | 0:a9bcda5b678a | 1914 | Socket.priorWebsocketSuccess = 'websocket' == this.transport.name; |
edamame22 | 0:a9bcda5b678a | 1915 | this.emit('open'); |
edamame22 | 0:a9bcda5b678a | 1916 | this.flush(); |
edamame22 | 0:a9bcda5b678a | 1917 | |
edamame22 | 0:a9bcda5b678a | 1918 | // we check for `readyState` in case an `open` |
edamame22 | 0:a9bcda5b678a | 1919 | // listener already closed the socket |
edamame22 | 0:a9bcda5b678a | 1920 | if ('open' == this.readyState && this.upgrade && this.transport.pause) { |
edamame22 | 0:a9bcda5b678a | 1921 | debug('starting upgrade probes'); |
edamame22 | 0:a9bcda5b678a | 1922 | for (var i = 0, l = this.upgrades.length; i < l; i++) { |
edamame22 | 0:a9bcda5b678a | 1923 | this.probe(this.upgrades[i]); |
edamame22 | 0:a9bcda5b678a | 1924 | } |
edamame22 | 0:a9bcda5b678a | 1925 | } |
edamame22 | 0:a9bcda5b678a | 1926 | }; |
edamame22 | 0:a9bcda5b678a | 1927 | |
edamame22 | 0:a9bcda5b678a | 1928 | /** |
edamame22 | 0:a9bcda5b678a | 1929 | * Handles a packet. |
edamame22 | 0:a9bcda5b678a | 1930 | * |
edamame22 | 0:a9bcda5b678a | 1931 | * @api private |
edamame22 | 0:a9bcda5b678a | 1932 | */ |
edamame22 | 0:a9bcda5b678a | 1933 | |
edamame22 | 0:a9bcda5b678a | 1934 | Socket.prototype.onPacket = function (packet) { |
edamame22 | 0:a9bcda5b678a | 1935 | if ('opening' == this.readyState || 'open' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 1936 | debug('socket receive: type "%s", data "%s"', packet.type, packet.data); |
edamame22 | 0:a9bcda5b678a | 1937 | |
edamame22 | 0:a9bcda5b678a | 1938 | this.emit('packet', packet); |
edamame22 | 0:a9bcda5b678a | 1939 | |
edamame22 | 0:a9bcda5b678a | 1940 | // Socket is live - any packet counts |
edamame22 | 0:a9bcda5b678a | 1941 | this.emit('heartbeat'); |
edamame22 | 0:a9bcda5b678a | 1942 | |
edamame22 | 0:a9bcda5b678a | 1943 | switch (packet.type) { |
edamame22 | 0:a9bcda5b678a | 1944 | case 'open': |
edamame22 | 0:a9bcda5b678a | 1945 | this.onHandshake(parsejson(packet.data)); |
edamame22 | 0:a9bcda5b678a | 1946 | break; |
edamame22 | 0:a9bcda5b678a | 1947 | |
edamame22 | 0:a9bcda5b678a | 1948 | case 'pong': |
edamame22 | 0:a9bcda5b678a | 1949 | this.setPing(); |
edamame22 | 0:a9bcda5b678a | 1950 | break; |
edamame22 | 0:a9bcda5b678a | 1951 | |
edamame22 | 0:a9bcda5b678a | 1952 | case 'error': |
edamame22 | 0:a9bcda5b678a | 1953 | var err = new Error('server error'); |
edamame22 | 0:a9bcda5b678a | 1954 | err.code = packet.data; |
edamame22 | 0:a9bcda5b678a | 1955 | this.emit('error', err); |
edamame22 | 0:a9bcda5b678a | 1956 | break; |
edamame22 | 0:a9bcda5b678a | 1957 | |
edamame22 | 0:a9bcda5b678a | 1958 | case 'message': |
edamame22 | 0:a9bcda5b678a | 1959 | this.emit('data', packet.data); |
edamame22 | 0:a9bcda5b678a | 1960 | this.emit('message', packet.data); |
edamame22 | 0:a9bcda5b678a | 1961 | break; |
edamame22 | 0:a9bcda5b678a | 1962 | } |
edamame22 | 0:a9bcda5b678a | 1963 | } else { |
edamame22 | 0:a9bcda5b678a | 1964 | debug('packet received with socket readyState "%s"', this.readyState); |
edamame22 | 0:a9bcda5b678a | 1965 | } |
edamame22 | 0:a9bcda5b678a | 1966 | }; |
edamame22 | 0:a9bcda5b678a | 1967 | |
edamame22 | 0:a9bcda5b678a | 1968 | /** |
edamame22 | 0:a9bcda5b678a | 1969 | * Called upon handshake completion. |
edamame22 | 0:a9bcda5b678a | 1970 | * |
edamame22 | 0:a9bcda5b678a | 1971 | * @param {Object} handshake obj |
edamame22 | 0:a9bcda5b678a | 1972 | * @api private |
edamame22 | 0:a9bcda5b678a | 1973 | */ |
edamame22 | 0:a9bcda5b678a | 1974 | |
edamame22 | 0:a9bcda5b678a | 1975 | Socket.prototype.onHandshake = function (data) { |
edamame22 | 0:a9bcda5b678a | 1976 | this.emit('handshake', data); |
edamame22 | 0:a9bcda5b678a | 1977 | this.id = data.sid; |
edamame22 | 0:a9bcda5b678a | 1978 | this.transport.query.sid = data.sid; |
edamame22 | 0:a9bcda5b678a | 1979 | this.upgrades = this.filterUpgrades(data.upgrades); |
edamame22 | 0:a9bcda5b678a | 1980 | this.pingInterval = data.pingInterval; |
edamame22 | 0:a9bcda5b678a | 1981 | this.pingTimeout = data.pingTimeout; |
edamame22 | 0:a9bcda5b678a | 1982 | this.onOpen(); |
edamame22 | 0:a9bcda5b678a | 1983 | // In case open handler closes socket |
edamame22 | 0:a9bcda5b678a | 1984 | if ('closed' == this.readyState) return; |
edamame22 | 0:a9bcda5b678a | 1985 | this.setPing(); |
edamame22 | 0:a9bcda5b678a | 1986 | |
edamame22 | 0:a9bcda5b678a | 1987 | // Prolong liveness of socket on heartbeat |
edamame22 | 0:a9bcda5b678a | 1988 | this.removeListener('heartbeat', this.onHeartbeat); |
edamame22 | 0:a9bcda5b678a | 1989 | this.on('heartbeat', this.onHeartbeat); |
edamame22 | 0:a9bcda5b678a | 1990 | }; |
edamame22 | 0:a9bcda5b678a | 1991 | |
edamame22 | 0:a9bcda5b678a | 1992 | /** |
edamame22 | 0:a9bcda5b678a | 1993 | * Resets ping timeout. |
edamame22 | 0:a9bcda5b678a | 1994 | * |
edamame22 | 0:a9bcda5b678a | 1995 | * @api private |
edamame22 | 0:a9bcda5b678a | 1996 | */ |
edamame22 | 0:a9bcda5b678a | 1997 | |
edamame22 | 0:a9bcda5b678a | 1998 | Socket.prototype.onHeartbeat = function (timeout) { |
edamame22 | 0:a9bcda5b678a | 1999 | clearTimeout(this.pingTimeoutTimer); |
edamame22 | 0:a9bcda5b678a | 2000 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2001 | self.pingTimeoutTimer = setTimeout(function () { |
edamame22 | 0:a9bcda5b678a | 2002 | if ('closed' == self.readyState) return; |
edamame22 | 0:a9bcda5b678a | 2003 | self.onClose('ping timeout'); |
edamame22 | 0:a9bcda5b678a | 2004 | }, timeout || (self.pingInterval + self.pingTimeout)); |
edamame22 | 0:a9bcda5b678a | 2005 | }; |
edamame22 | 0:a9bcda5b678a | 2006 | |
edamame22 | 0:a9bcda5b678a | 2007 | /** |
edamame22 | 0:a9bcda5b678a | 2008 | * Pings server every `this.pingInterval` and expects response |
edamame22 | 0:a9bcda5b678a | 2009 | * within `this.pingTimeout` or closes connection. |
edamame22 | 0:a9bcda5b678a | 2010 | * |
edamame22 | 0:a9bcda5b678a | 2011 | * @api private |
edamame22 | 0:a9bcda5b678a | 2012 | */ |
edamame22 | 0:a9bcda5b678a | 2013 | |
edamame22 | 0:a9bcda5b678a | 2014 | Socket.prototype.setPing = function () { |
edamame22 | 0:a9bcda5b678a | 2015 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2016 | clearTimeout(self.pingIntervalTimer); |
edamame22 | 0:a9bcda5b678a | 2017 | self.pingIntervalTimer = setTimeout(function () { |
edamame22 | 0:a9bcda5b678a | 2018 | debug('writing ping packet - expecting pong within %sms', self.pingTimeout); |
edamame22 | 0:a9bcda5b678a | 2019 | self.ping(); |
edamame22 | 0:a9bcda5b678a | 2020 | self.onHeartbeat(self.pingTimeout); |
edamame22 | 0:a9bcda5b678a | 2021 | }, self.pingInterval); |
edamame22 | 0:a9bcda5b678a | 2022 | }; |
edamame22 | 0:a9bcda5b678a | 2023 | |
edamame22 | 0:a9bcda5b678a | 2024 | /** |
edamame22 | 0:a9bcda5b678a | 2025 | * Sends a ping packet. |
edamame22 | 0:a9bcda5b678a | 2026 | * |
edamame22 | 0:a9bcda5b678a | 2027 | * @api public |
edamame22 | 0:a9bcda5b678a | 2028 | */ |
edamame22 | 0:a9bcda5b678a | 2029 | |
edamame22 | 0:a9bcda5b678a | 2030 | Socket.prototype.ping = function () { |
edamame22 | 0:a9bcda5b678a | 2031 | this.sendPacket('ping'); |
edamame22 | 0:a9bcda5b678a | 2032 | }; |
edamame22 | 0:a9bcda5b678a | 2033 | |
edamame22 | 0:a9bcda5b678a | 2034 | /** |
edamame22 | 0:a9bcda5b678a | 2035 | * Called on `drain` event |
edamame22 | 0:a9bcda5b678a | 2036 | * |
edamame22 | 0:a9bcda5b678a | 2037 | * @api private |
edamame22 | 0:a9bcda5b678a | 2038 | */ |
edamame22 | 0:a9bcda5b678a | 2039 | |
edamame22 | 0:a9bcda5b678a | 2040 | Socket.prototype.onDrain = function() { |
edamame22 | 0:a9bcda5b678a | 2041 | for (var i = 0; i < this.prevBufferLen; i++) { |
edamame22 | 0:a9bcda5b678a | 2042 | if (this.callbackBuffer[i]) { |
edamame22 | 0:a9bcda5b678a | 2043 | this.callbackBuffer[i](); |
edamame22 | 0:a9bcda5b678a | 2044 | } |
edamame22 | 0:a9bcda5b678a | 2045 | } |
edamame22 | 0:a9bcda5b678a | 2046 | |
edamame22 | 0:a9bcda5b678a | 2047 | this.writeBuffer.splice(0, this.prevBufferLen); |
edamame22 | 0:a9bcda5b678a | 2048 | this.callbackBuffer.splice(0, this.prevBufferLen); |
edamame22 | 0:a9bcda5b678a | 2049 | |
edamame22 | 0:a9bcda5b678a | 2050 | // setting prevBufferLen = 0 is very important |
edamame22 | 0:a9bcda5b678a | 2051 | // for example, when upgrading, upgrade packet is sent over, |
edamame22 | 0:a9bcda5b678a | 2052 | // and a nonzero prevBufferLen could cause problems on `drain` |
edamame22 | 0:a9bcda5b678a | 2053 | this.prevBufferLen = 0; |
edamame22 | 0:a9bcda5b678a | 2054 | |
edamame22 | 0:a9bcda5b678a | 2055 | if (this.writeBuffer.length == 0) { |
edamame22 | 0:a9bcda5b678a | 2056 | this.emit('drain'); |
edamame22 | 0:a9bcda5b678a | 2057 | } else { |
edamame22 | 0:a9bcda5b678a | 2058 | this.flush(); |
edamame22 | 0:a9bcda5b678a | 2059 | } |
edamame22 | 0:a9bcda5b678a | 2060 | }; |
edamame22 | 0:a9bcda5b678a | 2061 | |
edamame22 | 0:a9bcda5b678a | 2062 | /** |
edamame22 | 0:a9bcda5b678a | 2063 | * Flush write buffers. |
edamame22 | 0:a9bcda5b678a | 2064 | * |
edamame22 | 0:a9bcda5b678a | 2065 | * @api private |
edamame22 | 0:a9bcda5b678a | 2066 | */ |
edamame22 | 0:a9bcda5b678a | 2067 | |
edamame22 | 0:a9bcda5b678a | 2068 | Socket.prototype.flush = function () { |
edamame22 | 0:a9bcda5b678a | 2069 | if ('closed' != this.readyState && this.transport.writable && |
edamame22 | 0:a9bcda5b678a | 2070 | !this.upgrading && this.writeBuffer.length) { |
edamame22 | 0:a9bcda5b678a | 2071 | debug('flushing %d packets in socket', this.writeBuffer.length); |
edamame22 | 0:a9bcda5b678a | 2072 | this.transport.send(this.writeBuffer); |
edamame22 | 0:a9bcda5b678a | 2073 | // keep track of current length of writeBuffer |
edamame22 | 0:a9bcda5b678a | 2074 | // splice writeBuffer and callbackBuffer on `drain` |
edamame22 | 0:a9bcda5b678a | 2075 | this.prevBufferLen = this.writeBuffer.length; |
edamame22 | 0:a9bcda5b678a | 2076 | this.emit('flush'); |
edamame22 | 0:a9bcda5b678a | 2077 | } |
edamame22 | 0:a9bcda5b678a | 2078 | }; |
edamame22 | 0:a9bcda5b678a | 2079 | |
edamame22 | 0:a9bcda5b678a | 2080 | /** |
edamame22 | 0:a9bcda5b678a | 2081 | * Sends a message. |
edamame22 | 0:a9bcda5b678a | 2082 | * |
edamame22 | 0:a9bcda5b678a | 2083 | * @param {String} message. |
edamame22 | 0:a9bcda5b678a | 2084 | * @param {Function} callback function. |
edamame22 | 0:a9bcda5b678a | 2085 | * @return {Socket} for chaining. |
edamame22 | 0:a9bcda5b678a | 2086 | * @api public |
edamame22 | 0:a9bcda5b678a | 2087 | */ |
edamame22 | 0:a9bcda5b678a | 2088 | |
edamame22 | 0:a9bcda5b678a | 2089 | Socket.prototype.write = |
edamame22 | 0:a9bcda5b678a | 2090 | Socket.prototype.send = function (msg, fn) { |
edamame22 | 0:a9bcda5b678a | 2091 | this.sendPacket('message', msg, fn); |
edamame22 | 0:a9bcda5b678a | 2092 | return this; |
edamame22 | 0:a9bcda5b678a | 2093 | }; |
edamame22 | 0:a9bcda5b678a | 2094 | |
edamame22 | 0:a9bcda5b678a | 2095 | /** |
edamame22 | 0:a9bcda5b678a | 2096 | * Sends a packet. |
edamame22 | 0:a9bcda5b678a | 2097 | * |
edamame22 | 0:a9bcda5b678a | 2098 | * @param {String} packet type. |
edamame22 | 0:a9bcda5b678a | 2099 | * @param {String} data. |
edamame22 | 0:a9bcda5b678a | 2100 | * @param {Function} callback function. |
edamame22 | 0:a9bcda5b678a | 2101 | * @api private |
edamame22 | 0:a9bcda5b678a | 2102 | */ |
edamame22 | 0:a9bcda5b678a | 2103 | |
edamame22 | 0:a9bcda5b678a | 2104 | Socket.prototype.sendPacket = function (type, data, fn) { |
edamame22 | 0:a9bcda5b678a | 2105 | if ('closing' == this.readyState || 'closed' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 2106 | return; |
edamame22 | 0:a9bcda5b678a | 2107 | } |
edamame22 | 0:a9bcda5b678a | 2108 | |
edamame22 | 0:a9bcda5b678a | 2109 | var packet = { type: type, data: data }; |
edamame22 | 0:a9bcda5b678a | 2110 | this.emit('packetCreate', packet); |
edamame22 | 0:a9bcda5b678a | 2111 | this.writeBuffer.push(packet); |
edamame22 | 0:a9bcda5b678a | 2112 | this.callbackBuffer.push(fn); |
edamame22 | 0:a9bcda5b678a | 2113 | this.flush(); |
edamame22 | 0:a9bcda5b678a | 2114 | }; |
edamame22 | 0:a9bcda5b678a | 2115 | |
edamame22 | 0:a9bcda5b678a | 2116 | /** |
edamame22 | 0:a9bcda5b678a | 2117 | * Closes the connection. |
edamame22 | 0:a9bcda5b678a | 2118 | * |
edamame22 | 0:a9bcda5b678a | 2119 | * @api private |
edamame22 | 0:a9bcda5b678a | 2120 | */ |
edamame22 | 0:a9bcda5b678a | 2121 | |
edamame22 | 0:a9bcda5b678a | 2122 | Socket.prototype.close = function () { |
edamame22 | 0:a9bcda5b678a | 2123 | if ('opening' == this.readyState || 'open' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 2124 | this.readyState = 'closing'; |
edamame22 | 0:a9bcda5b678a | 2125 | |
edamame22 | 0:a9bcda5b678a | 2126 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2127 | |
edamame22 | 0:a9bcda5b678a | 2128 | function close() { |
edamame22 | 0:a9bcda5b678a | 2129 | self.onClose('forced close'); |
edamame22 | 0:a9bcda5b678a | 2130 | debug('socket closing - telling transport to close'); |
edamame22 | 0:a9bcda5b678a | 2131 | self.transport.close(); |
edamame22 | 0:a9bcda5b678a | 2132 | } |
edamame22 | 0:a9bcda5b678a | 2133 | |
edamame22 | 0:a9bcda5b678a | 2134 | function cleanupAndClose() { |
edamame22 | 0:a9bcda5b678a | 2135 | self.removeListener('upgrade', cleanupAndClose); |
edamame22 | 0:a9bcda5b678a | 2136 | self.removeListener('upgradeError', cleanupAndClose); |
edamame22 | 0:a9bcda5b678a | 2137 | close(); |
edamame22 | 0:a9bcda5b678a | 2138 | } |
edamame22 | 0:a9bcda5b678a | 2139 | |
edamame22 | 0:a9bcda5b678a | 2140 | function waitForUpgrade() { |
edamame22 | 0:a9bcda5b678a | 2141 | // wait for upgrade to finish since we can't send packets while pausing a transport |
edamame22 | 0:a9bcda5b678a | 2142 | self.once('upgrade', cleanupAndClose); |
edamame22 | 0:a9bcda5b678a | 2143 | self.once('upgradeError', cleanupAndClose); |
edamame22 | 0:a9bcda5b678a | 2144 | } |
edamame22 | 0:a9bcda5b678a | 2145 | |
edamame22 | 0:a9bcda5b678a | 2146 | if (this.writeBuffer.length) { |
edamame22 | 0:a9bcda5b678a | 2147 | this.once('drain', function() { |
edamame22 | 0:a9bcda5b678a | 2148 | if (this.upgrading) { |
edamame22 | 0:a9bcda5b678a | 2149 | waitForUpgrade(); |
edamame22 | 0:a9bcda5b678a | 2150 | } else { |
edamame22 | 0:a9bcda5b678a | 2151 | close(); |
edamame22 | 0:a9bcda5b678a | 2152 | } |
edamame22 | 0:a9bcda5b678a | 2153 | }); |
edamame22 | 0:a9bcda5b678a | 2154 | } else if (this.upgrading) { |
edamame22 | 0:a9bcda5b678a | 2155 | waitForUpgrade(); |
edamame22 | 0:a9bcda5b678a | 2156 | } else { |
edamame22 | 0:a9bcda5b678a | 2157 | close(); |
edamame22 | 0:a9bcda5b678a | 2158 | } |
edamame22 | 0:a9bcda5b678a | 2159 | } |
edamame22 | 0:a9bcda5b678a | 2160 | |
edamame22 | 0:a9bcda5b678a | 2161 | return this; |
edamame22 | 0:a9bcda5b678a | 2162 | }; |
edamame22 | 0:a9bcda5b678a | 2163 | |
edamame22 | 0:a9bcda5b678a | 2164 | /** |
edamame22 | 0:a9bcda5b678a | 2165 | * Called upon transport error |
edamame22 | 0:a9bcda5b678a | 2166 | * |
edamame22 | 0:a9bcda5b678a | 2167 | * @api private |
edamame22 | 0:a9bcda5b678a | 2168 | */ |
edamame22 | 0:a9bcda5b678a | 2169 | |
edamame22 | 0:a9bcda5b678a | 2170 | Socket.prototype.onError = function (err) { |
edamame22 | 0:a9bcda5b678a | 2171 | debug('socket error %j', err); |
edamame22 | 0:a9bcda5b678a | 2172 | Socket.priorWebsocketSuccess = false; |
edamame22 | 0:a9bcda5b678a | 2173 | this.emit('error', err); |
edamame22 | 0:a9bcda5b678a | 2174 | this.onClose('transport error', err); |
edamame22 | 0:a9bcda5b678a | 2175 | }; |
edamame22 | 0:a9bcda5b678a | 2176 | |
edamame22 | 0:a9bcda5b678a | 2177 | /** |
edamame22 | 0:a9bcda5b678a | 2178 | * Called upon transport close. |
edamame22 | 0:a9bcda5b678a | 2179 | * |
edamame22 | 0:a9bcda5b678a | 2180 | * @api private |
edamame22 | 0:a9bcda5b678a | 2181 | */ |
edamame22 | 0:a9bcda5b678a | 2182 | |
edamame22 | 0:a9bcda5b678a | 2183 | Socket.prototype.onClose = function (reason, desc) { |
edamame22 | 0:a9bcda5b678a | 2184 | if ('opening' == this.readyState || 'open' == this.readyState || 'closing' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 2185 | debug('socket close with reason: "%s"', reason); |
edamame22 | 0:a9bcda5b678a | 2186 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2187 | |
edamame22 | 0:a9bcda5b678a | 2188 | // clear timers |
edamame22 | 0:a9bcda5b678a | 2189 | clearTimeout(this.pingIntervalTimer); |
edamame22 | 0:a9bcda5b678a | 2190 | clearTimeout(this.pingTimeoutTimer); |
edamame22 | 0:a9bcda5b678a | 2191 | |
edamame22 | 0:a9bcda5b678a | 2192 | // clean buffers in next tick, so developers can still |
edamame22 | 0:a9bcda5b678a | 2193 | // grab the buffers on `close` event |
edamame22 | 0:a9bcda5b678a | 2194 | setTimeout(function() { |
edamame22 | 0:a9bcda5b678a | 2195 | self.writeBuffer = []; |
edamame22 | 0:a9bcda5b678a | 2196 | self.callbackBuffer = []; |
edamame22 | 0:a9bcda5b678a | 2197 | self.prevBufferLen = 0; |
edamame22 | 0:a9bcda5b678a | 2198 | }, 0); |
edamame22 | 0:a9bcda5b678a | 2199 | |
edamame22 | 0:a9bcda5b678a | 2200 | // stop event from firing again for transport |
edamame22 | 0:a9bcda5b678a | 2201 | this.transport.removeAllListeners('close'); |
edamame22 | 0:a9bcda5b678a | 2202 | |
edamame22 | 0:a9bcda5b678a | 2203 | // ensure transport won't stay open |
edamame22 | 0:a9bcda5b678a | 2204 | this.transport.close(); |
edamame22 | 0:a9bcda5b678a | 2205 | |
edamame22 | 0:a9bcda5b678a | 2206 | // ignore further transport communication |
edamame22 | 0:a9bcda5b678a | 2207 | this.transport.removeAllListeners(); |
edamame22 | 0:a9bcda5b678a | 2208 | |
edamame22 | 0:a9bcda5b678a | 2209 | // set ready state |
edamame22 | 0:a9bcda5b678a | 2210 | this.readyState = 'closed'; |
edamame22 | 0:a9bcda5b678a | 2211 | |
edamame22 | 0:a9bcda5b678a | 2212 | // clear session id |
edamame22 | 0:a9bcda5b678a | 2213 | this.id = null; |
edamame22 | 0:a9bcda5b678a | 2214 | |
edamame22 | 0:a9bcda5b678a | 2215 | // emit close event |
edamame22 | 0:a9bcda5b678a | 2216 | this.emit('close', reason, desc); |
edamame22 | 0:a9bcda5b678a | 2217 | } |
edamame22 | 0:a9bcda5b678a | 2218 | }; |
edamame22 | 0:a9bcda5b678a | 2219 | |
edamame22 | 0:a9bcda5b678a | 2220 | /** |
edamame22 | 0:a9bcda5b678a | 2221 | * Filters upgrades, returning only those matching client transports. |
edamame22 | 0:a9bcda5b678a | 2222 | * |
edamame22 | 0:a9bcda5b678a | 2223 | * @param {Array} server upgrades |
edamame22 | 0:a9bcda5b678a | 2224 | * @api private |
edamame22 | 0:a9bcda5b678a | 2225 | * |
edamame22 | 0:a9bcda5b678a | 2226 | */ |
edamame22 | 0:a9bcda5b678a | 2227 | |
edamame22 | 0:a9bcda5b678a | 2228 | Socket.prototype.filterUpgrades = function (upgrades) { |
edamame22 | 0:a9bcda5b678a | 2229 | var filteredUpgrades = []; |
edamame22 | 0:a9bcda5b678a | 2230 | for (var i = 0, j = upgrades.length; i<j; i++) { |
edamame22 | 0:a9bcda5b678a | 2231 | if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]); |
edamame22 | 0:a9bcda5b678a | 2232 | } |
edamame22 | 0:a9bcda5b678a | 2233 | return filteredUpgrades; |
edamame22 | 0:a9bcda5b678a | 2234 | }; |
edamame22 | 0:a9bcda5b678a | 2235 | |
edamame22 | 0:a9bcda5b678a | 2236 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 2237 | },{"./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){ |
edamame22 | 0:a9bcda5b678a | 2238 | /** |
edamame22 | 0:a9bcda5b678a | 2239 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 2240 | */ |
edamame22 | 0:a9bcda5b678a | 2241 | |
edamame22 | 0:a9bcda5b678a | 2242 | var parser = _dereq_('engine.io-parser'); |
edamame22 | 0:a9bcda5b678a | 2243 | var Emitter = _dereq_('component-emitter'); |
edamame22 | 0:a9bcda5b678a | 2244 | |
edamame22 | 0:a9bcda5b678a | 2245 | /** |
edamame22 | 0:a9bcda5b678a | 2246 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 2247 | */ |
edamame22 | 0:a9bcda5b678a | 2248 | |
edamame22 | 0:a9bcda5b678a | 2249 | module.exports = Transport; |
edamame22 | 0:a9bcda5b678a | 2250 | |
edamame22 | 0:a9bcda5b678a | 2251 | /** |
edamame22 | 0:a9bcda5b678a | 2252 | * Transport abstract constructor. |
edamame22 | 0:a9bcda5b678a | 2253 | * |
edamame22 | 0:a9bcda5b678a | 2254 | * @param {Object} options. |
edamame22 | 0:a9bcda5b678a | 2255 | * @api private |
edamame22 | 0:a9bcda5b678a | 2256 | */ |
edamame22 | 0:a9bcda5b678a | 2257 | |
edamame22 | 0:a9bcda5b678a | 2258 | function Transport (opts) { |
edamame22 | 0:a9bcda5b678a | 2259 | this.path = opts.path; |
edamame22 | 0:a9bcda5b678a | 2260 | this.hostname = opts.hostname; |
edamame22 | 0:a9bcda5b678a | 2261 | this.port = opts.port; |
edamame22 | 0:a9bcda5b678a | 2262 | this.secure = opts.secure; |
edamame22 | 0:a9bcda5b678a | 2263 | this.query = opts.query; |
edamame22 | 0:a9bcda5b678a | 2264 | this.timestampParam = opts.timestampParam; |
edamame22 | 0:a9bcda5b678a | 2265 | this.timestampRequests = opts.timestampRequests; |
edamame22 | 0:a9bcda5b678a | 2266 | this.readyState = ''; |
edamame22 | 0:a9bcda5b678a | 2267 | this.agent = opts.agent || false; |
edamame22 | 0:a9bcda5b678a | 2268 | this.socket = opts.socket; |
edamame22 | 0:a9bcda5b678a | 2269 | this.enablesXDR = opts.enablesXDR; |
edamame22 | 0:a9bcda5b678a | 2270 | |
edamame22 | 0:a9bcda5b678a | 2271 | // SSL options for Node.js client |
edamame22 | 0:a9bcda5b678a | 2272 | this.pfx = opts.pfx; |
edamame22 | 0:a9bcda5b678a | 2273 | this.key = opts.key; |
edamame22 | 0:a9bcda5b678a | 2274 | this.passphrase = opts.passphrase; |
edamame22 | 0:a9bcda5b678a | 2275 | this.cert = opts.cert; |
edamame22 | 0:a9bcda5b678a | 2276 | this.ca = opts.ca; |
edamame22 | 0:a9bcda5b678a | 2277 | this.ciphers = opts.ciphers; |
edamame22 | 0:a9bcda5b678a | 2278 | this.rejectUnauthorized = opts.rejectUnauthorized; |
edamame22 | 0:a9bcda5b678a | 2279 | } |
edamame22 | 0:a9bcda5b678a | 2280 | |
edamame22 | 0:a9bcda5b678a | 2281 | /** |
edamame22 | 0:a9bcda5b678a | 2282 | * Mix in `Emitter`. |
edamame22 | 0:a9bcda5b678a | 2283 | */ |
edamame22 | 0:a9bcda5b678a | 2284 | |
edamame22 | 0:a9bcda5b678a | 2285 | Emitter(Transport.prototype); |
edamame22 | 0:a9bcda5b678a | 2286 | |
edamame22 | 0:a9bcda5b678a | 2287 | /** |
edamame22 | 0:a9bcda5b678a | 2288 | * A counter used to prevent collisions in the timestamps used |
edamame22 | 0:a9bcda5b678a | 2289 | * for cache busting. |
edamame22 | 0:a9bcda5b678a | 2290 | */ |
edamame22 | 0:a9bcda5b678a | 2291 | |
edamame22 | 0:a9bcda5b678a | 2292 | Transport.timestamps = 0; |
edamame22 | 0:a9bcda5b678a | 2293 | |
edamame22 | 0:a9bcda5b678a | 2294 | /** |
edamame22 | 0:a9bcda5b678a | 2295 | * Emits an error. |
edamame22 | 0:a9bcda5b678a | 2296 | * |
edamame22 | 0:a9bcda5b678a | 2297 | * @param {String} str |
edamame22 | 0:a9bcda5b678a | 2298 | * @return {Transport} for chaining |
edamame22 | 0:a9bcda5b678a | 2299 | * @api public |
edamame22 | 0:a9bcda5b678a | 2300 | */ |
edamame22 | 0:a9bcda5b678a | 2301 | |
edamame22 | 0:a9bcda5b678a | 2302 | Transport.prototype.onError = function (msg, desc) { |
edamame22 | 0:a9bcda5b678a | 2303 | var err = new Error(msg); |
edamame22 | 0:a9bcda5b678a | 2304 | err.type = 'TransportError'; |
edamame22 | 0:a9bcda5b678a | 2305 | err.description = desc; |
edamame22 | 0:a9bcda5b678a | 2306 | this.emit('error', err); |
edamame22 | 0:a9bcda5b678a | 2307 | return this; |
edamame22 | 0:a9bcda5b678a | 2308 | }; |
edamame22 | 0:a9bcda5b678a | 2309 | |
edamame22 | 0:a9bcda5b678a | 2310 | /** |
edamame22 | 0:a9bcda5b678a | 2311 | * Opens the transport. |
edamame22 | 0:a9bcda5b678a | 2312 | * |
edamame22 | 0:a9bcda5b678a | 2313 | * @api public |
edamame22 | 0:a9bcda5b678a | 2314 | */ |
edamame22 | 0:a9bcda5b678a | 2315 | |
edamame22 | 0:a9bcda5b678a | 2316 | Transport.prototype.open = function () { |
edamame22 | 0:a9bcda5b678a | 2317 | if ('closed' == this.readyState || '' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 2318 | this.readyState = 'opening'; |
edamame22 | 0:a9bcda5b678a | 2319 | this.doOpen(); |
edamame22 | 0:a9bcda5b678a | 2320 | } |
edamame22 | 0:a9bcda5b678a | 2321 | |
edamame22 | 0:a9bcda5b678a | 2322 | return this; |
edamame22 | 0:a9bcda5b678a | 2323 | }; |
edamame22 | 0:a9bcda5b678a | 2324 | |
edamame22 | 0:a9bcda5b678a | 2325 | /** |
edamame22 | 0:a9bcda5b678a | 2326 | * Closes the transport. |
edamame22 | 0:a9bcda5b678a | 2327 | * |
edamame22 | 0:a9bcda5b678a | 2328 | * @api private |
edamame22 | 0:a9bcda5b678a | 2329 | */ |
edamame22 | 0:a9bcda5b678a | 2330 | |
edamame22 | 0:a9bcda5b678a | 2331 | Transport.prototype.close = function () { |
edamame22 | 0:a9bcda5b678a | 2332 | if ('opening' == this.readyState || 'open' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 2333 | this.doClose(); |
edamame22 | 0:a9bcda5b678a | 2334 | this.onClose(); |
edamame22 | 0:a9bcda5b678a | 2335 | } |
edamame22 | 0:a9bcda5b678a | 2336 | |
edamame22 | 0:a9bcda5b678a | 2337 | return this; |
edamame22 | 0:a9bcda5b678a | 2338 | }; |
edamame22 | 0:a9bcda5b678a | 2339 | |
edamame22 | 0:a9bcda5b678a | 2340 | /** |
edamame22 | 0:a9bcda5b678a | 2341 | * Sends multiple packets. |
edamame22 | 0:a9bcda5b678a | 2342 | * |
edamame22 | 0:a9bcda5b678a | 2343 | * @param {Array} packets |
edamame22 | 0:a9bcda5b678a | 2344 | * @api private |
edamame22 | 0:a9bcda5b678a | 2345 | */ |
edamame22 | 0:a9bcda5b678a | 2346 | |
edamame22 | 0:a9bcda5b678a | 2347 | Transport.prototype.send = function(packets){ |
edamame22 | 0:a9bcda5b678a | 2348 | if ('open' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 2349 | this.write(packets); |
edamame22 | 0:a9bcda5b678a | 2350 | } else { |
edamame22 | 0:a9bcda5b678a | 2351 | throw new Error('Transport not open'); |
edamame22 | 0:a9bcda5b678a | 2352 | } |
edamame22 | 0:a9bcda5b678a | 2353 | }; |
edamame22 | 0:a9bcda5b678a | 2354 | |
edamame22 | 0:a9bcda5b678a | 2355 | /** |
edamame22 | 0:a9bcda5b678a | 2356 | * Called upon open |
edamame22 | 0:a9bcda5b678a | 2357 | * |
edamame22 | 0:a9bcda5b678a | 2358 | * @api private |
edamame22 | 0:a9bcda5b678a | 2359 | */ |
edamame22 | 0:a9bcda5b678a | 2360 | |
edamame22 | 0:a9bcda5b678a | 2361 | Transport.prototype.onOpen = function () { |
edamame22 | 0:a9bcda5b678a | 2362 | this.readyState = 'open'; |
edamame22 | 0:a9bcda5b678a | 2363 | this.writable = true; |
edamame22 | 0:a9bcda5b678a | 2364 | this.emit('open'); |
edamame22 | 0:a9bcda5b678a | 2365 | }; |
edamame22 | 0:a9bcda5b678a | 2366 | |
edamame22 | 0:a9bcda5b678a | 2367 | /** |
edamame22 | 0:a9bcda5b678a | 2368 | * Called with data. |
edamame22 | 0:a9bcda5b678a | 2369 | * |
edamame22 | 0:a9bcda5b678a | 2370 | * @param {String} data |
edamame22 | 0:a9bcda5b678a | 2371 | * @api private |
edamame22 | 0:a9bcda5b678a | 2372 | */ |
edamame22 | 0:a9bcda5b678a | 2373 | |
edamame22 | 0:a9bcda5b678a | 2374 | Transport.prototype.onData = function(data){ |
edamame22 | 0:a9bcda5b678a | 2375 | var packet = parser.decodePacket(data, this.socket.binaryType); |
edamame22 | 0:a9bcda5b678a | 2376 | this.onPacket(packet); |
edamame22 | 0:a9bcda5b678a | 2377 | }; |
edamame22 | 0:a9bcda5b678a | 2378 | |
edamame22 | 0:a9bcda5b678a | 2379 | /** |
edamame22 | 0:a9bcda5b678a | 2380 | * Called with a decoded packet. |
edamame22 | 0:a9bcda5b678a | 2381 | */ |
edamame22 | 0:a9bcda5b678a | 2382 | |
edamame22 | 0:a9bcda5b678a | 2383 | Transport.prototype.onPacket = function (packet) { |
edamame22 | 0:a9bcda5b678a | 2384 | this.emit('packet', packet); |
edamame22 | 0:a9bcda5b678a | 2385 | }; |
edamame22 | 0:a9bcda5b678a | 2386 | |
edamame22 | 0:a9bcda5b678a | 2387 | /** |
edamame22 | 0:a9bcda5b678a | 2388 | * Called upon close. |
edamame22 | 0:a9bcda5b678a | 2389 | * |
edamame22 | 0:a9bcda5b678a | 2390 | * @api private |
edamame22 | 0:a9bcda5b678a | 2391 | */ |
edamame22 | 0:a9bcda5b678a | 2392 | |
edamame22 | 0:a9bcda5b678a | 2393 | Transport.prototype.onClose = function () { |
edamame22 | 0:a9bcda5b678a | 2394 | this.readyState = 'closed'; |
edamame22 | 0:a9bcda5b678a | 2395 | this.emit('close'); |
edamame22 | 0:a9bcda5b678a | 2396 | }; |
edamame22 | 0:a9bcda5b678a | 2397 | |
edamame22 | 0:a9bcda5b678a | 2398 | },{"component-emitter":9,"engine.io-parser":25}],15:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 2399 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 2400 | /** |
edamame22 | 0:a9bcda5b678a | 2401 | * Module dependencies |
edamame22 | 0:a9bcda5b678a | 2402 | */ |
edamame22 | 0:a9bcda5b678a | 2403 | |
edamame22 | 0:a9bcda5b678a | 2404 | var XMLHttpRequest = _dereq_('xmlhttprequest'); |
edamame22 | 0:a9bcda5b678a | 2405 | var XHR = _dereq_('./polling-xhr'); |
edamame22 | 0:a9bcda5b678a | 2406 | var JSONP = _dereq_('./polling-jsonp'); |
edamame22 | 0:a9bcda5b678a | 2407 | var websocket = _dereq_('./websocket'); |
edamame22 | 0:a9bcda5b678a | 2408 | |
edamame22 | 0:a9bcda5b678a | 2409 | /** |
edamame22 | 0:a9bcda5b678a | 2410 | * Export transports. |
edamame22 | 0:a9bcda5b678a | 2411 | */ |
edamame22 | 0:a9bcda5b678a | 2412 | |
edamame22 | 0:a9bcda5b678a | 2413 | exports.polling = polling; |
edamame22 | 0:a9bcda5b678a | 2414 | exports.websocket = websocket; |
edamame22 | 0:a9bcda5b678a | 2415 | |
edamame22 | 0:a9bcda5b678a | 2416 | /** |
edamame22 | 0:a9bcda5b678a | 2417 | * Polling transport polymorphic constructor. |
edamame22 | 0:a9bcda5b678a | 2418 | * Decides on xhr vs jsonp based on feature detection. |
edamame22 | 0:a9bcda5b678a | 2419 | * |
edamame22 | 0:a9bcda5b678a | 2420 | * @api private |
edamame22 | 0:a9bcda5b678a | 2421 | */ |
edamame22 | 0:a9bcda5b678a | 2422 | |
edamame22 | 0:a9bcda5b678a | 2423 | function polling(opts){ |
edamame22 | 0:a9bcda5b678a | 2424 | var xhr; |
edamame22 | 0:a9bcda5b678a | 2425 | var xd = false; |
edamame22 | 0:a9bcda5b678a | 2426 | var xs = false; |
edamame22 | 0:a9bcda5b678a | 2427 | var jsonp = false !== opts.jsonp; |
edamame22 | 0:a9bcda5b678a | 2428 | |
edamame22 | 0:a9bcda5b678a | 2429 | if (global.location) { |
edamame22 | 0:a9bcda5b678a | 2430 | var isSSL = 'https:' == location.protocol; |
edamame22 | 0:a9bcda5b678a | 2431 | var port = location.port; |
edamame22 | 0:a9bcda5b678a | 2432 | |
edamame22 | 0:a9bcda5b678a | 2433 | // some user agents have empty `location.port` |
edamame22 | 0:a9bcda5b678a | 2434 | if (!port) { |
edamame22 | 0:a9bcda5b678a | 2435 | port = isSSL ? 443 : 80; |
edamame22 | 0:a9bcda5b678a | 2436 | } |
edamame22 | 0:a9bcda5b678a | 2437 | |
edamame22 | 0:a9bcda5b678a | 2438 | xd = opts.hostname != location.hostname || port != opts.port; |
edamame22 | 0:a9bcda5b678a | 2439 | xs = opts.secure != isSSL; |
edamame22 | 0:a9bcda5b678a | 2440 | } |
edamame22 | 0:a9bcda5b678a | 2441 | |
edamame22 | 0:a9bcda5b678a | 2442 | opts.xdomain = xd; |
edamame22 | 0:a9bcda5b678a | 2443 | opts.xscheme = xs; |
edamame22 | 0:a9bcda5b678a | 2444 | xhr = new XMLHttpRequest(opts); |
edamame22 | 0:a9bcda5b678a | 2445 | |
edamame22 | 0:a9bcda5b678a | 2446 | if ('open' in xhr && !opts.forceJSONP) { |
edamame22 | 0:a9bcda5b678a | 2447 | return new XHR(opts); |
edamame22 | 0:a9bcda5b678a | 2448 | } else { |
edamame22 | 0:a9bcda5b678a | 2449 | if (!jsonp) throw new Error('JSONP disabled'); |
edamame22 | 0:a9bcda5b678a | 2450 | return new JSONP(opts); |
edamame22 | 0:a9bcda5b678a | 2451 | } |
edamame22 | 0:a9bcda5b678a | 2452 | } |
edamame22 | 0:a9bcda5b678a | 2453 | |
edamame22 | 0:a9bcda5b678a | 2454 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 2455 | },{"./polling-jsonp":16,"./polling-xhr":17,"./websocket":19,"xmlhttprequest":20}],16:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 2456 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 2457 | |
edamame22 | 0:a9bcda5b678a | 2458 | /** |
edamame22 | 0:a9bcda5b678a | 2459 | * Module requirements. |
edamame22 | 0:a9bcda5b678a | 2460 | */ |
edamame22 | 0:a9bcda5b678a | 2461 | |
edamame22 | 0:a9bcda5b678a | 2462 | var Polling = _dereq_('./polling'); |
edamame22 | 0:a9bcda5b678a | 2463 | var inherit = _dereq_('component-inherit'); |
edamame22 | 0:a9bcda5b678a | 2464 | |
edamame22 | 0:a9bcda5b678a | 2465 | /** |
edamame22 | 0:a9bcda5b678a | 2466 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 2467 | */ |
edamame22 | 0:a9bcda5b678a | 2468 | |
edamame22 | 0:a9bcda5b678a | 2469 | module.exports = JSONPPolling; |
edamame22 | 0:a9bcda5b678a | 2470 | |
edamame22 | 0:a9bcda5b678a | 2471 | /** |
edamame22 | 0:a9bcda5b678a | 2472 | * Cached regular expressions. |
edamame22 | 0:a9bcda5b678a | 2473 | */ |
edamame22 | 0:a9bcda5b678a | 2474 | |
edamame22 | 0:a9bcda5b678a | 2475 | var rNewline = /\n/g; |
edamame22 | 0:a9bcda5b678a | 2476 | var rEscapedNewline = /\\n/g; |
edamame22 | 0:a9bcda5b678a | 2477 | |
edamame22 | 0:a9bcda5b678a | 2478 | /** |
edamame22 | 0:a9bcda5b678a | 2479 | * Global JSONP callbacks. |
edamame22 | 0:a9bcda5b678a | 2480 | */ |
edamame22 | 0:a9bcda5b678a | 2481 | |
edamame22 | 0:a9bcda5b678a | 2482 | var callbacks; |
edamame22 | 0:a9bcda5b678a | 2483 | |
edamame22 | 0:a9bcda5b678a | 2484 | /** |
edamame22 | 0:a9bcda5b678a | 2485 | * Callbacks count. |
edamame22 | 0:a9bcda5b678a | 2486 | */ |
edamame22 | 0:a9bcda5b678a | 2487 | |
edamame22 | 0:a9bcda5b678a | 2488 | var index = 0; |
edamame22 | 0:a9bcda5b678a | 2489 | |
edamame22 | 0:a9bcda5b678a | 2490 | /** |
edamame22 | 0:a9bcda5b678a | 2491 | * Noop. |
edamame22 | 0:a9bcda5b678a | 2492 | */ |
edamame22 | 0:a9bcda5b678a | 2493 | |
edamame22 | 0:a9bcda5b678a | 2494 | function empty () { } |
edamame22 | 0:a9bcda5b678a | 2495 | |
edamame22 | 0:a9bcda5b678a | 2496 | /** |
edamame22 | 0:a9bcda5b678a | 2497 | * JSONP Polling constructor. |
edamame22 | 0:a9bcda5b678a | 2498 | * |
edamame22 | 0:a9bcda5b678a | 2499 | * @param {Object} opts. |
edamame22 | 0:a9bcda5b678a | 2500 | * @api public |
edamame22 | 0:a9bcda5b678a | 2501 | */ |
edamame22 | 0:a9bcda5b678a | 2502 | |
edamame22 | 0:a9bcda5b678a | 2503 | function JSONPPolling (opts) { |
edamame22 | 0:a9bcda5b678a | 2504 | Polling.call(this, opts); |
edamame22 | 0:a9bcda5b678a | 2505 | |
edamame22 | 0:a9bcda5b678a | 2506 | this.query = this.query || {}; |
edamame22 | 0:a9bcda5b678a | 2507 | |
edamame22 | 0:a9bcda5b678a | 2508 | // define global callbacks array if not present |
edamame22 | 0:a9bcda5b678a | 2509 | // we do this here (lazily) to avoid unneeded global pollution |
edamame22 | 0:a9bcda5b678a | 2510 | if (!callbacks) { |
edamame22 | 0:a9bcda5b678a | 2511 | // we need to consider multiple engines in the same page |
edamame22 | 0:a9bcda5b678a | 2512 | if (!global.___eio) global.___eio = []; |
edamame22 | 0:a9bcda5b678a | 2513 | callbacks = global.___eio; |
edamame22 | 0:a9bcda5b678a | 2514 | } |
edamame22 | 0:a9bcda5b678a | 2515 | |
edamame22 | 0:a9bcda5b678a | 2516 | // callback identifier |
edamame22 | 0:a9bcda5b678a | 2517 | this.index = callbacks.length; |
edamame22 | 0:a9bcda5b678a | 2518 | |
edamame22 | 0:a9bcda5b678a | 2519 | // add callback to jsonp global |
edamame22 | 0:a9bcda5b678a | 2520 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2521 | callbacks.push(function (msg) { |
edamame22 | 0:a9bcda5b678a | 2522 | self.onData(msg); |
edamame22 | 0:a9bcda5b678a | 2523 | }); |
edamame22 | 0:a9bcda5b678a | 2524 | |
edamame22 | 0:a9bcda5b678a | 2525 | // append to query string |
edamame22 | 0:a9bcda5b678a | 2526 | this.query.j = this.index; |
edamame22 | 0:a9bcda5b678a | 2527 | |
edamame22 | 0:a9bcda5b678a | 2528 | // prevent spurious errors from being emitted when the window is unloaded |
edamame22 | 0:a9bcda5b678a | 2529 | if (global.document && global.addEventListener) { |
edamame22 | 0:a9bcda5b678a | 2530 | global.addEventListener('beforeunload', function () { |
edamame22 | 0:a9bcda5b678a | 2531 | if (self.script) self.script.onerror = empty; |
edamame22 | 0:a9bcda5b678a | 2532 | }, false); |
edamame22 | 0:a9bcda5b678a | 2533 | } |
edamame22 | 0:a9bcda5b678a | 2534 | } |
edamame22 | 0:a9bcda5b678a | 2535 | |
edamame22 | 0:a9bcda5b678a | 2536 | /** |
edamame22 | 0:a9bcda5b678a | 2537 | * Inherits from Polling. |
edamame22 | 0:a9bcda5b678a | 2538 | */ |
edamame22 | 0:a9bcda5b678a | 2539 | |
edamame22 | 0:a9bcda5b678a | 2540 | inherit(JSONPPolling, Polling); |
edamame22 | 0:a9bcda5b678a | 2541 | |
edamame22 | 0:a9bcda5b678a | 2542 | /* |
edamame22 | 0:a9bcda5b678a | 2543 | * JSONP only supports binary as base64 encoded strings |
edamame22 | 0:a9bcda5b678a | 2544 | */ |
edamame22 | 0:a9bcda5b678a | 2545 | |
edamame22 | 0:a9bcda5b678a | 2546 | JSONPPolling.prototype.supportsBinary = false; |
edamame22 | 0:a9bcda5b678a | 2547 | |
edamame22 | 0:a9bcda5b678a | 2548 | /** |
edamame22 | 0:a9bcda5b678a | 2549 | * Closes the socket. |
edamame22 | 0:a9bcda5b678a | 2550 | * |
edamame22 | 0:a9bcda5b678a | 2551 | * @api private |
edamame22 | 0:a9bcda5b678a | 2552 | */ |
edamame22 | 0:a9bcda5b678a | 2553 | |
edamame22 | 0:a9bcda5b678a | 2554 | JSONPPolling.prototype.doClose = function () { |
edamame22 | 0:a9bcda5b678a | 2555 | if (this.script) { |
edamame22 | 0:a9bcda5b678a | 2556 | this.script.parentNode.removeChild(this.script); |
edamame22 | 0:a9bcda5b678a | 2557 | this.script = null; |
edamame22 | 0:a9bcda5b678a | 2558 | } |
edamame22 | 0:a9bcda5b678a | 2559 | |
edamame22 | 0:a9bcda5b678a | 2560 | if (this.form) { |
edamame22 | 0:a9bcda5b678a | 2561 | this.form.parentNode.removeChild(this.form); |
edamame22 | 0:a9bcda5b678a | 2562 | this.form = null; |
edamame22 | 0:a9bcda5b678a | 2563 | this.iframe = null; |
edamame22 | 0:a9bcda5b678a | 2564 | } |
edamame22 | 0:a9bcda5b678a | 2565 | |
edamame22 | 0:a9bcda5b678a | 2566 | Polling.prototype.doClose.call(this); |
edamame22 | 0:a9bcda5b678a | 2567 | }; |
edamame22 | 0:a9bcda5b678a | 2568 | |
edamame22 | 0:a9bcda5b678a | 2569 | /** |
edamame22 | 0:a9bcda5b678a | 2570 | * Starts a poll cycle. |
edamame22 | 0:a9bcda5b678a | 2571 | * |
edamame22 | 0:a9bcda5b678a | 2572 | * @api private |
edamame22 | 0:a9bcda5b678a | 2573 | */ |
edamame22 | 0:a9bcda5b678a | 2574 | |
edamame22 | 0:a9bcda5b678a | 2575 | JSONPPolling.prototype.doPoll = function () { |
edamame22 | 0:a9bcda5b678a | 2576 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2577 | var script = document.createElement('script'); |
edamame22 | 0:a9bcda5b678a | 2578 | |
edamame22 | 0:a9bcda5b678a | 2579 | if (this.script) { |
edamame22 | 0:a9bcda5b678a | 2580 | this.script.parentNode.removeChild(this.script); |
edamame22 | 0:a9bcda5b678a | 2581 | this.script = null; |
edamame22 | 0:a9bcda5b678a | 2582 | } |
edamame22 | 0:a9bcda5b678a | 2583 | |
edamame22 | 0:a9bcda5b678a | 2584 | script.async = true; |
edamame22 | 0:a9bcda5b678a | 2585 | script.src = this.uri(); |
edamame22 | 0:a9bcda5b678a | 2586 | script.onerror = function(e){ |
edamame22 | 0:a9bcda5b678a | 2587 | self.onError('jsonp poll error',e); |
edamame22 | 0:a9bcda5b678a | 2588 | }; |
edamame22 | 0:a9bcda5b678a | 2589 | |
edamame22 | 0:a9bcda5b678a | 2590 | var insertAt = document.getElementsByTagName('script')[0]; |
edamame22 | 0:a9bcda5b678a | 2591 | insertAt.parentNode.insertBefore(script, insertAt); |
edamame22 | 0:a9bcda5b678a | 2592 | this.script = script; |
edamame22 | 0:a9bcda5b678a | 2593 | |
edamame22 | 0:a9bcda5b678a | 2594 | var isUAgecko = 'undefined' != typeof navigator && /gecko/i.test(navigator.userAgent); |
edamame22 | 0:a9bcda5b678a | 2595 | |
edamame22 | 0:a9bcda5b678a | 2596 | if (isUAgecko) { |
edamame22 | 0:a9bcda5b678a | 2597 | setTimeout(function () { |
edamame22 | 0:a9bcda5b678a | 2598 | var iframe = document.createElement('iframe'); |
edamame22 | 0:a9bcda5b678a | 2599 | document.body.appendChild(iframe); |
edamame22 | 0:a9bcda5b678a | 2600 | document.body.removeChild(iframe); |
edamame22 | 0:a9bcda5b678a | 2601 | }, 100); |
edamame22 | 0:a9bcda5b678a | 2602 | } |
edamame22 | 0:a9bcda5b678a | 2603 | }; |
edamame22 | 0:a9bcda5b678a | 2604 | |
edamame22 | 0:a9bcda5b678a | 2605 | /** |
edamame22 | 0:a9bcda5b678a | 2606 | * Writes with a hidden iframe. |
edamame22 | 0:a9bcda5b678a | 2607 | * |
edamame22 | 0:a9bcda5b678a | 2608 | * @param {String} data to send |
edamame22 | 0:a9bcda5b678a | 2609 | * @param {Function} called upon flush. |
edamame22 | 0:a9bcda5b678a | 2610 | * @api private |
edamame22 | 0:a9bcda5b678a | 2611 | */ |
edamame22 | 0:a9bcda5b678a | 2612 | |
edamame22 | 0:a9bcda5b678a | 2613 | JSONPPolling.prototype.doWrite = function (data, fn) { |
edamame22 | 0:a9bcda5b678a | 2614 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2615 | |
edamame22 | 0:a9bcda5b678a | 2616 | if (!this.form) { |
edamame22 | 0:a9bcda5b678a | 2617 | var form = document.createElement('form'); |
edamame22 | 0:a9bcda5b678a | 2618 | var area = document.createElement('textarea'); |
edamame22 | 0:a9bcda5b678a | 2619 | var id = this.iframeId = 'eio_iframe_' + this.index; |
edamame22 | 0:a9bcda5b678a | 2620 | var iframe; |
edamame22 | 0:a9bcda5b678a | 2621 | |
edamame22 | 0:a9bcda5b678a | 2622 | form.className = 'socketio'; |
edamame22 | 0:a9bcda5b678a | 2623 | form.style.position = 'absolute'; |
edamame22 | 0:a9bcda5b678a | 2624 | form.style.top = '-1000px'; |
edamame22 | 0:a9bcda5b678a | 2625 | form.style.left = '-1000px'; |
edamame22 | 0:a9bcda5b678a | 2626 | form.target = id; |
edamame22 | 0:a9bcda5b678a | 2627 | form.method = 'POST'; |
edamame22 | 0:a9bcda5b678a | 2628 | form.setAttribute('accept-charset', 'utf-8'); |
edamame22 | 0:a9bcda5b678a | 2629 | area.name = 'd'; |
edamame22 | 0:a9bcda5b678a | 2630 | form.appendChild(area); |
edamame22 | 0:a9bcda5b678a | 2631 | document.body.appendChild(form); |
edamame22 | 0:a9bcda5b678a | 2632 | |
edamame22 | 0:a9bcda5b678a | 2633 | this.form = form; |
edamame22 | 0:a9bcda5b678a | 2634 | this.area = area; |
edamame22 | 0:a9bcda5b678a | 2635 | } |
edamame22 | 0:a9bcda5b678a | 2636 | |
edamame22 | 0:a9bcda5b678a | 2637 | this.form.action = this.uri(); |
edamame22 | 0:a9bcda5b678a | 2638 | |
edamame22 | 0:a9bcda5b678a | 2639 | function complete () { |
edamame22 | 0:a9bcda5b678a | 2640 | initIframe(); |
edamame22 | 0:a9bcda5b678a | 2641 | fn(); |
edamame22 | 0:a9bcda5b678a | 2642 | } |
edamame22 | 0:a9bcda5b678a | 2643 | |
edamame22 | 0:a9bcda5b678a | 2644 | function initIframe () { |
edamame22 | 0:a9bcda5b678a | 2645 | if (self.iframe) { |
edamame22 | 0:a9bcda5b678a | 2646 | try { |
edamame22 | 0:a9bcda5b678a | 2647 | self.form.removeChild(self.iframe); |
edamame22 | 0:a9bcda5b678a | 2648 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 2649 | self.onError('jsonp polling iframe removal error', e); |
edamame22 | 0:a9bcda5b678a | 2650 | } |
edamame22 | 0:a9bcda5b678a | 2651 | } |
edamame22 | 0:a9bcda5b678a | 2652 | |
edamame22 | 0:a9bcda5b678a | 2653 | try { |
edamame22 | 0:a9bcda5b678a | 2654 | // ie6 dynamic iframes with target="" support (thanks Chris Lambacher) |
edamame22 | 0:a9bcda5b678a | 2655 | var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">'; |
edamame22 | 0:a9bcda5b678a | 2656 | iframe = document.createElement(html); |
edamame22 | 0:a9bcda5b678a | 2657 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 2658 | iframe = document.createElement('iframe'); |
edamame22 | 0:a9bcda5b678a | 2659 | iframe.name = self.iframeId; |
edamame22 | 0:a9bcda5b678a | 2660 | iframe.src = 'javascript:0'; |
edamame22 | 0:a9bcda5b678a | 2661 | } |
edamame22 | 0:a9bcda5b678a | 2662 | |
edamame22 | 0:a9bcda5b678a | 2663 | iframe.id = self.iframeId; |
edamame22 | 0:a9bcda5b678a | 2664 | |
edamame22 | 0:a9bcda5b678a | 2665 | self.form.appendChild(iframe); |
edamame22 | 0:a9bcda5b678a | 2666 | self.iframe = iframe; |
edamame22 | 0:a9bcda5b678a | 2667 | } |
edamame22 | 0:a9bcda5b678a | 2668 | |
edamame22 | 0:a9bcda5b678a | 2669 | initIframe(); |
edamame22 | 0:a9bcda5b678a | 2670 | |
edamame22 | 0:a9bcda5b678a | 2671 | // escape \n to prevent it from being converted into \r\n by some UAs |
edamame22 | 0:a9bcda5b678a | 2672 | // double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side |
edamame22 | 0:a9bcda5b678a | 2673 | data = data.replace(rEscapedNewline, '\\\n'); |
edamame22 | 0:a9bcda5b678a | 2674 | this.area.value = data.replace(rNewline, '\\n'); |
edamame22 | 0:a9bcda5b678a | 2675 | |
edamame22 | 0:a9bcda5b678a | 2676 | try { |
edamame22 | 0:a9bcda5b678a | 2677 | this.form.submit(); |
edamame22 | 0:a9bcda5b678a | 2678 | } catch(e) {} |
edamame22 | 0:a9bcda5b678a | 2679 | |
edamame22 | 0:a9bcda5b678a | 2680 | if (this.iframe.attachEvent) { |
edamame22 | 0:a9bcda5b678a | 2681 | this.iframe.onreadystatechange = function(){ |
edamame22 | 0:a9bcda5b678a | 2682 | if (self.iframe.readyState == 'complete') { |
edamame22 | 0:a9bcda5b678a | 2683 | complete(); |
edamame22 | 0:a9bcda5b678a | 2684 | } |
edamame22 | 0:a9bcda5b678a | 2685 | }; |
edamame22 | 0:a9bcda5b678a | 2686 | } else { |
edamame22 | 0:a9bcda5b678a | 2687 | this.iframe.onload = complete; |
edamame22 | 0:a9bcda5b678a | 2688 | } |
edamame22 | 0:a9bcda5b678a | 2689 | }; |
edamame22 | 0:a9bcda5b678a | 2690 | |
edamame22 | 0:a9bcda5b678a | 2691 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 2692 | },{"./polling":18,"component-inherit":21}],17:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 2693 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 2694 | /** |
edamame22 | 0:a9bcda5b678a | 2695 | * Module requirements. |
edamame22 | 0:a9bcda5b678a | 2696 | */ |
edamame22 | 0:a9bcda5b678a | 2697 | |
edamame22 | 0:a9bcda5b678a | 2698 | var XMLHttpRequest = _dereq_('xmlhttprequest'); |
edamame22 | 0:a9bcda5b678a | 2699 | var Polling = _dereq_('./polling'); |
edamame22 | 0:a9bcda5b678a | 2700 | var Emitter = _dereq_('component-emitter'); |
edamame22 | 0:a9bcda5b678a | 2701 | var inherit = _dereq_('component-inherit'); |
edamame22 | 0:a9bcda5b678a | 2702 | var debug = _dereq_('debug')('engine.io-client:polling-xhr'); |
edamame22 | 0:a9bcda5b678a | 2703 | |
edamame22 | 0:a9bcda5b678a | 2704 | /** |
edamame22 | 0:a9bcda5b678a | 2705 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 2706 | */ |
edamame22 | 0:a9bcda5b678a | 2707 | |
edamame22 | 0:a9bcda5b678a | 2708 | module.exports = XHR; |
edamame22 | 0:a9bcda5b678a | 2709 | module.exports.Request = Request; |
edamame22 | 0:a9bcda5b678a | 2710 | |
edamame22 | 0:a9bcda5b678a | 2711 | /** |
edamame22 | 0:a9bcda5b678a | 2712 | * Empty function |
edamame22 | 0:a9bcda5b678a | 2713 | */ |
edamame22 | 0:a9bcda5b678a | 2714 | |
edamame22 | 0:a9bcda5b678a | 2715 | function empty(){} |
edamame22 | 0:a9bcda5b678a | 2716 | |
edamame22 | 0:a9bcda5b678a | 2717 | /** |
edamame22 | 0:a9bcda5b678a | 2718 | * XHR Polling constructor. |
edamame22 | 0:a9bcda5b678a | 2719 | * |
edamame22 | 0:a9bcda5b678a | 2720 | * @param {Object} opts |
edamame22 | 0:a9bcda5b678a | 2721 | * @api public |
edamame22 | 0:a9bcda5b678a | 2722 | */ |
edamame22 | 0:a9bcda5b678a | 2723 | |
edamame22 | 0:a9bcda5b678a | 2724 | function XHR(opts){ |
edamame22 | 0:a9bcda5b678a | 2725 | Polling.call(this, opts); |
edamame22 | 0:a9bcda5b678a | 2726 | |
edamame22 | 0:a9bcda5b678a | 2727 | if (global.location) { |
edamame22 | 0:a9bcda5b678a | 2728 | var isSSL = 'https:' == location.protocol; |
edamame22 | 0:a9bcda5b678a | 2729 | var port = location.port; |
edamame22 | 0:a9bcda5b678a | 2730 | |
edamame22 | 0:a9bcda5b678a | 2731 | // some user agents have empty `location.port` |
edamame22 | 0:a9bcda5b678a | 2732 | if (!port) { |
edamame22 | 0:a9bcda5b678a | 2733 | port = isSSL ? 443 : 80; |
edamame22 | 0:a9bcda5b678a | 2734 | } |
edamame22 | 0:a9bcda5b678a | 2735 | |
edamame22 | 0:a9bcda5b678a | 2736 | this.xd = opts.hostname != global.location.hostname || |
edamame22 | 0:a9bcda5b678a | 2737 | port != opts.port; |
edamame22 | 0:a9bcda5b678a | 2738 | this.xs = opts.secure != isSSL; |
edamame22 | 0:a9bcda5b678a | 2739 | } |
edamame22 | 0:a9bcda5b678a | 2740 | } |
edamame22 | 0:a9bcda5b678a | 2741 | |
edamame22 | 0:a9bcda5b678a | 2742 | /** |
edamame22 | 0:a9bcda5b678a | 2743 | * Inherits from Polling. |
edamame22 | 0:a9bcda5b678a | 2744 | */ |
edamame22 | 0:a9bcda5b678a | 2745 | |
edamame22 | 0:a9bcda5b678a | 2746 | inherit(XHR, Polling); |
edamame22 | 0:a9bcda5b678a | 2747 | |
edamame22 | 0:a9bcda5b678a | 2748 | /** |
edamame22 | 0:a9bcda5b678a | 2749 | * XHR supports binary |
edamame22 | 0:a9bcda5b678a | 2750 | */ |
edamame22 | 0:a9bcda5b678a | 2751 | |
edamame22 | 0:a9bcda5b678a | 2752 | XHR.prototype.supportsBinary = true; |
edamame22 | 0:a9bcda5b678a | 2753 | |
edamame22 | 0:a9bcda5b678a | 2754 | /** |
edamame22 | 0:a9bcda5b678a | 2755 | * Creates a request. |
edamame22 | 0:a9bcda5b678a | 2756 | * |
edamame22 | 0:a9bcda5b678a | 2757 | * @param {String} method |
edamame22 | 0:a9bcda5b678a | 2758 | * @api private |
edamame22 | 0:a9bcda5b678a | 2759 | */ |
edamame22 | 0:a9bcda5b678a | 2760 | |
edamame22 | 0:a9bcda5b678a | 2761 | XHR.prototype.request = function(opts){ |
edamame22 | 0:a9bcda5b678a | 2762 | opts = opts || {}; |
edamame22 | 0:a9bcda5b678a | 2763 | opts.uri = this.uri(); |
edamame22 | 0:a9bcda5b678a | 2764 | opts.xd = this.xd; |
edamame22 | 0:a9bcda5b678a | 2765 | opts.xs = this.xs; |
edamame22 | 0:a9bcda5b678a | 2766 | opts.agent = this.agent || false; |
edamame22 | 0:a9bcda5b678a | 2767 | opts.supportsBinary = this.supportsBinary; |
edamame22 | 0:a9bcda5b678a | 2768 | opts.enablesXDR = this.enablesXDR; |
edamame22 | 0:a9bcda5b678a | 2769 | |
edamame22 | 0:a9bcda5b678a | 2770 | // SSL options for Node.js client |
edamame22 | 0:a9bcda5b678a | 2771 | opts.pfx = this.pfx; |
edamame22 | 0:a9bcda5b678a | 2772 | opts.key = this.key; |
edamame22 | 0:a9bcda5b678a | 2773 | opts.passphrase = this.passphrase; |
edamame22 | 0:a9bcda5b678a | 2774 | opts.cert = this.cert; |
edamame22 | 0:a9bcda5b678a | 2775 | opts.ca = this.ca; |
edamame22 | 0:a9bcda5b678a | 2776 | opts.ciphers = this.ciphers; |
edamame22 | 0:a9bcda5b678a | 2777 | opts.rejectUnauthorized = this.rejectUnauthorized; |
edamame22 | 0:a9bcda5b678a | 2778 | |
edamame22 | 0:a9bcda5b678a | 2779 | return new Request(opts); |
edamame22 | 0:a9bcda5b678a | 2780 | }; |
edamame22 | 0:a9bcda5b678a | 2781 | |
edamame22 | 0:a9bcda5b678a | 2782 | /** |
edamame22 | 0:a9bcda5b678a | 2783 | * Sends data. |
edamame22 | 0:a9bcda5b678a | 2784 | * |
edamame22 | 0:a9bcda5b678a | 2785 | * @param {String} data to send. |
edamame22 | 0:a9bcda5b678a | 2786 | * @param {Function} called upon flush. |
edamame22 | 0:a9bcda5b678a | 2787 | * @api private |
edamame22 | 0:a9bcda5b678a | 2788 | */ |
edamame22 | 0:a9bcda5b678a | 2789 | |
edamame22 | 0:a9bcda5b678a | 2790 | XHR.prototype.doWrite = function(data, fn){ |
edamame22 | 0:a9bcda5b678a | 2791 | var isBinary = typeof data !== 'string' && data !== undefined; |
edamame22 | 0:a9bcda5b678a | 2792 | var req = this.request({ method: 'POST', data: data, isBinary: isBinary }); |
edamame22 | 0:a9bcda5b678a | 2793 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2794 | req.on('success', fn); |
edamame22 | 0:a9bcda5b678a | 2795 | req.on('error', function(err){ |
edamame22 | 0:a9bcda5b678a | 2796 | self.onError('xhr post error', err); |
edamame22 | 0:a9bcda5b678a | 2797 | }); |
edamame22 | 0:a9bcda5b678a | 2798 | this.sendXhr = req; |
edamame22 | 0:a9bcda5b678a | 2799 | }; |
edamame22 | 0:a9bcda5b678a | 2800 | |
edamame22 | 0:a9bcda5b678a | 2801 | /** |
edamame22 | 0:a9bcda5b678a | 2802 | * Starts a poll cycle. |
edamame22 | 0:a9bcda5b678a | 2803 | * |
edamame22 | 0:a9bcda5b678a | 2804 | * @api private |
edamame22 | 0:a9bcda5b678a | 2805 | */ |
edamame22 | 0:a9bcda5b678a | 2806 | |
edamame22 | 0:a9bcda5b678a | 2807 | XHR.prototype.doPoll = function(){ |
edamame22 | 0:a9bcda5b678a | 2808 | debug('xhr poll'); |
edamame22 | 0:a9bcda5b678a | 2809 | var req = this.request(); |
edamame22 | 0:a9bcda5b678a | 2810 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2811 | req.on('data', function(data){ |
edamame22 | 0:a9bcda5b678a | 2812 | self.onData(data); |
edamame22 | 0:a9bcda5b678a | 2813 | }); |
edamame22 | 0:a9bcda5b678a | 2814 | req.on('error', function(err){ |
edamame22 | 0:a9bcda5b678a | 2815 | self.onError('xhr poll error', err); |
edamame22 | 0:a9bcda5b678a | 2816 | }); |
edamame22 | 0:a9bcda5b678a | 2817 | this.pollXhr = req; |
edamame22 | 0:a9bcda5b678a | 2818 | }; |
edamame22 | 0:a9bcda5b678a | 2819 | |
edamame22 | 0:a9bcda5b678a | 2820 | /** |
edamame22 | 0:a9bcda5b678a | 2821 | * Request constructor |
edamame22 | 0:a9bcda5b678a | 2822 | * |
edamame22 | 0:a9bcda5b678a | 2823 | * @param {Object} options |
edamame22 | 0:a9bcda5b678a | 2824 | * @api public |
edamame22 | 0:a9bcda5b678a | 2825 | */ |
edamame22 | 0:a9bcda5b678a | 2826 | |
edamame22 | 0:a9bcda5b678a | 2827 | function Request(opts){ |
edamame22 | 0:a9bcda5b678a | 2828 | this.method = opts.method || 'GET'; |
edamame22 | 0:a9bcda5b678a | 2829 | this.uri = opts.uri; |
edamame22 | 0:a9bcda5b678a | 2830 | this.xd = !!opts.xd; |
edamame22 | 0:a9bcda5b678a | 2831 | this.xs = !!opts.xs; |
edamame22 | 0:a9bcda5b678a | 2832 | this.async = false !== opts.async; |
edamame22 | 0:a9bcda5b678a | 2833 | this.data = undefined != opts.data ? opts.data : null; |
edamame22 | 0:a9bcda5b678a | 2834 | this.agent = opts.agent; |
edamame22 | 0:a9bcda5b678a | 2835 | this.isBinary = opts.isBinary; |
edamame22 | 0:a9bcda5b678a | 2836 | this.supportsBinary = opts.supportsBinary; |
edamame22 | 0:a9bcda5b678a | 2837 | this.enablesXDR = opts.enablesXDR; |
edamame22 | 0:a9bcda5b678a | 2838 | |
edamame22 | 0:a9bcda5b678a | 2839 | // SSL options for Node.js client |
edamame22 | 0:a9bcda5b678a | 2840 | this.pfx = opts.pfx; |
edamame22 | 0:a9bcda5b678a | 2841 | this.key = opts.key; |
edamame22 | 0:a9bcda5b678a | 2842 | this.passphrase = opts.passphrase; |
edamame22 | 0:a9bcda5b678a | 2843 | this.cert = opts.cert; |
edamame22 | 0:a9bcda5b678a | 2844 | this.ca = opts.ca; |
edamame22 | 0:a9bcda5b678a | 2845 | this.ciphers = opts.ciphers; |
edamame22 | 0:a9bcda5b678a | 2846 | this.rejectUnauthorized = opts.rejectUnauthorized; |
edamame22 | 0:a9bcda5b678a | 2847 | |
edamame22 | 0:a9bcda5b678a | 2848 | this.create(); |
edamame22 | 0:a9bcda5b678a | 2849 | } |
edamame22 | 0:a9bcda5b678a | 2850 | |
edamame22 | 0:a9bcda5b678a | 2851 | /** |
edamame22 | 0:a9bcda5b678a | 2852 | * Mix in `Emitter`. |
edamame22 | 0:a9bcda5b678a | 2853 | */ |
edamame22 | 0:a9bcda5b678a | 2854 | |
edamame22 | 0:a9bcda5b678a | 2855 | Emitter(Request.prototype); |
edamame22 | 0:a9bcda5b678a | 2856 | |
edamame22 | 0:a9bcda5b678a | 2857 | /** |
edamame22 | 0:a9bcda5b678a | 2858 | * Creates the XHR object and sends the request. |
edamame22 | 0:a9bcda5b678a | 2859 | * |
edamame22 | 0:a9bcda5b678a | 2860 | * @api private |
edamame22 | 0:a9bcda5b678a | 2861 | */ |
edamame22 | 0:a9bcda5b678a | 2862 | |
edamame22 | 0:a9bcda5b678a | 2863 | Request.prototype.create = function(){ |
edamame22 | 0:a9bcda5b678a | 2864 | var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR }; |
edamame22 | 0:a9bcda5b678a | 2865 | |
edamame22 | 0:a9bcda5b678a | 2866 | // SSL options for Node.js client |
edamame22 | 0:a9bcda5b678a | 2867 | opts.pfx = this.pfx; |
edamame22 | 0:a9bcda5b678a | 2868 | opts.key = this.key; |
edamame22 | 0:a9bcda5b678a | 2869 | opts.passphrase = this.passphrase; |
edamame22 | 0:a9bcda5b678a | 2870 | opts.cert = this.cert; |
edamame22 | 0:a9bcda5b678a | 2871 | opts.ca = this.ca; |
edamame22 | 0:a9bcda5b678a | 2872 | opts.ciphers = this.ciphers; |
edamame22 | 0:a9bcda5b678a | 2873 | opts.rejectUnauthorized = this.rejectUnauthorized; |
edamame22 | 0:a9bcda5b678a | 2874 | |
edamame22 | 0:a9bcda5b678a | 2875 | var xhr = this.xhr = new XMLHttpRequest(opts); |
edamame22 | 0:a9bcda5b678a | 2876 | var self = this; |
edamame22 | 0:a9bcda5b678a | 2877 | |
edamame22 | 0:a9bcda5b678a | 2878 | try { |
edamame22 | 0:a9bcda5b678a | 2879 | debug('xhr open %s: %s', this.method, this.uri); |
edamame22 | 0:a9bcda5b678a | 2880 | xhr.open(this.method, this.uri, this.async); |
edamame22 | 0:a9bcda5b678a | 2881 | if (this.supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 2882 | // This has to be done after open because Firefox is stupid |
edamame22 | 0:a9bcda5b678a | 2883 | // http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension |
edamame22 | 0:a9bcda5b678a | 2884 | xhr.responseType = 'arraybuffer'; |
edamame22 | 0:a9bcda5b678a | 2885 | } |
edamame22 | 0:a9bcda5b678a | 2886 | |
edamame22 | 0:a9bcda5b678a | 2887 | if ('POST' == this.method) { |
edamame22 | 0:a9bcda5b678a | 2888 | try { |
edamame22 | 0:a9bcda5b678a | 2889 | if (this.isBinary) { |
edamame22 | 0:a9bcda5b678a | 2890 | xhr.setRequestHeader('Content-type', 'application/octet-stream'); |
edamame22 | 0:a9bcda5b678a | 2891 | } else { |
edamame22 | 0:a9bcda5b678a | 2892 | xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8'); |
edamame22 | 0:a9bcda5b678a | 2893 | } |
edamame22 | 0:a9bcda5b678a | 2894 | } catch (e) {} |
edamame22 | 0:a9bcda5b678a | 2895 | } |
edamame22 | 0:a9bcda5b678a | 2896 | |
edamame22 | 0:a9bcda5b678a | 2897 | // ie6 check |
edamame22 | 0:a9bcda5b678a | 2898 | if ('withCredentials' in xhr) { |
edamame22 | 0:a9bcda5b678a | 2899 | xhr.withCredentials = true; |
edamame22 | 0:a9bcda5b678a | 2900 | } |
edamame22 | 0:a9bcda5b678a | 2901 | |
edamame22 | 0:a9bcda5b678a | 2902 | if (this.hasXDR()) { |
edamame22 | 0:a9bcda5b678a | 2903 | xhr.onload = function(){ |
edamame22 | 0:a9bcda5b678a | 2904 | self.onLoad(); |
edamame22 | 0:a9bcda5b678a | 2905 | }; |
edamame22 | 0:a9bcda5b678a | 2906 | xhr.onerror = function(){ |
edamame22 | 0:a9bcda5b678a | 2907 | self.onError(xhr.responseText); |
edamame22 | 0:a9bcda5b678a | 2908 | }; |
edamame22 | 0:a9bcda5b678a | 2909 | } else { |
edamame22 | 0:a9bcda5b678a | 2910 | xhr.onreadystatechange = function(){ |
edamame22 | 0:a9bcda5b678a | 2911 | if (4 != xhr.readyState) return; |
edamame22 | 0:a9bcda5b678a | 2912 | if (200 == xhr.status || 1223 == xhr.status) { |
edamame22 | 0:a9bcda5b678a | 2913 | self.onLoad(); |
edamame22 | 0:a9bcda5b678a | 2914 | } else { |
edamame22 | 0:a9bcda5b678a | 2915 | // make sure the `error` event handler that's user-set |
edamame22 | 0:a9bcda5b678a | 2916 | // does not throw in the same tick and gets caught here |
edamame22 | 0:a9bcda5b678a | 2917 | setTimeout(function(){ |
edamame22 | 0:a9bcda5b678a | 2918 | self.onError(xhr.status); |
edamame22 | 0:a9bcda5b678a | 2919 | }, 0); |
edamame22 | 0:a9bcda5b678a | 2920 | } |
edamame22 | 0:a9bcda5b678a | 2921 | }; |
edamame22 | 0:a9bcda5b678a | 2922 | } |
edamame22 | 0:a9bcda5b678a | 2923 | |
edamame22 | 0:a9bcda5b678a | 2924 | debug('xhr data %s', this.data); |
edamame22 | 0:a9bcda5b678a | 2925 | xhr.send(this.data); |
edamame22 | 0:a9bcda5b678a | 2926 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 2927 | // Need to defer since .create() is called directly fhrom the constructor |
edamame22 | 0:a9bcda5b678a | 2928 | // and thus the 'error' event can only be only bound *after* this exception |
edamame22 | 0:a9bcda5b678a | 2929 | // occurs. Therefore, also, we cannot throw here at all. |
edamame22 | 0:a9bcda5b678a | 2930 | setTimeout(function() { |
edamame22 | 0:a9bcda5b678a | 2931 | self.onError(e); |
edamame22 | 0:a9bcda5b678a | 2932 | }, 0); |
edamame22 | 0:a9bcda5b678a | 2933 | return; |
edamame22 | 0:a9bcda5b678a | 2934 | } |
edamame22 | 0:a9bcda5b678a | 2935 | |
edamame22 | 0:a9bcda5b678a | 2936 | if (global.document) { |
edamame22 | 0:a9bcda5b678a | 2937 | this.index = Request.requestsCount++; |
edamame22 | 0:a9bcda5b678a | 2938 | Request.requests[this.index] = this; |
edamame22 | 0:a9bcda5b678a | 2939 | } |
edamame22 | 0:a9bcda5b678a | 2940 | }; |
edamame22 | 0:a9bcda5b678a | 2941 | |
edamame22 | 0:a9bcda5b678a | 2942 | /** |
edamame22 | 0:a9bcda5b678a | 2943 | * Called upon successful response. |
edamame22 | 0:a9bcda5b678a | 2944 | * |
edamame22 | 0:a9bcda5b678a | 2945 | * @api private |
edamame22 | 0:a9bcda5b678a | 2946 | */ |
edamame22 | 0:a9bcda5b678a | 2947 | |
edamame22 | 0:a9bcda5b678a | 2948 | Request.prototype.onSuccess = function(){ |
edamame22 | 0:a9bcda5b678a | 2949 | this.emit('success'); |
edamame22 | 0:a9bcda5b678a | 2950 | this.cleanup(); |
edamame22 | 0:a9bcda5b678a | 2951 | }; |
edamame22 | 0:a9bcda5b678a | 2952 | |
edamame22 | 0:a9bcda5b678a | 2953 | /** |
edamame22 | 0:a9bcda5b678a | 2954 | * Called if we have data. |
edamame22 | 0:a9bcda5b678a | 2955 | * |
edamame22 | 0:a9bcda5b678a | 2956 | * @api private |
edamame22 | 0:a9bcda5b678a | 2957 | */ |
edamame22 | 0:a9bcda5b678a | 2958 | |
edamame22 | 0:a9bcda5b678a | 2959 | Request.prototype.onData = function(data){ |
edamame22 | 0:a9bcda5b678a | 2960 | this.emit('data', data); |
edamame22 | 0:a9bcda5b678a | 2961 | this.onSuccess(); |
edamame22 | 0:a9bcda5b678a | 2962 | }; |
edamame22 | 0:a9bcda5b678a | 2963 | |
edamame22 | 0:a9bcda5b678a | 2964 | /** |
edamame22 | 0:a9bcda5b678a | 2965 | * Called upon error. |
edamame22 | 0:a9bcda5b678a | 2966 | * |
edamame22 | 0:a9bcda5b678a | 2967 | * @api private |
edamame22 | 0:a9bcda5b678a | 2968 | */ |
edamame22 | 0:a9bcda5b678a | 2969 | |
edamame22 | 0:a9bcda5b678a | 2970 | Request.prototype.onError = function(err){ |
edamame22 | 0:a9bcda5b678a | 2971 | this.emit('error', err); |
edamame22 | 0:a9bcda5b678a | 2972 | this.cleanup(true); |
edamame22 | 0:a9bcda5b678a | 2973 | }; |
edamame22 | 0:a9bcda5b678a | 2974 | |
edamame22 | 0:a9bcda5b678a | 2975 | /** |
edamame22 | 0:a9bcda5b678a | 2976 | * Cleans up house. |
edamame22 | 0:a9bcda5b678a | 2977 | * |
edamame22 | 0:a9bcda5b678a | 2978 | * @api private |
edamame22 | 0:a9bcda5b678a | 2979 | */ |
edamame22 | 0:a9bcda5b678a | 2980 | |
edamame22 | 0:a9bcda5b678a | 2981 | Request.prototype.cleanup = function(fromError){ |
edamame22 | 0:a9bcda5b678a | 2982 | if ('undefined' == typeof this.xhr || null === this.xhr) { |
edamame22 | 0:a9bcda5b678a | 2983 | return; |
edamame22 | 0:a9bcda5b678a | 2984 | } |
edamame22 | 0:a9bcda5b678a | 2985 | // xmlhttprequest |
edamame22 | 0:a9bcda5b678a | 2986 | if (this.hasXDR()) { |
edamame22 | 0:a9bcda5b678a | 2987 | this.xhr.onload = this.xhr.onerror = empty; |
edamame22 | 0:a9bcda5b678a | 2988 | } else { |
edamame22 | 0:a9bcda5b678a | 2989 | this.xhr.onreadystatechange = empty; |
edamame22 | 0:a9bcda5b678a | 2990 | } |
edamame22 | 0:a9bcda5b678a | 2991 | |
edamame22 | 0:a9bcda5b678a | 2992 | if (fromError) { |
edamame22 | 0:a9bcda5b678a | 2993 | try { |
edamame22 | 0:a9bcda5b678a | 2994 | this.xhr.abort(); |
edamame22 | 0:a9bcda5b678a | 2995 | } catch(e) {} |
edamame22 | 0:a9bcda5b678a | 2996 | } |
edamame22 | 0:a9bcda5b678a | 2997 | |
edamame22 | 0:a9bcda5b678a | 2998 | if (global.document) { |
edamame22 | 0:a9bcda5b678a | 2999 | delete Request.requests[this.index]; |
edamame22 | 0:a9bcda5b678a | 3000 | } |
edamame22 | 0:a9bcda5b678a | 3001 | |
edamame22 | 0:a9bcda5b678a | 3002 | this.xhr = null; |
edamame22 | 0:a9bcda5b678a | 3003 | }; |
edamame22 | 0:a9bcda5b678a | 3004 | |
edamame22 | 0:a9bcda5b678a | 3005 | /** |
edamame22 | 0:a9bcda5b678a | 3006 | * Called upon load. |
edamame22 | 0:a9bcda5b678a | 3007 | * |
edamame22 | 0:a9bcda5b678a | 3008 | * @api private |
edamame22 | 0:a9bcda5b678a | 3009 | */ |
edamame22 | 0:a9bcda5b678a | 3010 | |
edamame22 | 0:a9bcda5b678a | 3011 | Request.prototype.onLoad = function(){ |
edamame22 | 0:a9bcda5b678a | 3012 | var data; |
edamame22 | 0:a9bcda5b678a | 3013 | try { |
edamame22 | 0:a9bcda5b678a | 3014 | var contentType; |
edamame22 | 0:a9bcda5b678a | 3015 | try { |
edamame22 | 0:a9bcda5b678a | 3016 | contentType = this.xhr.getResponseHeader('Content-Type').split(';')[0]; |
edamame22 | 0:a9bcda5b678a | 3017 | } catch (e) {} |
edamame22 | 0:a9bcda5b678a | 3018 | if (contentType === 'application/octet-stream') { |
edamame22 | 0:a9bcda5b678a | 3019 | data = this.xhr.response; |
edamame22 | 0:a9bcda5b678a | 3020 | } else { |
edamame22 | 0:a9bcda5b678a | 3021 | if (!this.supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 3022 | data = this.xhr.responseText; |
edamame22 | 0:a9bcda5b678a | 3023 | } else { |
edamame22 | 0:a9bcda5b678a | 3024 | data = 'ok'; |
edamame22 | 0:a9bcda5b678a | 3025 | } |
edamame22 | 0:a9bcda5b678a | 3026 | } |
edamame22 | 0:a9bcda5b678a | 3027 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 3028 | this.onError(e); |
edamame22 | 0:a9bcda5b678a | 3029 | } |
edamame22 | 0:a9bcda5b678a | 3030 | if (null != data) { |
edamame22 | 0:a9bcda5b678a | 3031 | this.onData(data); |
edamame22 | 0:a9bcda5b678a | 3032 | } |
edamame22 | 0:a9bcda5b678a | 3033 | }; |
edamame22 | 0:a9bcda5b678a | 3034 | |
edamame22 | 0:a9bcda5b678a | 3035 | /** |
edamame22 | 0:a9bcda5b678a | 3036 | * Check if it has XDomainRequest. |
edamame22 | 0:a9bcda5b678a | 3037 | * |
edamame22 | 0:a9bcda5b678a | 3038 | * @api private |
edamame22 | 0:a9bcda5b678a | 3039 | */ |
edamame22 | 0:a9bcda5b678a | 3040 | |
edamame22 | 0:a9bcda5b678a | 3041 | Request.prototype.hasXDR = function(){ |
edamame22 | 0:a9bcda5b678a | 3042 | return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR; |
edamame22 | 0:a9bcda5b678a | 3043 | }; |
edamame22 | 0:a9bcda5b678a | 3044 | |
edamame22 | 0:a9bcda5b678a | 3045 | /** |
edamame22 | 0:a9bcda5b678a | 3046 | * Aborts the request. |
edamame22 | 0:a9bcda5b678a | 3047 | * |
edamame22 | 0:a9bcda5b678a | 3048 | * @api public |
edamame22 | 0:a9bcda5b678a | 3049 | */ |
edamame22 | 0:a9bcda5b678a | 3050 | |
edamame22 | 0:a9bcda5b678a | 3051 | Request.prototype.abort = function(){ |
edamame22 | 0:a9bcda5b678a | 3052 | this.cleanup(); |
edamame22 | 0:a9bcda5b678a | 3053 | }; |
edamame22 | 0:a9bcda5b678a | 3054 | |
edamame22 | 0:a9bcda5b678a | 3055 | /** |
edamame22 | 0:a9bcda5b678a | 3056 | * Aborts pending requests when unloading the window. This is needed to prevent |
edamame22 | 0:a9bcda5b678a | 3057 | * memory leaks (e.g. when using IE) and to ensure that no spurious error is |
edamame22 | 0:a9bcda5b678a | 3058 | * emitted. |
edamame22 | 0:a9bcda5b678a | 3059 | */ |
edamame22 | 0:a9bcda5b678a | 3060 | |
edamame22 | 0:a9bcda5b678a | 3061 | if (global.document) { |
edamame22 | 0:a9bcda5b678a | 3062 | Request.requestsCount = 0; |
edamame22 | 0:a9bcda5b678a | 3063 | Request.requests = {}; |
edamame22 | 0:a9bcda5b678a | 3064 | if (global.attachEvent) { |
edamame22 | 0:a9bcda5b678a | 3065 | global.attachEvent('onunload', unloadHandler); |
edamame22 | 0:a9bcda5b678a | 3066 | } else if (global.addEventListener) { |
edamame22 | 0:a9bcda5b678a | 3067 | global.addEventListener('beforeunload', unloadHandler, false); |
edamame22 | 0:a9bcda5b678a | 3068 | } |
edamame22 | 0:a9bcda5b678a | 3069 | } |
edamame22 | 0:a9bcda5b678a | 3070 | |
edamame22 | 0:a9bcda5b678a | 3071 | function unloadHandler() { |
edamame22 | 0:a9bcda5b678a | 3072 | for (var i in Request.requests) { |
edamame22 | 0:a9bcda5b678a | 3073 | if (Request.requests.hasOwnProperty(i)) { |
edamame22 | 0:a9bcda5b678a | 3074 | Request.requests[i].abort(); |
edamame22 | 0:a9bcda5b678a | 3075 | } |
edamame22 | 0:a9bcda5b678a | 3076 | } |
edamame22 | 0:a9bcda5b678a | 3077 | } |
edamame22 | 0:a9bcda5b678a | 3078 | |
edamame22 | 0:a9bcda5b678a | 3079 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 3080 | },{"./polling":18,"component-emitter":9,"component-inherit":21,"debug":22,"xmlhttprequest":20}],18:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3081 | /** |
edamame22 | 0:a9bcda5b678a | 3082 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 3083 | */ |
edamame22 | 0:a9bcda5b678a | 3084 | |
edamame22 | 0:a9bcda5b678a | 3085 | var Transport = _dereq_('../transport'); |
edamame22 | 0:a9bcda5b678a | 3086 | var parseqs = _dereq_('parseqs'); |
edamame22 | 0:a9bcda5b678a | 3087 | var parser = _dereq_('engine.io-parser'); |
edamame22 | 0:a9bcda5b678a | 3088 | var inherit = _dereq_('component-inherit'); |
edamame22 | 0:a9bcda5b678a | 3089 | var debug = _dereq_('debug')('engine.io-client:polling'); |
edamame22 | 0:a9bcda5b678a | 3090 | |
edamame22 | 0:a9bcda5b678a | 3091 | /** |
edamame22 | 0:a9bcda5b678a | 3092 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 3093 | */ |
edamame22 | 0:a9bcda5b678a | 3094 | |
edamame22 | 0:a9bcda5b678a | 3095 | module.exports = Polling; |
edamame22 | 0:a9bcda5b678a | 3096 | |
edamame22 | 0:a9bcda5b678a | 3097 | /** |
edamame22 | 0:a9bcda5b678a | 3098 | * Is XHR2 supported? |
edamame22 | 0:a9bcda5b678a | 3099 | */ |
edamame22 | 0:a9bcda5b678a | 3100 | |
edamame22 | 0:a9bcda5b678a | 3101 | var hasXHR2 = (function() { |
edamame22 | 0:a9bcda5b678a | 3102 | var XMLHttpRequest = _dereq_('xmlhttprequest'); |
edamame22 | 0:a9bcda5b678a | 3103 | var xhr = new XMLHttpRequest({ xdomain: false }); |
edamame22 | 0:a9bcda5b678a | 3104 | return null != xhr.responseType; |
edamame22 | 0:a9bcda5b678a | 3105 | })(); |
edamame22 | 0:a9bcda5b678a | 3106 | |
edamame22 | 0:a9bcda5b678a | 3107 | /** |
edamame22 | 0:a9bcda5b678a | 3108 | * Polling interface. |
edamame22 | 0:a9bcda5b678a | 3109 | * |
edamame22 | 0:a9bcda5b678a | 3110 | * @param {Object} opts |
edamame22 | 0:a9bcda5b678a | 3111 | * @api private |
edamame22 | 0:a9bcda5b678a | 3112 | */ |
edamame22 | 0:a9bcda5b678a | 3113 | |
edamame22 | 0:a9bcda5b678a | 3114 | function Polling(opts){ |
edamame22 | 0:a9bcda5b678a | 3115 | var forceBase64 = (opts && opts.forceBase64); |
edamame22 | 0:a9bcda5b678a | 3116 | if (!hasXHR2 || forceBase64) { |
edamame22 | 0:a9bcda5b678a | 3117 | this.supportsBinary = false; |
edamame22 | 0:a9bcda5b678a | 3118 | } |
edamame22 | 0:a9bcda5b678a | 3119 | Transport.call(this, opts); |
edamame22 | 0:a9bcda5b678a | 3120 | } |
edamame22 | 0:a9bcda5b678a | 3121 | |
edamame22 | 0:a9bcda5b678a | 3122 | /** |
edamame22 | 0:a9bcda5b678a | 3123 | * Inherits from Transport. |
edamame22 | 0:a9bcda5b678a | 3124 | */ |
edamame22 | 0:a9bcda5b678a | 3125 | |
edamame22 | 0:a9bcda5b678a | 3126 | inherit(Polling, Transport); |
edamame22 | 0:a9bcda5b678a | 3127 | |
edamame22 | 0:a9bcda5b678a | 3128 | /** |
edamame22 | 0:a9bcda5b678a | 3129 | * Transport name. |
edamame22 | 0:a9bcda5b678a | 3130 | */ |
edamame22 | 0:a9bcda5b678a | 3131 | |
edamame22 | 0:a9bcda5b678a | 3132 | Polling.prototype.name = 'polling'; |
edamame22 | 0:a9bcda5b678a | 3133 | |
edamame22 | 0:a9bcda5b678a | 3134 | /** |
edamame22 | 0:a9bcda5b678a | 3135 | * Opens the socket (triggers polling). We write a PING message to determine |
edamame22 | 0:a9bcda5b678a | 3136 | * when the transport is open. |
edamame22 | 0:a9bcda5b678a | 3137 | * |
edamame22 | 0:a9bcda5b678a | 3138 | * @api private |
edamame22 | 0:a9bcda5b678a | 3139 | */ |
edamame22 | 0:a9bcda5b678a | 3140 | |
edamame22 | 0:a9bcda5b678a | 3141 | Polling.prototype.doOpen = function(){ |
edamame22 | 0:a9bcda5b678a | 3142 | this.poll(); |
edamame22 | 0:a9bcda5b678a | 3143 | }; |
edamame22 | 0:a9bcda5b678a | 3144 | |
edamame22 | 0:a9bcda5b678a | 3145 | /** |
edamame22 | 0:a9bcda5b678a | 3146 | * Pauses polling. |
edamame22 | 0:a9bcda5b678a | 3147 | * |
edamame22 | 0:a9bcda5b678a | 3148 | * @param {Function} callback upon buffers are flushed and transport is paused |
edamame22 | 0:a9bcda5b678a | 3149 | * @api private |
edamame22 | 0:a9bcda5b678a | 3150 | */ |
edamame22 | 0:a9bcda5b678a | 3151 | |
edamame22 | 0:a9bcda5b678a | 3152 | Polling.prototype.pause = function(onPause){ |
edamame22 | 0:a9bcda5b678a | 3153 | var pending = 0; |
edamame22 | 0:a9bcda5b678a | 3154 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3155 | |
edamame22 | 0:a9bcda5b678a | 3156 | this.readyState = 'pausing'; |
edamame22 | 0:a9bcda5b678a | 3157 | |
edamame22 | 0:a9bcda5b678a | 3158 | function pause(){ |
edamame22 | 0:a9bcda5b678a | 3159 | debug('paused'); |
edamame22 | 0:a9bcda5b678a | 3160 | self.readyState = 'paused'; |
edamame22 | 0:a9bcda5b678a | 3161 | onPause(); |
edamame22 | 0:a9bcda5b678a | 3162 | } |
edamame22 | 0:a9bcda5b678a | 3163 | |
edamame22 | 0:a9bcda5b678a | 3164 | if (this.polling || !this.writable) { |
edamame22 | 0:a9bcda5b678a | 3165 | var total = 0; |
edamame22 | 0:a9bcda5b678a | 3166 | |
edamame22 | 0:a9bcda5b678a | 3167 | if (this.polling) { |
edamame22 | 0:a9bcda5b678a | 3168 | debug('we are currently polling - waiting to pause'); |
edamame22 | 0:a9bcda5b678a | 3169 | total++; |
edamame22 | 0:a9bcda5b678a | 3170 | this.once('pollComplete', function(){ |
edamame22 | 0:a9bcda5b678a | 3171 | debug('pre-pause polling complete'); |
edamame22 | 0:a9bcda5b678a | 3172 | --total || pause(); |
edamame22 | 0:a9bcda5b678a | 3173 | }); |
edamame22 | 0:a9bcda5b678a | 3174 | } |
edamame22 | 0:a9bcda5b678a | 3175 | |
edamame22 | 0:a9bcda5b678a | 3176 | if (!this.writable) { |
edamame22 | 0:a9bcda5b678a | 3177 | debug('we are currently writing - waiting to pause'); |
edamame22 | 0:a9bcda5b678a | 3178 | total++; |
edamame22 | 0:a9bcda5b678a | 3179 | this.once('drain', function(){ |
edamame22 | 0:a9bcda5b678a | 3180 | debug('pre-pause writing complete'); |
edamame22 | 0:a9bcda5b678a | 3181 | --total || pause(); |
edamame22 | 0:a9bcda5b678a | 3182 | }); |
edamame22 | 0:a9bcda5b678a | 3183 | } |
edamame22 | 0:a9bcda5b678a | 3184 | } else { |
edamame22 | 0:a9bcda5b678a | 3185 | pause(); |
edamame22 | 0:a9bcda5b678a | 3186 | } |
edamame22 | 0:a9bcda5b678a | 3187 | }; |
edamame22 | 0:a9bcda5b678a | 3188 | |
edamame22 | 0:a9bcda5b678a | 3189 | /** |
edamame22 | 0:a9bcda5b678a | 3190 | * Starts polling cycle. |
edamame22 | 0:a9bcda5b678a | 3191 | * |
edamame22 | 0:a9bcda5b678a | 3192 | * @api public |
edamame22 | 0:a9bcda5b678a | 3193 | */ |
edamame22 | 0:a9bcda5b678a | 3194 | |
edamame22 | 0:a9bcda5b678a | 3195 | Polling.prototype.poll = function(){ |
edamame22 | 0:a9bcda5b678a | 3196 | debug('polling'); |
edamame22 | 0:a9bcda5b678a | 3197 | this.polling = true; |
edamame22 | 0:a9bcda5b678a | 3198 | this.doPoll(); |
edamame22 | 0:a9bcda5b678a | 3199 | this.emit('poll'); |
edamame22 | 0:a9bcda5b678a | 3200 | }; |
edamame22 | 0:a9bcda5b678a | 3201 | |
edamame22 | 0:a9bcda5b678a | 3202 | /** |
edamame22 | 0:a9bcda5b678a | 3203 | * Overloads onData to detect payloads. |
edamame22 | 0:a9bcda5b678a | 3204 | * |
edamame22 | 0:a9bcda5b678a | 3205 | * @api private |
edamame22 | 0:a9bcda5b678a | 3206 | */ |
edamame22 | 0:a9bcda5b678a | 3207 | |
edamame22 | 0:a9bcda5b678a | 3208 | Polling.prototype.onData = function(data){ |
edamame22 | 0:a9bcda5b678a | 3209 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3210 | debug('polling got data %s', data); |
edamame22 | 0:a9bcda5b678a | 3211 | var callback = function(packet, index, total) { |
edamame22 | 0:a9bcda5b678a | 3212 | // if its the first message we consider the transport open |
edamame22 | 0:a9bcda5b678a | 3213 | if ('opening' == self.readyState) { |
edamame22 | 0:a9bcda5b678a | 3214 | self.onOpen(); |
edamame22 | 0:a9bcda5b678a | 3215 | } |
edamame22 | 0:a9bcda5b678a | 3216 | |
edamame22 | 0:a9bcda5b678a | 3217 | // if its a close packet, we close the ongoing requests |
edamame22 | 0:a9bcda5b678a | 3218 | if ('close' == packet.type) { |
edamame22 | 0:a9bcda5b678a | 3219 | self.onClose(); |
edamame22 | 0:a9bcda5b678a | 3220 | return false; |
edamame22 | 0:a9bcda5b678a | 3221 | } |
edamame22 | 0:a9bcda5b678a | 3222 | |
edamame22 | 0:a9bcda5b678a | 3223 | // otherwise bypass onData and handle the message |
edamame22 | 0:a9bcda5b678a | 3224 | self.onPacket(packet); |
edamame22 | 0:a9bcda5b678a | 3225 | }; |
edamame22 | 0:a9bcda5b678a | 3226 | |
edamame22 | 0:a9bcda5b678a | 3227 | // decode payload |
edamame22 | 0:a9bcda5b678a | 3228 | parser.decodePayload(data, this.socket.binaryType, callback); |
edamame22 | 0:a9bcda5b678a | 3229 | |
edamame22 | 0:a9bcda5b678a | 3230 | // if an event did not trigger closing |
edamame22 | 0:a9bcda5b678a | 3231 | if ('closed' != this.readyState) { |
edamame22 | 0:a9bcda5b678a | 3232 | // if we got data we're not polling |
edamame22 | 0:a9bcda5b678a | 3233 | this.polling = false; |
edamame22 | 0:a9bcda5b678a | 3234 | this.emit('pollComplete'); |
edamame22 | 0:a9bcda5b678a | 3235 | |
edamame22 | 0:a9bcda5b678a | 3236 | if ('open' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 3237 | this.poll(); |
edamame22 | 0:a9bcda5b678a | 3238 | } else { |
edamame22 | 0:a9bcda5b678a | 3239 | debug('ignoring poll - transport state "%s"', this.readyState); |
edamame22 | 0:a9bcda5b678a | 3240 | } |
edamame22 | 0:a9bcda5b678a | 3241 | } |
edamame22 | 0:a9bcda5b678a | 3242 | }; |
edamame22 | 0:a9bcda5b678a | 3243 | |
edamame22 | 0:a9bcda5b678a | 3244 | /** |
edamame22 | 0:a9bcda5b678a | 3245 | * For polling, send a close packet. |
edamame22 | 0:a9bcda5b678a | 3246 | * |
edamame22 | 0:a9bcda5b678a | 3247 | * @api private |
edamame22 | 0:a9bcda5b678a | 3248 | */ |
edamame22 | 0:a9bcda5b678a | 3249 | |
edamame22 | 0:a9bcda5b678a | 3250 | Polling.prototype.doClose = function(){ |
edamame22 | 0:a9bcda5b678a | 3251 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3252 | |
edamame22 | 0:a9bcda5b678a | 3253 | function close(){ |
edamame22 | 0:a9bcda5b678a | 3254 | debug('writing close packet'); |
edamame22 | 0:a9bcda5b678a | 3255 | self.write([{ type: 'close' }]); |
edamame22 | 0:a9bcda5b678a | 3256 | } |
edamame22 | 0:a9bcda5b678a | 3257 | |
edamame22 | 0:a9bcda5b678a | 3258 | if ('open' == this.readyState) { |
edamame22 | 0:a9bcda5b678a | 3259 | debug('transport open - closing'); |
edamame22 | 0:a9bcda5b678a | 3260 | close(); |
edamame22 | 0:a9bcda5b678a | 3261 | } else { |
edamame22 | 0:a9bcda5b678a | 3262 | // in case we're trying to close while |
edamame22 | 0:a9bcda5b678a | 3263 | // handshaking is in progress (GH-164) |
edamame22 | 0:a9bcda5b678a | 3264 | debug('transport not open - deferring close'); |
edamame22 | 0:a9bcda5b678a | 3265 | this.once('open', close); |
edamame22 | 0:a9bcda5b678a | 3266 | } |
edamame22 | 0:a9bcda5b678a | 3267 | }; |
edamame22 | 0:a9bcda5b678a | 3268 | |
edamame22 | 0:a9bcda5b678a | 3269 | /** |
edamame22 | 0:a9bcda5b678a | 3270 | * Writes a packets payload. |
edamame22 | 0:a9bcda5b678a | 3271 | * |
edamame22 | 0:a9bcda5b678a | 3272 | * @param {Array} data packets |
edamame22 | 0:a9bcda5b678a | 3273 | * @param {Function} drain callback |
edamame22 | 0:a9bcda5b678a | 3274 | * @api private |
edamame22 | 0:a9bcda5b678a | 3275 | */ |
edamame22 | 0:a9bcda5b678a | 3276 | |
edamame22 | 0:a9bcda5b678a | 3277 | Polling.prototype.write = function(packets){ |
edamame22 | 0:a9bcda5b678a | 3278 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3279 | this.writable = false; |
edamame22 | 0:a9bcda5b678a | 3280 | var callbackfn = function() { |
edamame22 | 0:a9bcda5b678a | 3281 | self.writable = true; |
edamame22 | 0:a9bcda5b678a | 3282 | self.emit('drain'); |
edamame22 | 0:a9bcda5b678a | 3283 | }; |
edamame22 | 0:a9bcda5b678a | 3284 | |
edamame22 | 0:a9bcda5b678a | 3285 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3286 | parser.encodePayload(packets, this.supportsBinary, function(data) { |
edamame22 | 0:a9bcda5b678a | 3287 | self.doWrite(data, callbackfn); |
edamame22 | 0:a9bcda5b678a | 3288 | }); |
edamame22 | 0:a9bcda5b678a | 3289 | }; |
edamame22 | 0:a9bcda5b678a | 3290 | |
edamame22 | 0:a9bcda5b678a | 3291 | /** |
edamame22 | 0:a9bcda5b678a | 3292 | * Generates uri for connection. |
edamame22 | 0:a9bcda5b678a | 3293 | * |
edamame22 | 0:a9bcda5b678a | 3294 | * @api private |
edamame22 | 0:a9bcda5b678a | 3295 | */ |
edamame22 | 0:a9bcda5b678a | 3296 | |
edamame22 | 0:a9bcda5b678a | 3297 | Polling.prototype.uri = function(){ |
edamame22 | 0:a9bcda5b678a | 3298 | var query = this.query || {}; |
edamame22 | 0:a9bcda5b678a | 3299 | var schema = this.secure ? 'https' : 'http'; |
edamame22 | 0:a9bcda5b678a | 3300 | var port = ''; |
edamame22 | 0:a9bcda5b678a | 3301 | |
edamame22 | 0:a9bcda5b678a | 3302 | // cache busting is forced |
edamame22 | 0:a9bcda5b678a | 3303 | if (false !== this.timestampRequests) { |
edamame22 | 0:a9bcda5b678a | 3304 | query[this.timestampParam] = +new Date + '-' + Transport.timestamps++; |
edamame22 | 0:a9bcda5b678a | 3305 | } |
edamame22 | 0:a9bcda5b678a | 3306 | |
edamame22 | 0:a9bcda5b678a | 3307 | if (!this.supportsBinary && !query.sid) { |
edamame22 | 0:a9bcda5b678a | 3308 | query.b64 = 1; |
edamame22 | 0:a9bcda5b678a | 3309 | } |
edamame22 | 0:a9bcda5b678a | 3310 | |
edamame22 | 0:a9bcda5b678a | 3311 | query = parseqs.encode(query); |
edamame22 | 0:a9bcda5b678a | 3312 | |
edamame22 | 0:a9bcda5b678a | 3313 | // avoid port if default for schema |
edamame22 | 0:a9bcda5b678a | 3314 | if (this.port && (('https' == schema && this.port != 443) || |
edamame22 | 0:a9bcda5b678a | 3315 | ('http' == schema && this.port != 80))) { |
edamame22 | 0:a9bcda5b678a | 3316 | port = ':' + this.port; |
edamame22 | 0:a9bcda5b678a | 3317 | } |
edamame22 | 0:a9bcda5b678a | 3318 | |
edamame22 | 0:a9bcda5b678a | 3319 | // prepend ? to query |
edamame22 | 0:a9bcda5b678a | 3320 | if (query.length) { |
edamame22 | 0:a9bcda5b678a | 3321 | query = '?' + query; |
edamame22 | 0:a9bcda5b678a | 3322 | } |
edamame22 | 0:a9bcda5b678a | 3323 | |
edamame22 | 0:a9bcda5b678a | 3324 | return schema + '://' + this.hostname + port + this.path + query; |
edamame22 | 0:a9bcda5b678a | 3325 | }; |
edamame22 | 0:a9bcda5b678a | 3326 | |
edamame22 | 0:a9bcda5b678a | 3327 | },{"../transport":14,"component-inherit":21,"debug":22,"engine.io-parser":25,"parseqs":35,"xmlhttprequest":20}],19:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3328 | /** |
edamame22 | 0:a9bcda5b678a | 3329 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 3330 | */ |
edamame22 | 0:a9bcda5b678a | 3331 | |
edamame22 | 0:a9bcda5b678a | 3332 | var Transport = _dereq_('../transport'); |
edamame22 | 0:a9bcda5b678a | 3333 | var parser = _dereq_('engine.io-parser'); |
edamame22 | 0:a9bcda5b678a | 3334 | var parseqs = _dereq_('parseqs'); |
edamame22 | 0:a9bcda5b678a | 3335 | var inherit = _dereq_('component-inherit'); |
edamame22 | 0:a9bcda5b678a | 3336 | var debug = _dereq_('debug')('engine.io-client:websocket'); |
edamame22 | 0:a9bcda5b678a | 3337 | |
edamame22 | 0:a9bcda5b678a | 3338 | /** |
edamame22 | 0:a9bcda5b678a | 3339 | * `ws` exposes a WebSocket-compatible interface in |
edamame22 | 0:a9bcda5b678a | 3340 | * Node, or the `WebSocket` or `MozWebSocket` globals |
edamame22 | 0:a9bcda5b678a | 3341 | * in the browser. |
edamame22 | 0:a9bcda5b678a | 3342 | */ |
edamame22 | 0:a9bcda5b678a | 3343 | |
edamame22 | 0:a9bcda5b678a | 3344 | var WebSocket = _dereq_('ws'); |
edamame22 | 0:a9bcda5b678a | 3345 | |
edamame22 | 0:a9bcda5b678a | 3346 | /** |
edamame22 | 0:a9bcda5b678a | 3347 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 3348 | */ |
edamame22 | 0:a9bcda5b678a | 3349 | |
edamame22 | 0:a9bcda5b678a | 3350 | module.exports = WS; |
edamame22 | 0:a9bcda5b678a | 3351 | |
edamame22 | 0:a9bcda5b678a | 3352 | /** |
edamame22 | 0:a9bcda5b678a | 3353 | * WebSocket transport constructor. |
edamame22 | 0:a9bcda5b678a | 3354 | * |
edamame22 | 0:a9bcda5b678a | 3355 | * @api {Object} connection options |
edamame22 | 0:a9bcda5b678a | 3356 | * @api public |
edamame22 | 0:a9bcda5b678a | 3357 | */ |
edamame22 | 0:a9bcda5b678a | 3358 | |
edamame22 | 0:a9bcda5b678a | 3359 | function WS(opts){ |
edamame22 | 0:a9bcda5b678a | 3360 | var forceBase64 = (opts && opts.forceBase64); |
edamame22 | 0:a9bcda5b678a | 3361 | if (forceBase64) { |
edamame22 | 0:a9bcda5b678a | 3362 | this.supportsBinary = false; |
edamame22 | 0:a9bcda5b678a | 3363 | } |
edamame22 | 0:a9bcda5b678a | 3364 | Transport.call(this, opts); |
edamame22 | 0:a9bcda5b678a | 3365 | } |
edamame22 | 0:a9bcda5b678a | 3366 | |
edamame22 | 0:a9bcda5b678a | 3367 | /** |
edamame22 | 0:a9bcda5b678a | 3368 | * Inherits from Transport. |
edamame22 | 0:a9bcda5b678a | 3369 | */ |
edamame22 | 0:a9bcda5b678a | 3370 | |
edamame22 | 0:a9bcda5b678a | 3371 | inherit(WS, Transport); |
edamame22 | 0:a9bcda5b678a | 3372 | |
edamame22 | 0:a9bcda5b678a | 3373 | /** |
edamame22 | 0:a9bcda5b678a | 3374 | * Transport name. |
edamame22 | 0:a9bcda5b678a | 3375 | * |
edamame22 | 0:a9bcda5b678a | 3376 | * @api public |
edamame22 | 0:a9bcda5b678a | 3377 | */ |
edamame22 | 0:a9bcda5b678a | 3378 | |
edamame22 | 0:a9bcda5b678a | 3379 | WS.prototype.name = 'websocket'; |
edamame22 | 0:a9bcda5b678a | 3380 | |
edamame22 | 0:a9bcda5b678a | 3381 | /* |
edamame22 | 0:a9bcda5b678a | 3382 | * WebSockets support binary |
edamame22 | 0:a9bcda5b678a | 3383 | */ |
edamame22 | 0:a9bcda5b678a | 3384 | |
edamame22 | 0:a9bcda5b678a | 3385 | WS.prototype.supportsBinary = true; |
edamame22 | 0:a9bcda5b678a | 3386 | |
edamame22 | 0:a9bcda5b678a | 3387 | /** |
edamame22 | 0:a9bcda5b678a | 3388 | * Opens socket. |
edamame22 | 0:a9bcda5b678a | 3389 | * |
edamame22 | 0:a9bcda5b678a | 3390 | * @api private |
edamame22 | 0:a9bcda5b678a | 3391 | */ |
edamame22 | 0:a9bcda5b678a | 3392 | |
edamame22 | 0:a9bcda5b678a | 3393 | WS.prototype.doOpen = function(){ |
edamame22 | 0:a9bcda5b678a | 3394 | if (!this.check()) { |
edamame22 | 0:a9bcda5b678a | 3395 | // let probe timeout |
edamame22 | 0:a9bcda5b678a | 3396 | return; |
edamame22 | 0:a9bcda5b678a | 3397 | } |
edamame22 | 0:a9bcda5b678a | 3398 | |
edamame22 | 0:a9bcda5b678a | 3399 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3400 | var uri = this.uri(); |
edamame22 | 0:a9bcda5b678a | 3401 | var protocols = void(0); |
edamame22 | 0:a9bcda5b678a | 3402 | var opts = { agent: this.agent }; |
edamame22 | 0:a9bcda5b678a | 3403 | |
edamame22 | 0:a9bcda5b678a | 3404 | // SSL options for Node.js client |
edamame22 | 0:a9bcda5b678a | 3405 | opts.pfx = this.pfx; |
edamame22 | 0:a9bcda5b678a | 3406 | opts.key = this.key; |
edamame22 | 0:a9bcda5b678a | 3407 | opts.passphrase = this.passphrase; |
edamame22 | 0:a9bcda5b678a | 3408 | opts.cert = this.cert; |
edamame22 | 0:a9bcda5b678a | 3409 | opts.ca = this.ca; |
edamame22 | 0:a9bcda5b678a | 3410 | opts.ciphers = this.ciphers; |
edamame22 | 0:a9bcda5b678a | 3411 | opts.rejectUnauthorized = this.rejectUnauthorized; |
edamame22 | 0:a9bcda5b678a | 3412 | |
edamame22 | 0:a9bcda5b678a | 3413 | this.ws = new WebSocket(uri, protocols, opts); |
edamame22 | 0:a9bcda5b678a | 3414 | |
edamame22 | 0:a9bcda5b678a | 3415 | if (this.ws.binaryType === undefined) { |
edamame22 | 0:a9bcda5b678a | 3416 | this.supportsBinary = false; |
edamame22 | 0:a9bcda5b678a | 3417 | } |
edamame22 | 0:a9bcda5b678a | 3418 | |
edamame22 | 0:a9bcda5b678a | 3419 | this.ws.binaryType = 'arraybuffer'; |
edamame22 | 0:a9bcda5b678a | 3420 | this.addEventListeners(); |
edamame22 | 0:a9bcda5b678a | 3421 | }; |
edamame22 | 0:a9bcda5b678a | 3422 | |
edamame22 | 0:a9bcda5b678a | 3423 | /** |
edamame22 | 0:a9bcda5b678a | 3424 | * Adds event listeners to the socket |
edamame22 | 0:a9bcda5b678a | 3425 | * |
edamame22 | 0:a9bcda5b678a | 3426 | * @api private |
edamame22 | 0:a9bcda5b678a | 3427 | */ |
edamame22 | 0:a9bcda5b678a | 3428 | |
edamame22 | 0:a9bcda5b678a | 3429 | WS.prototype.addEventListeners = function(){ |
edamame22 | 0:a9bcda5b678a | 3430 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3431 | |
edamame22 | 0:a9bcda5b678a | 3432 | this.ws.onopen = function(){ |
edamame22 | 0:a9bcda5b678a | 3433 | self.onOpen(); |
edamame22 | 0:a9bcda5b678a | 3434 | }; |
edamame22 | 0:a9bcda5b678a | 3435 | this.ws.onclose = function(){ |
edamame22 | 0:a9bcda5b678a | 3436 | self.onClose(); |
edamame22 | 0:a9bcda5b678a | 3437 | }; |
edamame22 | 0:a9bcda5b678a | 3438 | this.ws.onmessage = function(ev){ |
edamame22 | 0:a9bcda5b678a | 3439 | self.onData(ev.data); |
edamame22 | 0:a9bcda5b678a | 3440 | }; |
edamame22 | 0:a9bcda5b678a | 3441 | this.ws.onerror = function(e){ |
edamame22 | 0:a9bcda5b678a | 3442 | self.onError('websocket error', e); |
edamame22 | 0:a9bcda5b678a | 3443 | }; |
edamame22 | 0:a9bcda5b678a | 3444 | }; |
edamame22 | 0:a9bcda5b678a | 3445 | |
edamame22 | 0:a9bcda5b678a | 3446 | /** |
edamame22 | 0:a9bcda5b678a | 3447 | * Override `onData` to use a timer on iOS. |
edamame22 | 0:a9bcda5b678a | 3448 | * See: https://gist.github.com/mloughran/2052006 |
edamame22 | 0:a9bcda5b678a | 3449 | * |
edamame22 | 0:a9bcda5b678a | 3450 | * @api private |
edamame22 | 0:a9bcda5b678a | 3451 | */ |
edamame22 | 0:a9bcda5b678a | 3452 | |
edamame22 | 0:a9bcda5b678a | 3453 | if ('undefined' != typeof navigator |
edamame22 | 0:a9bcda5b678a | 3454 | && /iPad|iPhone|iPod/i.test(navigator.userAgent)) { |
edamame22 | 0:a9bcda5b678a | 3455 | WS.prototype.onData = function(data){ |
edamame22 | 0:a9bcda5b678a | 3456 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3457 | setTimeout(function(){ |
edamame22 | 0:a9bcda5b678a | 3458 | Transport.prototype.onData.call(self, data); |
edamame22 | 0:a9bcda5b678a | 3459 | }, 0); |
edamame22 | 0:a9bcda5b678a | 3460 | }; |
edamame22 | 0:a9bcda5b678a | 3461 | } |
edamame22 | 0:a9bcda5b678a | 3462 | |
edamame22 | 0:a9bcda5b678a | 3463 | /** |
edamame22 | 0:a9bcda5b678a | 3464 | * Writes data to socket. |
edamame22 | 0:a9bcda5b678a | 3465 | * |
edamame22 | 0:a9bcda5b678a | 3466 | * @param {Array} array of packets. |
edamame22 | 0:a9bcda5b678a | 3467 | * @api private |
edamame22 | 0:a9bcda5b678a | 3468 | */ |
edamame22 | 0:a9bcda5b678a | 3469 | |
edamame22 | 0:a9bcda5b678a | 3470 | WS.prototype.write = function(packets){ |
edamame22 | 0:a9bcda5b678a | 3471 | var self = this; |
edamame22 | 0:a9bcda5b678a | 3472 | this.writable = false; |
edamame22 | 0:a9bcda5b678a | 3473 | // encodePacket efficient as it uses WS framing |
edamame22 | 0:a9bcda5b678a | 3474 | // no need for encodePayload |
edamame22 | 0:a9bcda5b678a | 3475 | for (var i = 0, l = packets.length; i < l; i++) { |
edamame22 | 0:a9bcda5b678a | 3476 | parser.encodePacket(packets[i], this.supportsBinary, function(data) { |
edamame22 | 0:a9bcda5b678a | 3477 | //Sometimes the websocket has already been closed but the browser didn't |
edamame22 | 0:a9bcda5b678a | 3478 | //have a chance of informing us about it yet, in that case send will |
edamame22 | 0:a9bcda5b678a | 3479 | //throw an error |
edamame22 | 0:a9bcda5b678a | 3480 | try { |
edamame22 | 0:a9bcda5b678a | 3481 | self.ws.send(data); |
edamame22 | 0:a9bcda5b678a | 3482 | } catch (e){ |
edamame22 | 0:a9bcda5b678a | 3483 | debug('websocket closed before onclose event'); |
edamame22 | 0:a9bcda5b678a | 3484 | } |
edamame22 | 0:a9bcda5b678a | 3485 | }); |
edamame22 | 0:a9bcda5b678a | 3486 | } |
edamame22 | 0:a9bcda5b678a | 3487 | |
edamame22 | 0:a9bcda5b678a | 3488 | function ondrain() { |
edamame22 | 0:a9bcda5b678a | 3489 | self.writable = true; |
edamame22 | 0:a9bcda5b678a | 3490 | self.emit('drain'); |
edamame22 | 0:a9bcda5b678a | 3491 | } |
edamame22 | 0:a9bcda5b678a | 3492 | // fake drain |
edamame22 | 0:a9bcda5b678a | 3493 | // defer to next tick to allow Socket to clear writeBuffer |
edamame22 | 0:a9bcda5b678a | 3494 | setTimeout(ondrain, 0); |
edamame22 | 0:a9bcda5b678a | 3495 | }; |
edamame22 | 0:a9bcda5b678a | 3496 | |
edamame22 | 0:a9bcda5b678a | 3497 | /** |
edamame22 | 0:a9bcda5b678a | 3498 | * Called upon close |
edamame22 | 0:a9bcda5b678a | 3499 | * |
edamame22 | 0:a9bcda5b678a | 3500 | * @api private |
edamame22 | 0:a9bcda5b678a | 3501 | */ |
edamame22 | 0:a9bcda5b678a | 3502 | |
edamame22 | 0:a9bcda5b678a | 3503 | WS.prototype.onClose = function(){ |
edamame22 | 0:a9bcda5b678a | 3504 | Transport.prototype.onClose.call(this); |
edamame22 | 0:a9bcda5b678a | 3505 | }; |
edamame22 | 0:a9bcda5b678a | 3506 | |
edamame22 | 0:a9bcda5b678a | 3507 | /** |
edamame22 | 0:a9bcda5b678a | 3508 | * Closes socket. |
edamame22 | 0:a9bcda5b678a | 3509 | * |
edamame22 | 0:a9bcda5b678a | 3510 | * @api private |
edamame22 | 0:a9bcda5b678a | 3511 | */ |
edamame22 | 0:a9bcda5b678a | 3512 | |
edamame22 | 0:a9bcda5b678a | 3513 | WS.prototype.doClose = function(){ |
edamame22 | 0:a9bcda5b678a | 3514 | if (typeof this.ws !== 'undefined') { |
edamame22 | 0:a9bcda5b678a | 3515 | this.ws.close(); |
edamame22 | 0:a9bcda5b678a | 3516 | } |
edamame22 | 0:a9bcda5b678a | 3517 | }; |
edamame22 | 0:a9bcda5b678a | 3518 | |
edamame22 | 0:a9bcda5b678a | 3519 | /** |
edamame22 | 0:a9bcda5b678a | 3520 | * Generates uri for connection. |
edamame22 | 0:a9bcda5b678a | 3521 | * |
edamame22 | 0:a9bcda5b678a | 3522 | * @api private |
edamame22 | 0:a9bcda5b678a | 3523 | */ |
edamame22 | 0:a9bcda5b678a | 3524 | |
edamame22 | 0:a9bcda5b678a | 3525 | WS.prototype.uri = function(){ |
edamame22 | 0:a9bcda5b678a | 3526 | var query = this.query || {}; |
edamame22 | 0:a9bcda5b678a | 3527 | var schema = this.secure ? 'wss' : 'ws'; |
edamame22 | 0:a9bcda5b678a | 3528 | var port = ''; |
edamame22 | 0:a9bcda5b678a | 3529 | |
edamame22 | 0:a9bcda5b678a | 3530 | // avoid port if default for schema |
edamame22 | 0:a9bcda5b678a | 3531 | if (this.port && (('wss' == schema && this.port != 443) |
edamame22 | 0:a9bcda5b678a | 3532 | || ('ws' == schema && this.port != 80))) { |
edamame22 | 0:a9bcda5b678a | 3533 | port = ':' + this.port; |
edamame22 | 0:a9bcda5b678a | 3534 | } |
edamame22 | 0:a9bcda5b678a | 3535 | |
edamame22 | 0:a9bcda5b678a | 3536 | // append timestamp to URI |
edamame22 | 0:a9bcda5b678a | 3537 | if (this.timestampRequests) { |
edamame22 | 0:a9bcda5b678a | 3538 | query[this.timestampParam] = +new Date; |
edamame22 | 0:a9bcda5b678a | 3539 | } |
edamame22 | 0:a9bcda5b678a | 3540 | |
edamame22 | 0:a9bcda5b678a | 3541 | // communicate binary support capabilities |
edamame22 | 0:a9bcda5b678a | 3542 | if (!this.supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 3543 | query.b64 = 1; |
edamame22 | 0:a9bcda5b678a | 3544 | } |
edamame22 | 0:a9bcda5b678a | 3545 | |
edamame22 | 0:a9bcda5b678a | 3546 | query = parseqs.encode(query); |
edamame22 | 0:a9bcda5b678a | 3547 | |
edamame22 | 0:a9bcda5b678a | 3548 | // prepend ? to query |
edamame22 | 0:a9bcda5b678a | 3549 | if (query.length) { |
edamame22 | 0:a9bcda5b678a | 3550 | query = '?' + query; |
edamame22 | 0:a9bcda5b678a | 3551 | } |
edamame22 | 0:a9bcda5b678a | 3552 | |
edamame22 | 0:a9bcda5b678a | 3553 | return schema + '://' + this.hostname + port + this.path + query; |
edamame22 | 0:a9bcda5b678a | 3554 | }; |
edamame22 | 0:a9bcda5b678a | 3555 | |
edamame22 | 0:a9bcda5b678a | 3556 | /** |
edamame22 | 0:a9bcda5b678a | 3557 | * Feature detection for WebSocket. |
edamame22 | 0:a9bcda5b678a | 3558 | * |
edamame22 | 0:a9bcda5b678a | 3559 | * @return {Boolean} whether this transport is available. |
edamame22 | 0:a9bcda5b678a | 3560 | * @api public |
edamame22 | 0:a9bcda5b678a | 3561 | */ |
edamame22 | 0:a9bcda5b678a | 3562 | |
edamame22 | 0:a9bcda5b678a | 3563 | WS.prototype.check = function(){ |
edamame22 | 0:a9bcda5b678a | 3564 | return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name); |
edamame22 | 0:a9bcda5b678a | 3565 | }; |
edamame22 | 0:a9bcda5b678a | 3566 | |
edamame22 | 0:a9bcda5b678a | 3567 | },{"../transport":14,"component-inherit":21,"debug":22,"engine.io-parser":25,"parseqs":35,"ws":37}],20:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3568 | // browser shim for xmlhttprequest module |
edamame22 | 0:a9bcda5b678a | 3569 | var hasCORS = _dereq_('has-cors'); |
edamame22 | 0:a9bcda5b678a | 3570 | |
edamame22 | 0:a9bcda5b678a | 3571 | module.exports = function(opts) { |
edamame22 | 0:a9bcda5b678a | 3572 | var xdomain = opts.xdomain; |
edamame22 | 0:a9bcda5b678a | 3573 | |
edamame22 | 0:a9bcda5b678a | 3574 | // scheme must be same when usign XDomainRequest |
edamame22 | 0:a9bcda5b678a | 3575 | // http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx |
edamame22 | 0:a9bcda5b678a | 3576 | var xscheme = opts.xscheme; |
edamame22 | 0:a9bcda5b678a | 3577 | |
edamame22 | 0:a9bcda5b678a | 3578 | // XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default. |
edamame22 | 0:a9bcda5b678a | 3579 | // https://github.com/Automattic/engine.io-client/pull/217 |
edamame22 | 0:a9bcda5b678a | 3580 | var enablesXDR = opts.enablesXDR; |
edamame22 | 0:a9bcda5b678a | 3581 | |
edamame22 | 0:a9bcda5b678a | 3582 | // XMLHttpRequest can be disabled on IE |
edamame22 | 0:a9bcda5b678a | 3583 | try { |
edamame22 | 0:a9bcda5b678a | 3584 | if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) { |
edamame22 | 0:a9bcda5b678a | 3585 | return new XMLHttpRequest(); |
edamame22 | 0:a9bcda5b678a | 3586 | } |
edamame22 | 0:a9bcda5b678a | 3587 | } catch (e) { } |
edamame22 | 0:a9bcda5b678a | 3588 | |
edamame22 | 0:a9bcda5b678a | 3589 | // Use XDomainRequest for IE8 if enablesXDR is true |
edamame22 | 0:a9bcda5b678a | 3590 | // because loading bar keeps flashing when using jsonp-polling |
edamame22 | 0:a9bcda5b678a | 3591 | // https://github.com/yujiosaka/socke.io-ie8-loading-example |
edamame22 | 0:a9bcda5b678a | 3592 | try { |
edamame22 | 0:a9bcda5b678a | 3593 | if ('undefined' != typeof XDomainRequest && !xscheme && enablesXDR) { |
edamame22 | 0:a9bcda5b678a | 3594 | return new XDomainRequest(); |
edamame22 | 0:a9bcda5b678a | 3595 | } |
edamame22 | 0:a9bcda5b678a | 3596 | } catch (e) { } |
edamame22 | 0:a9bcda5b678a | 3597 | |
edamame22 | 0:a9bcda5b678a | 3598 | if (!xdomain) { |
edamame22 | 0:a9bcda5b678a | 3599 | try { |
edamame22 | 0:a9bcda5b678a | 3600 | return new ActiveXObject('Microsoft.XMLHTTP'); |
edamame22 | 0:a9bcda5b678a | 3601 | } catch(e) { } |
edamame22 | 0:a9bcda5b678a | 3602 | } |
edamame22 | 0:a9bcda5b678a | 3603 | } |
edamame22 | 0:a9bcda5b678a | 3604 | |
edamame22 | 0:a9bcda5b678a | 3605 | },{"has-cors":40}],21:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3606 | |
edamame22 | 0:a9bcda5b678a | 3607 | module.exports = function(a, b){ |
edamame22 | 0:a9bcda5b678a | 3608 | var fn = function(){}; |
edamame22 | 0:a9bcda5b678a | 3609 | fn.prototype = b.prototype; |
edamame22 | 0:a9bcda5b678a | 3610 | a.prototype = new fn; |
edamame22 | 0:a9bcda5b678a | 3611 | a.prototype.constructor = a; |
edamame22 | 0:a9bcda5b678a | 3612 | }; |
edamame22 | 0:a9bcda5b678a | 3613 | },{}],22:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3614 | |
edamame22 | 0:a9bcda5b678a | 3615 | /** |
edamame22 | 0:a9bcda5b678a | 3616 | * This is the web browser implementation of `debug()`. |
edamame22 | 0:a9bcda5b678a | 3617 | * |
edamame22 | 0:a9bcda5b678a | 3618 | * Expose `debug()` as the module. |
edamame22 | 0:a9bcda5b678a | 3619 | */ |
edamame22 | 0:a9bcda5b678a | 3620 | |
edamame22 | 0:a9bcda5b678a | 3621 | exports = module.exports = _dereq_('./debug'); |
edamame22 | 0:a9bcda5b678a | 3622 | exports.log = log; |
edamame22 | 0:a9bcda5b678a | 3623 | exports.formatArgs = formatArgs; |
edamame22 | 0:a9bcda5b678a | 3624 | exports.save = save; |
edamame22 | 0:a9bcda5b678a | 3625 | exports.load = load; |
edamame22 | 0:a9bcda5b678a | 3626 | exports.useColors = useColors; |
edamame22 | 0:a9bcda5b678a | 3627 | |
edamame22 | 0:a9bcda5b678a | 3628 | /** |
edamame22 | 0:a9bcda5b678a | 3629 | * Colors. |
edamame22 | 0:a9bcda5b678a | 3630 | */ |
edamame22 | 0:a9bcda5b678a | 3631 | |
edamame22 | 0:a9bcda5b678a | 3632 | exports.colors = [ |
edamame22 | 0:a9bcda5b678a | 3633 | 'lightseagreen', |
edamame22 | 0:a9bcda5b678a | 3634 | 'forestgreen', |
edamame22 | 0:a9bcda5b678a | 3635 | 'goldenrod', |
edamame22 | 0:a9bcda5b678a | 3636 | 'dodgerblue', |
edamame22 | 0:a9bcda5b678a | 3637 | 'darkorchid', |
edamame22 | 0:a9bcda5b678a | 3638 | 'crimson' |
edamame22 | 0:a9bcda5b678a | 3639 | ]; |
edamame22 | 0:a9bcda5b678a | 3640 | |
edamame22 | 0:a9bcda5b678a | 3641 | /** |
edamame22 | 0:a9bcda5b678a | 3642 | * Currently only WebKit-based Web Inspectors, Firefox >= v31, |
edamame22 | 0:a9bcda5b678a | 3643 | * and the Firebug extension (any Firefox version) are known |
edamame22 | 0:a9bcda5b678a | 3644 | * to support "%c" CSS customizations. |
edamame22 | 0:a9bcda5b678a | 3645 | * |
edamame22 | 0:a9bcda5b678a | 3646 | * TODO: add a `localStorage` variable to explicitly enable/disable colors |
edamame22 | 0:a9bcda5b678a | 3647 | */ |
edamame22 | 0:a9bcda5b678a | 3648 | |
edamame22 | 0:a9bcda5b678a | 3649 | function useColors() { |
edamame22 | 0:a9bcda5b678a | 3650 | // is webkit? http://stackoverflow.com/a/16459606/376773 |
edamame22 | 0:a9bcda5b678a | 3651 | return ('WebkitAppearance' in document.documentElement.style) || |
edamame22 | 0:a9bcda5b678a | 3652 | // is firebug? http://stackoverflow.com/a/398120/376773 |
edamame22 | 0:a9bcda5b678a | 3653 | (window.console && (console.firebug || (console.exception && console.table))) || |
edamame22 | 0:a9bcda5b678a | 3654 | // is firefox >= v31? |
edamame22 | 0:a9bcda5b678a | 3655 | // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages |
edamame22 | 0:a9bcda5b678a | 3656 | (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31); |
edamame22 | 0:a9bcda5b678a | 3657 | } |
edamame22 | 0:a9bcda5b678a | 3658 | |
edamame22 | 0:a9bcda5b678a | 3659 | /** |
edamame22 | 0:a9bcda5b678a | 3660 | * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. |
edamame22 | 0:a9bcda5b678a | 3661 | */ |
edamame22 | 0:a9bcda5b678a | 3662 | |
edamame22 | 0:a9bcda5b678a | 3663 | exports.formatters.j = function(v) { |
edamame22 | 0:a9bcda5b678a | 3664 | return JSON.stringify(v); |
edamame22 | 0:a9bcda5b678a | 3665 | }; |
edamame22 | 0:a9bcda5b678a | 3666 | |
edamame22 | 0:a9bcda5b678a | 3667 | |
edamame22 | 0:a9bcda5b678a | 3668 | /** |
edamame22 | 0:a9bcda5b678a | 3669 | * Colorize log arguments if enabled. |
edamame22 | 0:a9bcda5b678a | 3670 | * |
edamame22 | 0:a9bcda5b678a | 3671 | * @api public |
edamame22 | 0:a9bcda5b678a | 3672 | */ |
edamame22 | 0:a9bcda5b678a | 3673 | |
edamame22 | 0:a9bcda5b678a | 3674 | function formatArgs() { |
edamame22 | 0:a9bcda5b678a | 3675 | var args = arguments; |
edamame22 | 0:a9bcda5b678a | 3676 | var useColors = this.useColors; |
edamame22 | 0:a9bcda5b678a | 3677 | |
edamame22 | 0:a9bcda5b678a | 3678 | args[0] = (useColors ? '%c' : '') |
edamame22 | 0:a9bcda5b678a | 3679 | + this.namespace |
edamame22 | 0:a9bcda5b678a | 3680 | + (useColors ? ' %c' : ' ') |
edamame22 | 0:a9bcda5b678a | 3681 | + args[0] |
edamame22 | 0:a9bcda5b678a | 3682 | + (useColors ? '%c ' : ' ') |
edamame22 | 0:a9bcda5b678a | 3683 | + '+' + exports.humanize(this.diff); |
edamame22 | 0:a9bcda5b678a | 3684 | |
edamame22 | 0:a9bcda5b678a | 3685 | if (!useColors) return args; |
edamame22 | 0:a9bcda5b678a | 3686 | |
edamame22 | 0:a9bcda5b678a | 3687 | var c = 'color: ' + this.color; |
edamame22 | 0:a9bcda5b678a | 3688 | args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1)); |
edamame22 | 0:a9bcda5b678a | 3689 | |
edamame22 | 0:a9bcda5b678a | 3690 | // the final "%c" is somewhat tricky, because there could be other |
edamame22 | 0:a9bcda5b678a | 3691 | // arguments passed either before or after the %c, so we need to |
edamame22 | 0:a9bcda5b678a | 3692 | // figure out the correct index to insert the CSS into |
edamame22 | 0:a9bcda5b678a | 3693 | var index = 0; |
edamame22 | 0:a9bcda5b678a | 3694 | var lastC = 0; |
edamame22 | 0:a9bcda5b678a | 3695 | args[0].replace(/%[a-z%]/g, function(match) { |
edamame22 | 0:a9bcda5b678a | 3696 | if ('%' === match) return; |
edamame22 | 0:a9bcda5b678a | 3697 | index++; |
edamame22 | 0:a9bcda5b678a | 3698 | if ('%c' === match) { |
edamame22 | 0:a9bcda5b678a | 3699 | // we only are interested in the *last* %c |
edamame22 | 0:a9bcda5b678a | 3700 | // (the user may have provided their own) |
edamame22 | 0:a9bcda5b678a | 3701 | lastC = index; |
edamame22 | 0:a9bcda5b678a | 3702 | } |
edamame22 | 0:a9bcda5b678a | 3703 | }); |
edamame22 | 0:a9bcda5b678a | 3704 | |
edamame22 | 0:a9bcda5b678a | 3705 | args.splice(lastC, 0, c); |
edamame22 | 0:a9bcda5b678a | 3706 | return args; |
edamame22 | 0:a9bcda5b678a | 3707 | } |
edamame22 | 0:a9bcda5b678a | 3708 | |
edamame22 | 0:a9bcda5b678a | 3709 | /** |
edamame22 | 0:a9bcda5b678a | 3710 | * Invokes `console.log()` when available. |
edamame22 | 0:a9bcda5b678a | 3711 | * No-op when `console.log` is not a "function". |
edamame22 | 0:a9bcda5b678a | 3712 | * |
edamame22 | 0:a9bcda5b678a | 3713 | * @api public |
edamame22 | 0:a9bcda5b678a | 3714 | */ |
edamame22 | 0:a9bcda5b678a | 3715 | |
edamame22 | 0:a9bcda5b678a | 3716 | function log() { |
edamame22 | 0:a9bcda5b678a | 3717 | // This hackery is required for IE8, |
edamame22 | 0:a9bcda5b678a | 3718 | // where the `console.log` function doesn't have 'apply' |
edamame22 | 0:a9bcda5b678a | 3719 | return 'object' == typeof console |
edamame22 | 0:a9bcda5b678a | 3720 | && 'function' == typeof console.log |
edamame22 | 0:a9bcda5b678a | 3721 | && Function.prototype.apply.call(console.log, console, arguments); |
edamame22 | 0:a9bcda5b678a | 3722 | } |
edamame22 | 0:a9bcda5b678a | 3723 | |
edamame22 | 0:a9bcda5b678a | 3724 | /** |
edamame22 | 0:a9bcda5b678a | 3725 | * Save `namespaces`. |
edamame22 | 0:a9bcda5b678a | 3726 | * |
edamame22 | 0:a9bcda5b678a | 3727 | * @param {String} namespaces |
edamame22 | 0:a9bcda5b678a | 3728 | * @api private |
edamame22 | 0:a9bcda5b678a | 3729 | */ |
edamame22 | 0:a9bcda5b678a | 3730 | |
edamame22 | 0:a9bcda5b678a | 3731 | function save(namespaces) { |
edamame22 | 0:a9bcda5b678a | 3732 | try { |
edamame22 | 0:a9bcda5b678a | 3733 | if (null == namespaces) { |
edamame22 | 0:a9bcda5b678a | 3734 | localStorage.removeItem('debug'); |
edamame22 | 0:a9bcda5b678a | 3735 | } else { |
edamame22 | 0:a9bcda5b678a | 3736 | localStorage.debug = namespaces; |
edamame22 | 0:a9bcda5b678a | 3737 | } |
edamame22 | 0:a9bcda5b678a | 3738 | } catch(e) {} |
edamame22 | 0:a9bcda5b678a | 3739 | } |
edamame22 | 0:a9bcda5b678a | 3740 | |
edamame22 | 0:a9bcda5b678a | 3741 | /** |
edamame22 | 0:a9bcda5b678a | 3742 | * Load `namespaces`. |
edamame22 | 0:a9bcda5b678a | 3743 | * |
edamame22 | 0:a9bcda5b678a | 3744 | * @return {String} returns the previously persisted debug modes |
edamame22 | 0:a9bcda5b678a | 3745 | * @api private |
edamame22 | 0:a9bcda5b678a | 3746 | */ |
edamame22 | 0:a9bcda5b678a | 3747 | |
edamame22 | 0:a9bcda5b678a | 3748 | function load() { |
edamame22 | 0:a9bcda5b678a | 3749 | var r; |
edamame22 | 0:a9bcda5b678a | 3750 | try { |
edamame22 | 0:a9bcda5b678a | 3751 | r = localStorage.debug; |
edamame22 | 0:a9bcda5b678a | 3752 | } catch(e) {} |
edamame22 | 0:a9bcda5b678a | 3753 | return r; |
edamame22 | 0:a9bcda5b678a | 3754 | } |
edamame22 | 0:a9bcda5b678a | 3755 | |
edamame22 | 0:a9bcda5b678a | 3756 | /** |
edamame22 | 0:a9bcda5b678a | 3757 | * Enable namespaces listed in `localStorage.debug` initially. |
edamame22 | 0:a9bcda5b678a | 3758 | */ |
edamame22 | 0:a9bcda5b678a | 3759 | |
edamame22 | 0:a9bcda5b678a | 3760 | exports.enable(load()); |
edamame22 | 0:a9bcda5b678a | 3761 | |
edamame22 | 0:a9bcda5b678a | 3762 | },{"./debug":23}],23:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3763 | |
edamame22 | 0:a9bcda5b678a | 3764 | /** |
edamame22 | 0:a9bcda5b678a | 3765 | * This is the common logic for both the Node.js and web browser |
edamame22 | 0:a9bcda5b678a | 3766 | * implementations of `debug()`. |
edamame22 | 0:a9bcda5b678a | 3767 | * |
edamame22 | 0:a9bcda5b678a | 3768 | * Expose `debug()` as the module. |
edamame22 | 0:a9bcda5b678a | 3769 | */ |
edamame22 | 0:a9bcda5b678a | 3770 | |
edamame22 | 0:a9bcda5b678a | 3771 | exports = module.exports = debug; |
edamame22 | 0:a9bcda5b678a | 3772 | exports.coerce = coerce; |
edamame22 | 0:a9bcda5b678a | 3773 | exports.disable = disable; |
edamame22 | 0:a9bcda5b678a | 3774 | exports.enable = enable; |
edamame22 | 0:a9bcda5b678a | 3775 | exports.enabled = enabled; |
edamame22 | 0:a9bcda5b678a | 3776 | exports.humanize = _dereq_('ms'); |
edamame22 | 0:a9bcda5b678a | 3777 | |
edamame22 | 0:a9bcda5b678a | 3778 | /** |
edamame22 | 0:a9bcda5b678a | 3779 | * The currently active debug mode names, and names to skip. |
edamame22 | 0:a9bcda5b678a | 3780 | */ |
edamame22 | 0:a9bcda5b678a | 3781 | |
edamame22 | 0:a9bcda5b678a | 3782 | exports.names = []; |
edamame22 | 0:a9bcda5b678a | 3783 | exports.skips = []; |
edamame22 | 0:a9bcda5b678a | 3784 | |
edamame22 | 0:a9bcda5b678a | 3785 | /** |
edamame22 | 0:a9bcda5b678a | 3786 | * Map of special "%n" handling functions, for the debug "format" argument. |
edamame22 | 0:a9bcda5b678a | 3787 | * |
edamame22 | 0:a9bcda5b678a | 3788 | * Valid key names are a single, lowercased letter, i.e. "n". |
edamame22 | 0:a9bcda5b678a | 3789 | */ |
edamame22 | 0:a9bcda5b678a | 3790 | |
edamame22 | 0:a9bcda5b678a | 3791 | exports.formatters = {}; |
edamame22 | 0:a9bcda5b678a | 3792 | |
edamame22 | 0:a9bcda5b678a | 3793 | /** |
edamame22 | 0:a9bcda5b678a | 3794 | * Previously assigned color. |
edamame22 | 0:a9bcda5b678a | 3795 | */ |
edamame22 | 0:a9bcda5b678a | 3796 | |
edamame22 | 0:a9bcda5b678a | 3797 | var prevColor = 0; |
edamame22 | 0:a9bcda5b678a | 3798 | |
edamame22 | 0:a9bcda5b678a | 3799 | /** |
edamame22 | 0:a9bcda5b678a | 3800 | * Previous log timestamp. |
edamame22 | 0:a9bcda5b678a | 3801 | */ |
edamame22 | 0:a9bcda5b678a | 3802 | |
edamame22 | 0:a9bcda5b678a | 3803 | var prevTime; |
edamame22 | 0:a9bcda5b678a | 3804 | |
edamame22 | 0:a9bcda5b678a | 3805 | /** |
edamame22 | 0:a9bcda5b678a | 3806 | * Select a color. |
edamame22 | 0:a9bcda5b678a | 3807 | * |
edamame22 | 0:a9bcda5b678a | 3808 | * @return {Number} |
edamame22 | 0:a9bcda5b678a | 3809 | * @api private |
edamame22 | 0:a9bcda5b678a | 3810 | */ |
edamame22 | 0:a9bcda5b678a | 3811 | |
edamame22 | 0:a9bcda5b678a | 3812 | function selectColor() { |
edamame22 | 0:a9bcda5b678a | 3813 | return exports.colors[prevColor++ % exports.colors.length]; |
edamame22 | 0:a9bcda5b678a | 3814 | } |
edamame22 | 0:a9bcda5b678a | 3815 | |
edamame22 | 0:a9bcda5b678a | 3816 | /** |
edamame22 | 0:a9bcda5b678a | 3817 | * Create a debugger with the given `namespace`. |
edamame22 | 0:a9bcda5b678a | 3818 | * |
edamame22 | 0:a9bcda5b678a | 3819 | * @param {String} namespace |
edamame22 | 0:a9bcda5b678a | 3820 | * @return {Function} |
edamame22 | 0:a9bcda5b678a | 3821 | * @api public |
edamame22 | 0:a9bcda5b678a | 3822 | */ |
edamame22 | 0:a9bcda5b678a | 3823 | |
edamame22 | 0:a9bcda5b678a | 3824 | function debug(namespace) { |
edamame22 | 0:a9bcda5b678a | 3825 | |
edamame22 | 0:a9bcda5b678a | 3826 | // define the `disabled` version |
edamame22 | 0:a9bcda5b678a | 3827 | function disabled() { |
edamame22 | 0:a9bcda5b678a | 3828 | } |
edamame22 | 0:a9bcda5b678a | 3829 | disabled.enabled = false; |
edamame22 | 0:a9bcda5b678a | 3830 | |
edamame22 | 0:a9bcda5b678a | 3831 | // define the `enabled` version |
edamame22 | 0:a9bcda5b678a | 3832 | function enabled() { |
edamame22 | 0:a9bcda5b678a | 3833 | |
edamame22 | 0:a9bcda5b678a | 3834 | var self = enabled; |
edamame22 | 0:a9bcda5b678a | 3835 | |
edamame22 | 0:a9bcda5b678a | 3836 | // set `diff` timestamp |
edamame22 | 0:a9bcda5b678a | 3837 | var curr = +new Date(); |
edamame22 | 0:a9bcda5b678a | 3838 | var ms = curr - (prevTime || curr); |
edamame22 | 0:a9bcda5b678a | 3839 | self.diff = ms; |
edamame22 | 0:a9bcda5b678a | 3840 | self.prev = prevTime; |
edamame22 | 0:a9bcda5b678a | 3841 | self.curr = curr; |
edamame22 | 0:a9bcda5b678a | 3842 | prevTime = curr; |
edamame22 | 0:a9bcda5b678a | 3843 | |
edamame22 | 0:a9bcda5b678a | 3844 | // add the `color` if not set |
edamame22 | 0:a9bcda5b678a | 3845 | if (null == self.useColors) self.useColors = exports.useColors(); |
edamame22 | 0:a9bcda5b678a | 3846 | if (null == self.color && self.useColors) self.color = selectColor(); |
edamame22 | 0:a9bcda5b678a | 3847 | |
edamame22 | 0:a9bcda5b678a | 3848 | var args = Array.prototype.slice.call(arguments); |
edamame22 | 0:a9bcda5b678a | 3849 | |
edamame22 | 0:a9bcda5b678a | 3850 | args[0] = exports.coerce(args[0]); |
edamame22 | 0:a9bcda5b678a | 3851 | |
edamame22 | 0:a9bcda5b678a | 3852 | if ('string' !== typeof args[0]) { |
edamame22 | 0:a9bcda5b678a | 3853 | // anything else let's inspect with %o |
edamame22 | 0:a9bcda5b678a | 3854 | args = ['%o'].concat(args); |
edamame22 | 0:a9bcda5b678a | 3855 | } |
edamame22 | 0:a9bcda5b678a | 3856 | |
edamame22 | 0:a9bcda5b678a | 3857 | // apply any `formatters` transformations |
edamame22 | 0:a9bcda5b678a | 3858 | var index = 0; |
edamame22 | 0:a9bcda5b678a | 3859 | args[0] = args[0].replace(/%([a-z%])/g, function(match, format) { |
edamame22 | 0:a9bcda5b678a | 3860 | // if we encounter an escaped % then don't increase the array index |
edamame22 | 0:a9bcda5b678a | 3861 | if (match === '%') return match; |
edamame22 | 0:a9bcda5b678a | 3862 | index++; |
edamame22 | 0:a9bcda5b678a | 3863 | var formatter = exports.formatters[format]; |
edamame22 | 0:a9bcda5b678a | 3864 | if ('function' === typeof formatter) { |
edamame22 | 0:a9bcda5b678a | 3865 | var val = args[index]; |
edamame22 | 0:a9bcda5b678a | 3866 | match = formatter.call(self, val); |
edamame22 | 0:a9bcda5b678a | 3867 | |
edamame22 | 0:a9bcda5b678a | 3868 | // now we need to remove `args[index]` since it's inlined in the `format` |
edamame22 | 0:a9bcda5b678a | 3869 | args.splice(index, 1); |
edamame22 | 0:a9bcda5b678a | 3870 | index--; |
edamame22 | 0:a9bcda5b678a | 3871 | } |
edamame22 | 0:a9bcda5b678a | 3872 | return match; |
edamame22 | 0:a9bcda5b678a | 3873 | }); |
edamame22 | 0:a9bcda5b678a | 3874 | |
edamame22 | 0:a9bcda5b678a | 3875 | if ('function' === typeof exports.formatArgs) { |
edamame22 | 0:a9bcda5b678a | 3876 | args = exports.formatArgs.apply(self, args); |
edamame22 | 0:a9bcda5b678a | 3877 | } |
edamame22 | 0:a9bcda5b678a | 3878 | var logFn = enabled.log || exports.log || console.log.bind(console); |
edamame22 | 0:a9bcda5b678a | 3879 | logFn.apply(self, args); |
edamame22 | 0:a9bcda5b678a | 3880 | } |
edamame22 | 0:a9bcda5b678a | 3881 | enabled.enabled = true; |
edamame22 | 0:a9bcda5b678a | 3882 | |
edamame22 | 0:a9bcda5b678a | 3883 | var fn = exports.enabled(namespace) ? enabled : disabled; |
edamame22 | 0:a9bcda5b678a | 3884 | |
edamame22 | 0:a9bcda5b678a | 3885 | fn.namespace = namespace; |
edamame22 | 0:a9bcda5b678a | 3886 | |
edamame22 | 0:a9bcda5b678a | 3887 | return fn; |
edamame22 | 0:a9bcda5b678a | 3888 | } |
edamame22 | 0:a9bcda5b678a | 3889 | |
edamame22 | 0:a9bcda5b678a | 3890 | /** |
edamame22 | 0:a9bcda5b678a | 3891 | * Enables a debug mode by namespaces. This can include modes |
edamame22 | 0:a9bcda5b678a | 3892 | * separated by a colon and wildcards. |
edamame22 | 0:a9bcda5b678a | 3893 | * |
edamame22 | 0:a9bcda5b678a | 3894 | * @param {String} namespaces |
edamame22 | 0:a9bcda5b678a | 3895 | * @api public |
edamame22 | 0:a9bcda5b678a | 3896 | */ |
edamame22 | 0:a9bcda5b678a | 3897 | |
edamame22 | 0:a9bcda5b678a | 3898 | function enable(namespaces) { |
edamame22 | 0:a9bcda5b678a | 3899 | exports.save(namespaces); |
edamame22 | 0:a9bcda5b678a | 3900 | |
edamame22 | 0:a9bcda5b678a | 3901 | var split = (namespaces || '').split(/[\s,]+/); |
edamame22 | 0:a9bcda5b678a | 3902 | var len = split.length; |
edamame22 | 0:a9bcda5b678a | 3903 | |
edamame22 | 0:a9bcda5b678a | 3904 | for (var i = 0; i < len; i++) { |
edamame22 | 0:a9bcda5b678a | 3905 | if (!split[i]) continue; // ignore empty strings |
edamame22 | 0:a9bcda5b678a | 3906 | namespaces = split[i].replace(/\*/g, '.*?'); |
edamame22 | 0:a9bcda5b678a | 3907 | if (namespaces[0] === '-') { |
edamame22 | 0:a9bcda5b678a | 3908 | exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); |
edamame22 | 0:a9bcda5b678a | 3909 | } else { |
edamame22 | 0:a9bcda5b678a | 3910 | exports.names.push(new RegExp('^' + namespaces + '$')); |
edamame22 | 0:a9bcda5b678a | 3911 | } |
edamame22 | 0:a9bcda5b678a | 3912 | } |
edamame22 | 0:a9bcda5b678a | 3913 | } |
edamame22 | 0:a9bcda5b678a | 3914 | |
edamame22 | 0:a9bcda5b678a | 3915 | /** |
edamame22 | 0:a9bcda5b678a | 3916 | * Disable debug output. |
edamame22 | 0:a9bcda5b678a | 3917 | * |
edamame22 | 0:a9bcda5b678a | 3918 | * @api public |
edamame22 | 0:a9bcda5b678a | 3919 | */ |
edamame22 | 0:a9bcda5b678a | 3920 | |
edamame22 | 0:a9bcda5b678a | 3921 | function disable() { |
edamame22 | 0:a9bcda5b678a | 3922 | exports.enable(''); |
edamame22 | 0:a9bcda5b678a | 3923 | } |
edamame22 | 0:a9bcda5b678a | 3924 | |
edamame22 | 0:a9bcda5b678a | 3925 | /** |
edamame22 | 0:a9bcda5b678a | 3926 | * Returns true if the given mode name is enabled, false otherwise. |
edamame22 | 0:a9bcda5b678a | 3927 | * |
edamame22 | 0:a9bcda5b678a | 3928 | * @param {String} name |
edamame22 | 0:a9bcda5b678a | 3929 | * @return {Boolean} |
edamame22 | 0:a9bcda5b678a | 3930 | * @api public |
edamame22 | 0:a9bcda5b678a | 3931 | */ |
edamame22 | 0:a9bcda5b678a | 3932 | |
edamame22 | 0:a9bcda5b678a | 3933 | function enabled(name) { |
edamame22 | 0:a9bcda5b678a | 3934 | var i, len; |
edamame22 | 0:a9bcda5b678a | 3935 | for (i = 0, len = exports.skips.length; i < len; i++) { |
edamame22 | 0:a9bcda5b678a | 3936 | if (exports.skips[i].test(name)) { |
edamame22 | 0:a9bcda5b678a | 3937 | return false; |
edamame22 | 0:a9bcda5b678a | 3938 | } |
edamame22 | 0:a9bcda5b678a | 3939 | } |
edamame22 | 0:a9bcda5b678a | 3940 | for (i = 0, len = exports.names.length; i < len; i++) { |
edamame22 | 0:a9bcda5b678a | 3941 | if (exports.names[i].test(name)) { |
edamame22 | 0:a9bcda5b678a | 3942 | return true; |
edamame22 | 0:a9bcda5b678a | 3943 | } |
edamame22 | 0:a9bcda5b678a | 3944 | } |
edamame22 | 0:a9bcda5b678a | 3945 | return false; |
edamame22 | 0:a9bcda5b678a | 3946 | } |
edamame22 | 0:a9bcda5b678a | 3947 | |
edamame22 | 0:a9bcda5b678a | 3948 | /** |
edamame22 | 0:a9bcda5b678a | 3949 | * Coerce `val`. |
edamame22 | 0:a9bcda5b678a | 3950 | * |
edamame22 | 0:a9bcda5b678a | 3951 | * @param {Mixed} val |
edamame22 | 0:a9bcda5b678a | 3952 | * @return {Mixed} |
edamame22 | 0:a9bcda5b678a | 3953 | * @api private |
edamame22 | 0:a9bcda5b678a | 3954 | */ |
edamame22 | 0:a9bcda5b678a | 3955 | |
edamame22 | 0:a9bcda5b678a | 3956 | function coerce(val) { |
edamame22 | 0:a9bcda5b678a | 3957 | if (val instanceof Error) return val.stack || val.message; |
edamame22 | 0:a9bcda5b678a | 3958 | return val; |
edamame22 | 0:a9bcda5b678a | 3959 | } |
edamame22 | 0:a9bcda5b678a | 3960 | |
edamame22 | 0:a9bcda5b678a | 3961 | },{"ms":24}],24:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 3962 | /** |
edamame22 | 0:a9bcda5b678a | 3963 | * Helpers. |
edamame22 | 0:a9bcda5b678a | 3964 | */ |
edamame22 | 0:a9bcda5b678a | 3965 | |
edamame22 | 0:a9bcda5b678a | 3966 | var s = 1000; |
edamame22 | 0:a9bcda5b678a | 3967 | var m = s * 60; |
edamame22 | 0:a9bcda5b678a | 3968 | var h = m * 60; |
edamame22 | 0:a9bcda5b678a | 3969 | var d = h * 24; |
edamame22 | 0:a9bcda5b678a | 3970 | var y = d * 365.25; |
edamame22 | 0:a9bcda5b678a | 3971 | |
edamame22 | 0:a9bcda5b678a | 3972 | /** |
edamame22 | 0:a9bcda5b678a | 3973 | * Parse or format the given `val`. |
edamame22 | 0:a9bcda5b678a | 3974 | * |
edamame22 | 0:a9bcda5b678a | 3975 | * Options: |
edamame22 | 0:a9bcda5b678a | 3976 | * |
edamame22 | 0:a9bcda5b678a | 3977 | * - `long` verbose formatting [false] |
edamame22 | 0:a9bcda5b678a | 3978 | * |
edamame22 | 0:a9bcda5b678a | 3979 | * @param {String|Number} val |
edamame22 | 0:a9bcda5b678a | 3980 | * @param {Object} options |
edamame22 | 0:a9bcda5b678a | 3981 | * @return {String|Number} |
edamame22 | 0:a9bcda5b678a | 3982 | * @api public |
edamame22 | 0:a9bcda5b678a | 3983 | */ |
edamame22 | 0:a9bcda5b678a | 3984 | |
edamame22 | 0:a9bcda5b678a | 3985 | module.exports = function(val, options){ |
edamame22 | 0:a9bcda5b678a | 3986 | options = options || {}; |
edamame22 | 0:a9bcda5b678a | 3987 | if ('string' == typeof val) return parse(val); |
edamame22 | 0:a9bcda5b678a | 3988 | return options.long |
edamame22 | 0:a9bcda5b678a | 3989 | ? long(val) |
edamame22 | 0:a9bcda5b678a | 3990 | : short(val); |
edamame22 | 0:a9bcda5b678a | 3991 | }; |
edamame22 | 0:a9bcda5b678a | 3992 | |
edamame22 | 0:a9bcda5b678a | 3993 | /** |
edamame22 | 0:a9bcda5b678a | 3994 | * Parse the given `str` and return milliseconds. |
edamame22 | 0:a9bcda5b678a | 3995 | * |
edamame22 | 0:a9bcda5b678a | 3996 | * @param {String} str |
edamame22 | 0:a9bcda5b678a | 3997 | * @return {Number} |
edamame22 | 0:a9bcda5b678a | 3998 | * @api private |
edamame22 | 0:a9bcda5b678a | 3999 | */ |
edamame22 | 0:a9bcda5b678a | 4000 | |
edamame22 | 0:a9bcda5b678a | 4001 | function parse(str) { |
edamame22 | 0:a9bcda5b678a | 4002 | var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); |
edamame22 | 0:a9bcda5b678a | 4003 | if (!match) return; |
edamame22 | 0:a9bcda5b678a | 4004 | var n = parseFloat(match[1]); |
edamame22 | 0:a9bcda5b678a | 4005 | var type = (match[2] || 'ms').toLowerCase(); |
edamame22 | 0:a9bcda5b678a | 4006 | switch (type) { |
edamame22 | 0:a9bcda5b678a | 4007 | case 'years': |
edamame22 | 0:a9bcda5b678a | 4008 | case 'year': |
edamame22 | 0:a9bcda5b678a | 4009 | case 'y': |
edamame22 | 0:a9bcda5b678a | 4010 | return n * y; |
edamame22 | 0:a9bcda5b678a | 4011 | case 'days': |
edamame22 | 0:a9bcda5b678a | 4012 | case 'day': |
edamame22 | 0:a9bcda5b678a | 4013 | case 'd': |
edamame22 | 0:a9bcda5b678a | 4014 | return n * d; |
edamame22 | 0:a9bcda5b678a | 4015 | case 'hours': |
edamame22 | 0:a9bcda5b678a | 4016 | case 'hour': |
edamame22 | 0:a9bcda5b678a | 4017 | case 'h': |
edamame22 | 0:a9bcda5b678a | 4018 | return n * h; |
edamame22 | 0:a9bcda5b678a | 4019 | case 'minutes': |
edamame22 | 0:a9bcda5b678a | 4020 | case 'minute': |
edamame22 | 0:a9bcda5b678a | 4021 | case 'm': |
edamame22 | 0:a9bcda5b678a | 4022 | return n * m; |
edamame22 | 0:a9bcda5b678a | 4023 | case 'seconds': |
edamame22 | 0:a9bcda5b678a | 4024 | case 'second': |
edamame22 | 0:a9bcda5b678a | 4025 | case 's': |
edamame22 | 0:a9bcda5b678a | 4026 | return n * s; |
edamame22 | 0:a9bcda5b678a | 4027 | case 'ms': |
edamame22 | 0:a9bcda5b678a | 4028 | return n; |
edamame22 | 0:a9bcda5b678a | 4029 | } |
edamame22 | 0:a9bcda5b678a | 4030 | } |
edamame22 | 0:a9bcda5b678a | 4031 | |
edamame22 | 0:a9bcda5b678a | 4032 | /** |
edamame22 | 0:a9bcda5b678a | 4033 | * Short format for `ms`. |
edamame22 | 0:a9bcda5b678a | 4034 | * |
edamame22 | 0:a9bcda5b678a | 4035 | * @param {Number} ms |
edamame22 | 0:a9bcda5b678a | 4036 | * @return {String} |
edamame22 | 0:a9bcda5b678a | 4037 | * @api private |
edamame22 | 0:a9bcda5b678a | 4038 | */ |
edamame22 | 0:a9bcda5b678a | 4039 | |
edamame22 | 0:a9bcda5b678a | 4040 | function short(ms) { |
edamame22 | 0:a9bcda5b678a | 4041 | if (ms >= d) return Math.round(ms / d) + 'd'; |
edamame22 | 0:a9bcda5b678a | 4042 | if (ms >= h) return Math.round(ms / h) + 'h'; |
edamame22 | 0:a9bcda5b678a | 4043 | if (ms >= m) return Math.round(ms / m) + 'm'; |
edamame22 | 0:a9bcda5b678a | 4044 | if (ms >= s) return Math.round(ms / s) + 's'; |
edamame22 | 0:a9bcda5b678a | 4045 | return ms + 'ms'; |
edamame22 | 0:a9bcda5b678a | 4046 | } |
edamame22 | 0:a9bcda5b678a | 4047 | |
edamame22 | 0:a9bcda5b678a | 4048 | /** |
edamame22 | 0:a9bcda5b678a | 4049 | * Long format for `ms`. |
edamame22 | 0:a9bcda5b678a | 4050 | * |
edamame22 | 0:a9bcda5b678a | 4051 | * @param {Number} ms |
edamame22 | 0:a9bcda5b678a | 4052 | * @return {String} |
edamame22 | 0:a9bcda5b678a | 4053 | * @api private |
edamame22 | 0:a9bcda5b678a | 4054 | */ |
edamame22 | 0:a9bcda5b678a | 4055 | |
edamame22 | 0:a9bcda5b678a | 4056 | function long(ms) { |
edamame22 | 0:a9bcda5b678a | 4057 | return plural(ms, d, 'day') |
edamame22 | 0:a9bcda5b678a | 4058 | || plural(ms, h, 'hour') |
edamame22 | 0:a9bcda5b678a | 4059 | || plural(ms, m, 'minute') |
edamame22 | 0:a9bcda5b678a | 4060 | || plural(ms, s, 'second') |
edamame22 | 0:a9bcda5b678a | 4061 | || ms + ' ms'; |
edamame22 | 0:a9bcda5b678a | 4062 | } |
edamame22 | 0:a9bcda5b678a | 4063 | |
edamame22 | 0:a9bcda5b678a | 4064 | /** |
edamame22 | 0:a9bcda5b678a | 4065 | * Pluralization helper. |
edamame22 | 0:a9bcda5b678a | 4066 | */ |
edamame22 | 0:a9bcda5b678a | 4067 | |
edamame22 | 0:a9bcda5b678a | 4068 | function plural(ms, n, name) { |
edamame22 | 0:a9bcda5b678a | 4069 | if (ms < n) return; |
edamame22 | 0:a9bcda5b678a | 4070 | if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; |
edamame22 | 0:a9bcda5b678a | 4071 | return Math.ceil(ms / n) + ' ' + name + 's'; |
edamame22 | 0:a9bcda5b678a | 4072 | } |
edamame22 | 0:a9bcda5b678a | 4073 | |
edamame22 | 0:a9bcda5b678a | 4074 | },{}],25:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4075 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 4076 | /** |
edamame22 | 0:a9bcda5b678a | 4077 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 4078 | */ |
edamame22 | 0:a9bcda5b678a | 4079 | |
edamame22 | 0:a9bcda5b678a | 4080 | var keys = _dereq_('./keys'); |
edamame22 | 0:a9bcda5b678a | 4081 | var hasBinary = _dereq_('has-binary'); |
edamame22 | 0:a9bcda5b678a | 4082 | var sliceBuffer = _dereq_('arraybuffer.slice'); |
edamame22 | 0:a9bcda5b678a | 4083 | var base64encoder = _dereq_('base64-arraybuffer'); |
edamame22 | 0:a9bcda5b678a | 4084 | var after = _dereq_('after'); |
edamame22 | 0:a9bcda5b678a | 4085 | var utf8 = _dereq_('utf8'); |
edamame22 | 0:a9bcda5b678a | 4086 | |
edamame22 | 0:a9bcda5b678a | 4087 | /** |
edamame22 | 0:a9bcda5b678a | 4088 | * Check if we are running an android browser. That requires us to use |
edamame22 | 0:a9bcda5b678a | 4089 | * ArrayBuffer with polling transports... |
edamame22 | 0:a9bcda5b678a | 4090 | * |
edamame22 | 0:a9bcda5b678a | 4091 | * http://ghinda.net/jpeg-blob-ajax-android/ |
edamame22 | 0:a9bcda5b678a | 4092 | */ |
edamame22 | 0:a9bcda5b678a | 4093 | |
edamame22 | 0:a9bcda5b678a | 4094 | var isAndroid = navigator.userAgent.match(/Android/i); |
edamame22 | 0:a9bcda5b678a | 4095 | |
edamame22 | 0:a9bcda5b678a | 4096 | /** |
edamame22 | 0:a9bcda5b678a | 4097 | * Check if we are running in PhantomJS. |
edamame22 | 0:a9bcda5b678a | 4098 | * Uploading a Blob with PhantomJS does not work correctly, as reported here: |
edamame22 | 0:a9bcda5b678a | 4099 | * https://github.com/ariya/phantomjs/issues/11395 |
edamame22 | 0:a9bcda5b678a | 4100 | * @type boolean |
edamame22 | 0:a9bcda5b678a | 4101 | */ |
edamame22 | 0:a9bcda5b678a | 4102 | var isPhantomJS = /PhantomJS/i.test(navigator.userAgent); |
edamame22 | 0:a9bcda5b678a | 4103 | |
edamame22 | 0:a9bcda5b678a | 4104 | /** |
edamame22 | 0:a9bcda5b678a | 4105 | * When true, avoids using Blobs to encode payloads. |
edamame22 | 0:a9bcda5b678a | 4106 | * @type boolean |
edamame22 | 0:a9bcda5b678a | 4107 | */ |
edamame22 | 0:a9bcda5b678a | 4108 | var dontSendBlobs = isAndroid || isPhantomJS; |
edamame22 | 0:a9bcda5b678a | 4109 | |
edamame22 | 0:a9bcda5b678a | 4110 | /** |
edamame22 | 0:a9bcda5b678a | 4111 | * Current protocol version. |
edamame22 | 0:a9bcda5b678a | 4112 | */ |
edamame22 | 0:a9bcda5b678a | 4113 | |
edamame22 | 0:a9bcda5b678a | 4114 | exports.protocol = 3; |
edamame22 | 0:a9bcda5b678a | 4115 | |
edamame22 | 0:a9bcda5b678a | 4116 | /** |
edamame22 | 0:a9bcda5b678a | 4117 | * Packet types. |
edamame22 | 0:a9bcda5b678a | 4118 | */ |
edamame22 | 0:a9bcda5b678a | 4119 | |
edamame22 | 0:a9bcda5b678a | 4120 | var packets = exports.packets = { |
edamame22 | 0:a9bcda5b678a | 4121 | open: 0 // non-ws |
edamame22 | 0:a9bcda5b678a | 4122 | , close: 1 // non-ws |
edamame22 | 0:a9bcda5b678a | 4123 | , ping: 2 |
edamame22 | 0:a9bcda5b678a | 4124 | , pong: 3 |
edamame22 | 0:a9bcda5b678a | 4125 | , message: 4 |
edamame22 | 0:a9bcda5b678a | 4126 | , upgrade: 5 |
edamame22 | 0:a9bcda5b678a | 4127 | , noop: 6 |
edamame22 | 0:a9bcda5b678a | 4128 | }; |
edamame22 | 0:a9bcda5b678a | 4129 | |
edamame22 | 0:a9bcda5b678a | 4130 | var packetslist = keys(packets); |
edamame22 | 0:a9bcda5b678a | 4131 | |
edamame22 | 0:a9bcda5b678a | 4132 | /** |
edamame22 | 0:a9bcda5b678a | 4133 | * Premade error packet. |
edamame22 | 0:a9bcda5b678a | 4134 | */ |
edamame22 | 0:a9bcda5b678a | 4135 | |
edamame22 | 0:a9bcda5b678a | 4136 | var err = { type: 'error', data: 'parser error' }; |
edamame22 | 0:a9bcda5b678a | 4137 | |
edamame22 | 0:a9bcda5b678a | 4138 | /** |
edamame22 | 0:a9bcda5b678a | 4139 | * Create a blob api even for blob builder when vendor prefixes exist |
edamame22 | 0:a9bcda5b678a | 4140 | */ |
edamame22 | 0:a9bcda5b678a | 4141 | |
edamame22 | 0:a9bcda5b678a | 4142 | var Blob = _dereq_('blob'); |
edamame22 | 0:a9bcda5b678a | 4143 | |
edamame22 | 0:a9bcda5b678a | 4144 | /** |
edamame22 | 0:a9bcda5b678a | 4145 | * Encodes a packet. |
edamame22 | 0:a9bcda5b678a | 4146 | * |
edamame22 | 0:a9bcda5b678a | 4147 | * <packet type id> [ <data> ] |
edamame22 | 0:a9bcda5b678a | 4148 | * |
edamame22 | 0:a9bcda5b678a | 4149 | * Example: |
edamame22 | 0:a9bcda5b678a | 4150 | * |
edamame22 | 0:a9bcda5b678a | 4151 | * 5hello world |
edamame22 | 0:a9bcda5b678a | 4152 | * 3 |
edamame22 | 0:a9bcda5b678a | 4153 | * 4 |
edamame22 | 0:a9bcda5b678a | 4154 | * |
edamame22 | 0:a9bcda5b678a | 4155 | * Binary is encoded in an identical principle |
edamame22 | 0:a9bcda5b678a | 4156 | * |
edamame22 | 0:a9bcda5b678a | 4157 | * @api private |
edamame22 | 0:a9bcda5b678a | 4158 | */ |
edamame22 | 0:a9bcda5b678a | 4159 | |
edamame22 | 0:a9bcda5b678a | 4160 | exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) { |
edamame22 | 0:a9bcda5b678a | 4161 | if ('function' == typeof supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 4162 | callback = supportsBinary; |
edamame22 | 0:a9bcda5b678a | 4163 | supportsBinary = false; |
edamame22 | 0:a9bcda5b678a | 4164 | } |
edamame22 | 0:a9bcda5b678a | 4165 | |
edamame22 | 0:a9bcda5b678a | 4166 | if ('function' == typeof utf8encode) { |
edamame22 | 0:a9bcda5b678a | 4167 | callback = utf8encode; |
edamame22 | 0:a9bcda5b678a | 4168 | utf8encode = null; |
edamame22 | 0:a9bcda5b678a | 4169 | } |
edamame22 | 0:a9bcda5b678a | 4170 | |
edamame22 | 0:a9bcda5b678a | 4171 | var data = (packet.data === undefined) |
edamame22 | 0:a9bcda5b678a | 4172 | ? undefined |
edamame22 | 0:a9bcda5b678a | 4173 | : packet.data.buffer || packet.data; |
edamame22 | 0:a9bcda5b678a | 4174 | |
edamame22 | 0:a9bcda5b678a | 4175 | if (global.ArrayBuffer && data instanceof ArrayBuffer) { |
edamame22 | 0:a9bcda5b678a | 4176 | return encodeArrayBuffer(packet, supportsBinary, callback); |
edamame22 | 0:a9bcda5b678a | 4177 | } else if (Blob && data instanceof global.Blob) { |
edamame22 | 0:a9bcda5b678a | 4178 | return encodeBlob(packet, supportsBinary, callback); |
edamame22 | 0:a9bcda5b678a | 4179 | } |
edamame22 | 0:a9bcda5b678a | 4180 | |
edamame22 | 0:a9bcda5b678a | 4181 | // might be an object with { base64: true, data: dataAsBase64String } |
edamame22 | 0:a9bcda5b678a | 4182 | if (data && data.base64) { |
edamame22 | 0:a9bcda5b678a | 4183 | return encodeBase64Object(packet, callback); |
edamame22 | 0:a9bcda5b678a | 4184 | } |
edamame22 | 0:a9bcda5b678a | 4185 | |
edamame22 | 0:a9bcda5b678a | 4186 | // Sending data as a utf-8 string |
edamame22 | 0:a9bcda5b678a | 4187 | var encoded = packets[packet.type]; |
edamame22 | 0:a9bcda5b678a | 4188 | |
edamame22 | 0:a9bcda5b678a | 4189 | // data fragment is optional |
edamame22 | 0:a9bcda5b678a | 4190 | if (undefined !== packet.data) { |
edamame22 | 0:a9bcda5b678a | 4191 | encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data); |
edamame22 | 0:a9bcda5b678a | 4192 | } |
edamame22 | 0:a9bcda5b678a | 4193 | |
edamame22 | 0:a9bcda5b678a | 4194 | return callback('' + encoded); |
edamame22 | 0:a9bcda5b678a | 4195 | |
edamame22 | 0:a9bcda5b678a | 4196 | }; |
edamame22 | 0:a9bcda5b678a | 4197 | |
edamame22 | 0:a9bcda5b678a | 4198 | function encodeBase64Object(packet, callback) { |
edamame22 | 0:a9bcda5b678a | 4199 | // packet data is an object { base64: true, data: dataAsBase64String } |
edamame22 | 0:a9bcda5b678a | 4200 | var message = 'b' + exports.packets[packet.type] + packet.data.data; |
edamame22 | 0:a9bcda5b678a | 4201 | return callback(message); |
edamame22 | 0:a9bcda5b678a | 4202 | } |
edamame22 | 0:a9bcda5b678a | 4203 | |
edamame22 | 0:a9bcda5b678a | 4204 | /** |
edamame22 | 0:a9bcda5b678a | 4205 | * Encode packet helpers for binary types |
edamame22 | 0:a9bcda5b678a | 4206 | */ |
edamame22 | 0:a9bcda5b678a | 4207 | |
edamame22 | 0:a9bcda5b678a | 4208 | function encodeArrayBuffer(packet, supportsBinary, callback) { |
edamame22 | 0:a9bcda5b678a | 4209 | if (!supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 4210 | return exports.encodeBase64Packet(packet, callback); |
edamame22 | 0:a9bcda5b678a | 4211 | } |
edamame22 | 0:a9bcda5b678a | 4212 | |
edamame22 | 0:a9bcda5b678a | 4213 | var data = packet.data; |
edamame22 | 0:a9bcda5b678a | 4214 | var contentArray = new Uint8Array(data); |
edamame22 | 0:a9bcda5b678a | 4215 | var resultBuffer = new Uint8Array(1 + data.byteLength); |
edamame22 | 0:a9bcda5b678a | 4216 | |
edamame22 | 0:a9bcda5b678a | 4217 | resultBuffer[0] = packets[packet.type]; |
edamame22 | 0:a9bcda5b678a | 4218 | for (var i = 0; i < contentArray.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4219 | resultBuffer[i+1] = contentArray[i]; |
edamame22 | 0:a9bcda5b678a | 4220 | } |
edamame22 | 0:a9bcda5b678a | 4221 | |
edamame22 | 0:a9bcda5b678a | 4222 | return callback(resultBuffer.buffer); |
edamame22 | 0:a9bcda5b678a | 4223 | } |
edamame22 | 0:a9bcda5b678a | 4224 | |
edamame22 | 0:a9bcda5b678a | 4225 | function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) { |
edamame22 | 0:a9bcda5b678a | 4226 | if (!supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 4227 | return exports.encodeBase64Packet(packet, callback); |
edamame22 | 0:a9bcda5b678a | 4228 | } |
edamame22 | 0:a9bcda5b678a | 4229 | |
edamame22 | 0:a9bcda5b678a | 4230 | var fr = new FileReader(); |
edamame22 | 0:a9bcda5b678a | 4231 | fr.onload = function() { |
edamame22 | 0:a9bcda5b678a | 4232 | packet.data = fr.result; |
edamame22 | 0:a9bcda5b678a | 4233 | exports.encodePacket(packet, supportsBinary, true, callback); |
edamame22 | 0:a9bcda5b678a | 4234 | }; |
edamame22 | 0:a9bcda5b678a | 4235 | return fr.readAsArrayBuffer(packet.data); |
edamame22 | 0:a9bcda5b678a | 4236 | } |
edamame22 | 0:a9bcda5b678a | 4237 | |
edamame22 | 0:a9bcda5b678a | 4238 | function encodeBlob(packet, supportsBinary, callback) { |
edamame22 | 0:a9bcda5b678a | 4239 | if (!supportsBinary) { |
edamame22 | 0:a9bcda5b678a | 4240 | return exports.encodeBase64Packet(packet, callback); |
edamame22 | 0:a9bcda5b678a | 4241 | } |
edamame22 | 0:a9bcda5b678a | 4242 | |
edamame22 | 0:a9bcda5b678a | 4243 | if (dontSendBlobs) { |
edamame22 | 0:a9bcda5b678a | 4244 | return encodeBlobAsArrayBuffer(packet, supportsBinary, callback); |
edamame22 | 0:a9bcda5b678a | 4245 | } |
edamame22 | 0:a9bcda5b678a | 4246 | |
edamame22 | 0:a9bcda5b678a | 4247 | var length = new Uint8Array(1); |
edamame22 | 0:a9bcda5b678a | 4248 | length[0] = packets[packet.type]; |
edamame22 | 0:a9bcda5b678a | 4249 | var blob = new Blob([length.buffer, packet.data]); |
edamame22 | 0:a9bcda5b678a | 4250 | |
edamame22 | 0:a9bcda5b678a | 4251 | return callback(blob); |
edamame22 | 0:a9bcda5b678a | 4252 | } |
edamame22 | 0:a9bcda5b678a | 4253 | |
edamame22 | 0:a9bcda5b678a | 4254 | /** |
edamame22 | 0:a9bcda5b678a | 4255 | * Encodes a packet with binary data in a base64 string |
edamame22 | 0:a9bcda5b678a | 4256 | * |
edamame22 | 0:a9bcda5b678a | 4257 | * @param {Object} packet, has `type` and `data` |
edamame22 | 0:a9bcda5b678a | 4258 | * @return {String} base64 encoded message |
edamame22 | 0:a9bcda5b678a | 4259 | */ |
edamame22 | 0:a9bcda5b678a | 4260 | |
edamame22 | 0:a9bcda5b678a | 4261 | exports.encodeBase64Packet = function(packet, callback) { |
edamame22 | 0:a9bcda5b678a | 4262 | var message = 'b' + exports.packets[packet.type]; |
edamame22 | 0:a9bcda5b678a | 4263 | if (Blob && packet.data instanceof Blob) { |
edamame22 | 0:a9bcda5b678a | 4264 | var fr = new FileReader(); |
edamame22 | 0:a9bcda5b678a | 4265 | fr.onload = function() { |
edamame22 | 0:a9bcda5b678a | 4266 | var b64 = fr.result.split(',')[1]; |
edamame22 | 0:a9bcda5b678a | 4267 | callback(message + b64); |
edamame22 | 0:a9bcda5b678a | 4268 | }; |
edamame22 | 0:a9bcda5b678a | 4269 | return fr.readAsDataURL(packet.data); |
edamame22 | 0:a9bcda5b678a | 4270 | } |
edamame22 | 0:a9bcda5b678a | 4271 | |
edamame22 | 0:a9bcda5b678a | 4272 | var b64data; |
edamame22 | 0:a9bcda5b678a | 4273 | try { |
edamame22 | 0:a9bcda5b678a | 4274 | b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data)); |
edamame22 | 0:a9bcda5b678a | 4275 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 4276 | // iPhone Safari doesn't let you apply with typed arrays |
edamame22 | 0:a9bcda5b678a | 4277 | var typed = new Uint8Array(packet.data); |
edamame22 | 0:a9bcda5b678a | 4278 | var basic = new Array(typed.length); |
edamame22 | 0:a9bcda5b678a | 4279 | for (var i = 0; i < typed.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4280 | basic[i] = typed[i]; |
edamame22 | 0:a9bcda5b678a | 4281 | } |
edamame22 | 0:a9bcda5b678a | 4282 | b64data = String.fromCharCode.apply(null, basic); |
edamame22 | 0:a9bcda5b678a | 4283 | } |
edamame22 | 0:a9bcda5b678a | 4284 | message += global.btoa(b64data); |
edamame22 | 0:a9bcda5b678a | 4285 | return callback(message); |
edamame22 | 0:a9bcda5b678a | 4286 | }; |
edamame22 | 0:a9bcda5b678a | 4287 | |
edamame22 | 0:a9bcda5b678a | 4288 | /** |
edamame22 | 0:a9bcda5b678a | 4289 | * Decodes a packet. Changes format to Blob if requested. |
edamame22 | 0:a9bcda5b678a | 4290 | * |
edamame22 | 0:a9bcda5b678a | 4291 | * @return {Object} with `type` and `data` (if any) |
edamame22 | 0:a9bcda5b678a | 4292 | * @api private |
edamame22 | 0:a9bcda5b678a | 4293 | */ |
edamame22 | 0:a9bcda5b678a | 4294 | |
edamame22 | 0:a9bcda5b678a | 4295 | exports.decodePacket = function (data, binaryType, utf8decode) { |
edamame22 | 0:a9bcda5b678a | 4296 | // String data |
edamame22 | 0:a9bcda5b678a | 4297 | if (typeof data == 'string' || data === undefined) { |
edamame22 | 0:a9bcda5b678a | 4298 | if (data.charAt(0) == 'b') { |
edamame22 | 0:a9bcda5b678a | 4299 | return exports.decodeBase64Packet(data.substr(1), binaryType); |
edamame22 | 0:a9bcda5b678a | 4300 | } |
edamame22 | 0:a9bcda5b678a | 4301 | |
edamame22 | 0:a9bcda5b678a | 4302 | if (utf8decode) { |
edamame22 | 0:a9bcda5b678a | 4303 | try { |
edamame22 | 0:a9bcda5b678a | 4304 | data = utf8.decode(data); |
edamame22 | 0:a9bcda5b678a | 4305 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 4306 | return err; |
edamame22 | 0:a9bcda5b678a | 4307 | } |
edamame22 | 0:a9bcda5b678a | 4308 | } |
edamame22 | 0:a9bcda5b678a | 4309 | var type = data.charAt(0); |
edamame22 | 0:a9bcda5b678a | 4310 | |
edamame22 | 0:a9bcda5b678a | 4311 | if (Number(type) != type || !packetslist[type]) { |
edamame22 | 0:a9bcda5b678a | 4312 | return err; |
edamame22 | 0:a9bcda5b678a | 4313 | } |
edamame22 | 0:a9bcda5b678a | 4314 | |
edamame22 | 0:a9bcda5b678a | 4315 | if (data.length > 1) { |
edamame22 | 0:a9bcda5b678a | 4316 | return { type: packetslist[type], data: data.substring(1) }; |
edamame22 | 0:a9bcda5b678a | 4317 | } else { |
edamame22 | 0:a9bcda5b678a | 4318 | return { type: packetslist[type] }; |
edamame22 | 0:a9bcda5b678a | 4319 | } |
edamame22 | 0:a9bcda5b678a | 4320 | } |
edamame22 | 0:a9bcda5b678a | 4321 | |
edamame22 | 0:a9bcda5b678a | 4322 | var asArray = new Uint8Array(data); |
edamame22 | 0:a9bcda5b678a | 4323 | var type = asArray[0]; |
edamame22 | 0:a9bcda5b678a | 4324 | var rest = sliceBuffer(data, 1); |
edamame22 | 0:a9bcda5b678a | 4325 | if (Blob && binaryType === 'blob') { |
edamame22 | 0:a9bcda5b678a | 4326 | rest = new Blob([rest]); |
edamame22 | 0:a9bcda5b678a | 4327 | } |
edamame22 | 0:a9bcda5b678a | 4328 | return { type: packetslist[type], data: rest }; |
edamame22 | 0:a9bcda5b678a | 4329 | }; |
edamame22 | 0:a9bcda5b678a | 4330 | |
edamame22 | 0:a9bcda5b678a | 4331 | /** |
edamame22 | 0:a9bcda5b678a | 4332 | * Decodes a packet encoded in a base64 string |
edamame22 | 0:a9bcda5b678a | 4333 | * |
edamame22 | 0:a9bcda5b678a | 4334 | * @param {String} base64 encoded message |
edamame22 | 0:a9bcda5b678a | 4335 | * @return {Object} with `type` and `data` (if any) |
edamame22 | 0:a9bcda5b678a | 4336 | */ |
edamame22 | 0:a9bcda5b678a | 4337 | |
edamame22 | 0:a9bcda5b678a | 4338 | exports.decodeBase64Packet = function(msg, binaryType) { |
edamame22 | 0:a9bcda5b678a | 4339 | var type = packetslist[msg.charAt(0)]; |
edamame22 | 0:a9bcda5b678a | 4340 | if (!global.ArrayBuffer) { |
edamame22 | 0:a9bcda5b678a | 4341 | return { type: type, data: { base64: true, data: msg.substr(1) } }; |
edamame22 | 0:a9bcda5b678a | 4342 | } |
edamame22 | 0:a9bcda5b678a | 4343 | |
edamame22 | 0:a9bcda5b678a | 4344 | var data = base64encoder.decode(msg.substr(1)); |
edamame22 | 0:a9bcda5b678a | 4345 | |
edamame22 | 0:a9bcda5b678a | 4346 | if (binaryType === 'blob' && Blob) { |
edamame22 | 0:a9bcda5b678a | 4347 | data = new Blob([data]); |
edamame22 | 0:a9bcda5b678a | 4348 | } |
edamame22 | 0:a9bcda5b678a | 4349 | |
edamame22 | 0:a9bcda5b678a | 4350 | return { type: type, data: data }; |
edamame22 | 0:a9bcda5b678a | 4351 | }; |
edamame22 | 0:a9bcda5b678a | 4352 | |
edamame22 | 0:a9bcda5b678a | 4353 | /** |
edamame22 | 0:a9bcda5b678a | 4354 | * Encodes multiple messages (payload). |
edamame22 | 0:a9bcda5b678a | 4355 | * |
edamame22 | 0:a9bcda5b678a | 4356 | * <length>:data |
edamame22 | 0:a9bcda5b678a | 4357 | * |
edamame22 | 0:a9bcda5b678a | 4358 | * Example: |
edamame22 | 0:a9bcda5b678a | 4359 | * |
edamame22 | 0:a9bcda5b678a | 4360 | * 11:hello world2:hi |
edamame22 | 0:a9bcda5b678a | 4361 | * |
edamame22 | 0:a9bcda5b678a | 4362 | * If any contents are binary, they will be encoded as base64 strings. Base64 |
edamame22 | 0:a9bcda5b678a | 4363 | * encoded strings are marked with a b before the length specifier |
edamame22 | 0:a9bcda5b678a | 4364 | * |
edamame22 | 0:a9bcda5b678a | 4365 | * @param {Array} packets |
edamame22 | 0:a9bcda5b678a | 4366 | * @api private |
edamame22 | 0:a9bcda5b678a | 4367 | */ |
edamame22 | 0:a9bcda5b678a | 4368 | |
edamame22 | 0:a9bcda5b678a | 4369 | exports.encodePayload = function (packets, supportsBinary, callback) { |
edamame22 | 0:a9bcda5b678a | 4370 | if (typeof supportsBinary == 'function') { |
edamame22 | 0:a9bcda5b678a | 4371 | callback = supportsBinary; |
edamame22 | 0:a9bcda5b678a | 4372 | supportsBinary = null; |
edamame22 | 0:a9bcda5b678a | 4373 | } |
edamame22 | 0:a9bcda5b678a | 4374 | |
edamame22 | 0:a9bcda5b678a | 4375 | var isBinary = hasBinary(packets); |
edamame22 | 0:a9bcda5b678a | 4376 | |
edamame22 | 0:a9bcda5b678a | 4377 | if (supportsBinary && isBinary) { |
edamame22 | 0:a9bcda5b678a | 4378 | if (Blob && !dontSendBlobs) { |
edamame22 | 0:a9bcda5b678a | 4379 | return exports.encodePayloadAsBlob(packets, callback); |
edamame22 | 0:a9bcda5b678a | 4380 | } |
edamame22 | 0:a9bcda5b678a | 4381 | |
edamame22 | 0:a9bcda5b678a | 4382 | return exports.encodePayloadAsArrayBuffer(packets, callback); |
edamame22 | 0:a9bcda5b678a | 4383 | } |
edamame22 | 0:a9bcda5b678a | 4384 | |
edamame22 | 0:a9bcda5b678a | 4385 | if (!packets.length) { |
edamame22 | 0:a9bcda5b678a | 4386 | return callback('0:'); |
edamame22 | 0:a9bcda5b678a | 4387 | } |
edamame22 | 0:a9bcda5b678a | 4388 | |
edamame22 | 0:a9bcda5b678a | 4389 | function setLengthHeader(message) { |
edamame22 | 0:a9bcda5b678a | 4390 | return message.length + ':' + message; |
edamame22 | 0:a9bcda5b678a | 4391 | } |
edamame22 | 0:a9bcda5b678a | 4392 | |
edamame22 | 0:a9bcda5b678a | 4393 | function encodeOne(packet, doneCallback) { |
edamame22 | 0:a9bcda5b678a | 4394 | exports.encodePacket(packet, !isBinary ? false : supportsBinary, true, function(message) { |
edamame22 | 0:a9bcda5b678a | 4395 | doneCallback(null, setLengthHeader(message)); |
edamame22 | 0:a9bcda5b678a | 4396 | }); |
edamame22 | 0:a9bcda5b678a | 4397 | } |
edamame22 | 0:a9bcda5b678a | 4398 | |
edamame22 | 0:a9bcda5b678a | 4399 | map(packets, encodeOne, function(err, results) { |
edamame22 | 0:a9bcda5b678a | 4400 | return callback(results.join('')); |
edamame22 | 0:a9bcda5b678a | 4401 | }); |
edamame22 | 0:a9bcda5b678a | 4402 | }; |
edamame22 | 0:a9bcda5b678a | 4403 | |
edamame22 | 0:a9bcda5b678a | 4404 | /** |
edamame22 | 0:a9bcda5b678a | 4405 | * Async array map using after |
edamame22 | 0:a9bcda5b678a | 4406 | */ |
edamame22 | 0:a9bcda5b678a | 4407 | |
edamame22 | 0:a9bcda5b678a | 4408 | function map(ary, each, done) { |
edamame22 | 0:a9bcda5b678a | 4409 | var result = new Array(ary.length); |
edamame22 | 0:a9bcda5b678a | 4410 | var next = after(ary.length, done); |
edamame22 | 0:a9bcda5b678a | 4411 | |
edamame22 | 0:a9bcda5b678a | 4412 | var eachWithIndex = function(i, el, cb) { |
edamame22 | 0:a9bcda5b678a | 4413 | each(el, function(error, msg) { |
edamame22 | 0:a9bcda5b678a | 4414 | result[i] = msg; |
edamame22 | 0:a9bcda5b678a | 4415 | cb(error, result); |
edamame22 | 0:a9bcda5b678a | 4416 | }); |
edamame22 | 0:a9bcda5b678a | 4417 | }; |
edamame22 | 0:a9bcda5b678a | 4418 | |
edamame22 | 0:a9bcda5b678a | 4419 | for (var i = 0; i < ary.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4420 | eachWithIndex(i, ary[i], next); |
edamame22 | 0:a9bcda5b678a | 4421 | } |
edamame22 | 0:a9bcda5b678a | 4422 | } |
edamame22 | 0:a9bcda5b678a | 4423 | |
edamame22 | 0:a9bcda5b678a | 4424 | /* |
edamame22 | 0:a9bcda5b678a | 4425 | * Decodes data when a payload is maybe expected. Possible binary contents are |
edamame22 | 0:a9bcda5b678a | 4426 | * decoded from their base64 representation |
edamame22 | 0:a9bcda5b678a | 4427 | * |
edamame22 | 0:a9bcda5b678a | 4428 | * @param {String} data, callback method |
edamame22 | 0:a9bcda5b678a | 4429 | * @api public |
edamame22 | 0:a9bcda5b678a | 4430 | */ |
edamame22 | 0:a9bcda5b678a | 4431 | |
edamame22 | 0:a9bcda5b678a | 4432 | exports.decodePayload = function (data, binaryType, callback) { |
edamame22 | 0:a9bcda5b678a | 4433 | if (typeof data != 'string') { |
edamame22 | 0:a9bcda5b678a | 4434 | return exports.decodePayloadAsBinary(data, binaryType, callback); |
edamame22 | 0:a9bcda5b678a | 4435 | } |
edamame22 | 0:a9bcda5b678a | 4436 | |
edamame22 | 0:a9bcda5b678a | 4437 | if (typeof binaryType === 'function') { |
edamame22 | 0:a9bcda5b678a | 4438 | callback = binaryType; |
edamame22 | 0:a9bcda5b678a | 4439 | binaryType = null; |
edamame22 | 0:a9bcda5b678a | 4440 | } |
edamame22 | 0:a9bcda5b678a | 4441 | |
edamame22 | 0:a9bcda5b678a | 4442 | var packet; |
edamame22 | 0:a9bcda5b678a | 4443 | if (data == '') { |
edamame22 | 0:a9bcda5b678a | 4444 | // parser error - ignoring payload |
edamame22 | 0:a9bcda5b678a | 4445 | return callback(err, 0, 1); |
edamame22 | 0:a9bcda5b678a | 4446 | } |
edamame22 | 0:a9bcda5b678a | 4447 | |
edamame22 | 0:a9bcda5b678a | 4448 | var length = '' |
edamame22 | 0:a9bcda5b678a | 4449 | , n, msg; |
edamame22 | 0:a9bcda5b678a | 4450 | |
edamame22 | 0:a9bcda5b678a | 4451 | for (var i = 0, l = data.length; i < l; i++) { |
edamame22 | 0:a9bcda5b678a | 4452 | var chr = data.charAt(i); |
edamame22 | 0:a9bcda5b678a | 4453 | |
edamame22 | 0:a9bcda5b678a | 4454 | if (':' != chr) { |
edamame22 | 0:a9bcda5b678a | 4455 | length += chr; |
edamame22 | 0:a9bcda5b678a | 4456 | } else { |
edamame22 | 0:a9bcda5b678a | 4457 | if ('' == length || (length != (n = Number(length)))) { |
edamame22 | 0:a9bcda5b678a | 4458 | // parser error - ignoring payload |
edamame22 | 0:a9bcda5b678a | 4459 | return callback(err, 0, 1); |
edamame22 | 0:a9bcda5b678a | 4460 | } |
edamame22 | 0:a9bcda5b678a | 4461 | |
edamame22 | 0:a9bcda5b678a | 4462 | msg = data.substr(i + 1, n); |
edamame22 | 0:a9bcda5b678a | 4463 | |
edamame22 | 0:a9bcda5b678a | 4464 | if (length != msg.length) { |
edamame22 | 0:a9bcda5b678a | 4465 | // parser error - ignoring payload |
edamame22 | 0:a9bcda5b678a | 4466 | return callback(err, 0, 1); |
edamame22 | 0:a9bcda5b678a | 4467 | } |
edamame22 | 0:a9bcda5b678a | 4468 | |
edamame22 | 0:a9bcda5b678a | 4469 | if (msg.length) { |
edamame22 | 0:a9bcda5b678a | 4470 | packet = exports.decodePacket(msg, binaryType, true); |
edamame22 | 0:a9bcda5b678a | 4471 | |
edamame22 | 0:a9bcda5b678a | 4472 | if (err.type == packet.type && err.data == packet.data) { |
edamame22 | 0:a9bcda5b678a | 4473 | // parser error in individual packet - ignoring payload |
edamame22 | 0:a9bcda5b678a | 4474 | return callback(err, 0, 1); |
edamame22 | 0:a9bcda5b678a | 4475 | } |
edamame22 | 0:a9bcda5b678a | 4476 | |
edamame22 | 0:a9bcda5b678a | 4477 | var ret = callback(packet, i + n, l); |
edamame22 | 0:a9bcda5b678a | 4478 | if (false === ret) return; |
edamame22 | 0:a9bcda5b678a | 4479 | } |
edamame22 | 0:a9bcda5b678a | 4480 | |
edamame22 | 0:a9bcda5b678a | 4481 | // advance cursor |
edamame22 | 0:a9bcda5b678a | 4482 | i += n; |
edamame22 | 0:a9bcda5b678a | 4483 | length = ''; |
edamame22 | 0:a9bcda5b678a | 4484 | } |
edamame22 | 0:a9bcda5b678a | 4485 | } |
edamame22 | 0:a9bcda5b678a | 4486 | |
edamame22 | 0:a9bcda5b678a | 4487 | if (length != '') { |
edamame22 | 0:a9bcda5b678a | 4488 | // parser error - ignoring payload |
edamame22 | 0:a9bcda5b678a | 4489 | return callback(err, 0, 1); |
edamame22 | 0:a9bcda5b678a | 4490 | } |
edamame22 | 0:a9bcda5b678a | 4491 | |
edamame22 | 0:a9bcda5b678a | 4492 | }; |
edamame22 | 0:a9bcda5b678a | 4493 | |
edamame22 | 0:a9bcda5b678a | 4494 | /** |
edamame22 | 0:a9bcda5b678a | 4495 | * Encodes multiple messages (payload) as binary. |
edamame22 | 0:a9bcda5b678a | 4496 | * |
edamame22 | 0:a9bcda5b678a | 4497 | * <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number |
edamame22 | 0:a9bcda5b678a | 4498 | * 255><data> |
edamame22 | 0:a9bcda5b678a | 4499 | * |
edamame22 | 0:a9bcda5b678a | 4500 | * Example: |
edamame22 | 0:a9bcda5b678a | 4501 | * 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers |
edamame22 | 0:a9bcda5b678a | 4502 | * |
edamame22 | 0:a9bcda5b678a | 4503 | * @param {Array} packets |
edamame22 | 0:a9bcda5b678a | 4504 | * @return {ArrayBuffer} encoded payload |
edamame22 | 0:a9bcda5b678a | 4505 | * @api private |
edamame22 | 0:a9bcda5b678a | 4506 | */ |
edamame22 | 0:a9bcda5b678a | 4507 | |
edamame22 | 0:a9bcda5b678a | 4508 | exports.encodePayloadAsArrayBuffer = function(packets, callback) { |
edamame22 | 0:a9bcda5b678a | 4509 | if (!packets.length) { |
edamame22 | 0:a9bcda5b678a | 4510 | return callback(new ArrayBuffer(0)); |
edamame22 | 0:a9bcda5b678a | 4511 | } |
edamame22 | 0:a9bcda5b678a | 4512 | |
edamame22 | 0:a9bcda5b678a | 4513 | function encodeOne(packet, doneCallback) { |
edamame22 | 0:a9bcda5b678a | 4514 | exports.encodePacket(packet, true, true, function(data) { |
edamame22 | 0:a9bcda5b678a | 4515 | return doneCallback(null, data); |
edamame22 | 0:a9bcda5b678a | 4516 | }); |
edamame22 | 0:a9bcda5b678a | 4517 | } |
edamame22 | 0:a9bcda5b678a | 4518 | |
edamame22 | 0:a9bcda5b678a | 4519 | map(packets, encodeOne, function(err, encodedPackets) { |
edamame22 | 0:a9bcda5b678a | 4520 | var totalLength = encodedPackets.reduce(function(acc, p) { |
edamame22 | 0:a9bcda5b678a | 4521 | var len; |
edamame22 | 0:a9bcda5b678a | 4522 | if (typeof p === 'string'){ |
edamame22 | 0:a9bcda5b678a | 4523 | len = p.length; |
edamame22 | 0:a9bcda5b678a | 4524 | } else { |
edamame22 | 0:a9bcda5b678a | 4525 | len = p.byteLength; |
edamame22 | 0:a9bcda5b678a | 4526 | } |
edamame22 | 0:a9bcda5b678a | 4527 | return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2 |
edamame22 | 0:a9bcda5b678a | 4528 | }, 0); |
edamame22 | 0:a9bcda5b678a | 4529 | |
edamame22 | 0:a9bcda5b678a | 4530 | var resultArray = new Uint8Array(totalLength); |
edamame22 | 0:a9bcda5b678a | 4531 | |
edamame22 | 0:a9bcda5b678a | 4532 | var bufferIndex = 0; |
edamame22 | 0:a9bcda5b678a | 4533 | encodedPackets.forEach(function(p) { |
edamame22 | 0:a9bcda5b678a | 4534 | var isString = typeof p === 'string'; |
edamame22 | 0:a9bcda5b678a | 4535 | var ab = p; |
edamame22 | 0:a9bcda5b678a | 4536 | if (isString) { |
edamame22 | 0:a9bcda5b678a | 4537 | var view = new Uint8Array(p.length); |
edamame22 | 0:a9bcda5b678a | 4538 | for (var i = 0; i < p.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4539 | view[i] = p.charCodeAt(i); |
edamame22 | 0:a9bcda5b678a | 4540 | } |
edamame22 | 0:a9bcda5b678a | 4541 | ab = view.buffer; |
edamame22 | 0:a9bcda5b678a | 4542 | } |
edamame22 | 0:a9bcda5b678a | 4543 | |
edamame22 | 0:a9bcda5b678a | 4544 | if (isString) { // not true binary |
edamame22 | 0:a9bcda5b678a | 4545 | resultArray[bufferIndex++] = 0; |
edamame22 | 0:a9bcda5b678a | 4546 | } else { // true binary |
edamame22 | 0:a9bcda5b678a | 4547 | resultArray[bufferIndex++] = 1; |
edamame22 | 0:a9bcda5b678a | 4548 | } |
edamame22 | 0:a9bcda5b678a | 4549 | |
edamame22 | 0:a9bcda5b678a | 4550 | var lenStr = ab.byteLength.toString(); |
edamame22 | 0:a9bcda5b678a | 4551 | for (var i = 0; i < lenStr.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4552 | resultArray[bufferIndex++] = parseInt(lenStr[i]); |
edamame22 | 0:a9bcda5b678a | 4553 | } |
edamame22 | 0:a9bcda5b678a | 4554 | resultArray[bufferIndex++] = 255; |
edamame22 | 0:a9bcda5b678a | 4555 | |
edamame22 | 0:a9bcda5b678a | 4556 | var view = new Uint8Array(ab); |
edamame22 | 0:a9bcda5b678a | 4557 | for (var i = 0; i < view.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4558 | resultArray[bufferIndex++] = view[i]; |
edamame22 | 0:a9bcda5b678a | 4559 | } |
edamame22 | 0:a9bcda5b678a | 4560 | }); |
edamame22 | 0:a9bcda5b678a | 4561 | |
edamame22 | 0:a9bcda5b678a | 4562 | return callback(resultArray.buffer); |
edamame22 | 0:a9bcda5b678a | 4563 | }); |
edamame22 | 0:a9bcda5b678a | 4564 | }; |
edamame22 | 0:a9bcda5b678a | 4565 | |
edamame22 | 0:a9bcda5b678a | 4566 | /** |
edamame22 | 0:a9bcda5b678a | 4567 | * Encode as Blob |
edamame22 | 0:a9bcda5b678a | 4568 | */ |
edamame22 | 0:a9bcda5b678a | 4569 | |
edamame22 | 0:a9bcda5b678a | 4570 | exports.encodePayloadAsBlob = function(packets, callback) { |
edamame22 | 0:a9bcda5b678a | 4571 | function encodeOne(packet, doneCallback) { |
edamame22 | 0:a9bcda5b678a | 4572 | exports.encodePacket(packet, true, true, function(encoded) { |
edamame22 | 0:a9bcda5b678a | 4573 | var binaryIdentifier = new Uint8Array(1); |
edamame22 | 0:a9bcda5b678a | 4574 | binaryIdentifier[0] = 1; |
edamame22 | 0:a9bcda5b678a | 4575 | if (typeof encoded === 'string') { |
edamame22 | 0:a9bcda5b678a | 4576 | var view = new Uint8Array(encoded.length); |
edamame22 | 0:a9bcda5b678a | 4577 | for (var i = 0; i < encoded.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4578 | view[i] = encoded.charCodeAt(i); |
edamame22 | 0:a9bcda5b678a | 4579 | } |
edamame22 | 0:a9bcda5b678a | 4580 | encoded = view.buffer; |
edamame22 | 0:a9bcda5b678a | 4581 | binaryIdentifier[0] = 0; |
edamame22 | 0:a9bcda5b678a | 4582 | } |
edamame22 | 0:a9bcda5b678a | 4583 | |
edamame22 | 0:a9bcda5b678a | 4584 | var len = (encoded instanceof ArrayBuffer) |
edamame22 | 0:a9bcda5b678a | 4585 | ? encoded.byteLength |
edamame22 | 0:a9bcda5b678a | 4586 | : encoded.size; |
edamame22 | 0:a9bcda5b678a | 4587 | |
edamame22 | 0:a9bcda5b678a | 4588 | var lenStr = len.toString(); |
edamame22 | 0:a9bcda5b678a | 4589 | var lengthAry = new Uint8Array(lenStr.length + 1); |
edamame22 | 0:a9bcda5b678a | 4590 | for (var i = 0; i < lenStr.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4591 | lengthAry[i] = parseInt(lenStr[i]); |
edamame22 | 0:a9bcda5b678a | 4592 | } |
edamame22 | 0:a9bcda5b678a | 4593 | lengthAry[lenStr.length] = 255; |
edamame22 | 0:a9bcda5b678a | 4594 | |
edamame22 | 0:a9bcda5b678a | 4595 | if (Blob) { |
edamame22 | 0:a9bcda5b678a | 4596 | var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]); |
edamame22 | 0:a9bcda5b678a | 4597 | doneCallback(null, blob); |
edamame22 | 0:a9bcda5b678a | 4598 | } |
edamame22 | 0:a9bcda5b678a | 4599 | }); |
edamame22 | 0:a9bcda5b678a | 4600 | } |
edamame22 | 0:a9bcda5b678a | 4601 | |
edamame22 | 0:a9bcda5b678a | 4602 | map(packets, encodeOne, function(err, results) { |
edamame22 | 0:a9bcda5b678a | 4603 | return callback(new Blob(results)); |
edamame22 | 0:a9bcda5b678a | 4604 | }); |
edamame22 | 0:a9bcda5b678a | 4605 | }; |
edamame22 | 0:a9bcda5b678a | 4606 | |
edamame22 | 0:a9bcda5b678a | 4607 | /* |
edamame22 | 0:a9bcda5b678a | 4608 | * Decodes data when a payload is maybe expected. Strings are decoded by |
edamame22 | 0:a9bcda5b678a | 4609 | * interpreting each byte as a key code for entries marked to start with 0. See |
edamame22 | 0:a9bcda5b678a | 4610 | * description of encodePayloadAsBinary |
edamame22 | 0:a9bcda5b678a | 4611 | * |
edamame22 | 0:a9bcda5b678a | 4612 | * @param {ArrayBuffer} data, callback method |
edamame22 | 0:a9bcda5b678a | 4613 | * @api public |
edamame22 | 0:a9bcda5b678a | 4614 | */ |
edamame22 | 0:a9bcda5b678a | 4615 | |
edamame22 | 0:a9bcda5b678a | 4616 | exports.decodePayloadAsBinary = function (data, binaryType, callback) { |
edamame22 | 0:a9bcda5b678a | 4617 | if (typeof binaryType === 'function') { |
edamame22 | 0:a9bcda5b678a | 4618 | callback = binaryType; |
edamame22 | 0:a9bcda5b678a | 4619 | binaryType = null; |
edamame22 | 0:a9bcda5b678a | 4620 | } |
edamame22 | 0:a9bcda5b678a | 4621 | |
edamame22 | 0:a9bcda5b678a | 4622 | var bufferTail = data; |
edamame22 | 0:a9bcda5b678a | 4623 | var buffers = []; |
edamame22 | 0:a9bcda5b678a | 4624 | |
edamame22 | 0:a9bcda5b678a | 4625 | var numberTooLong = false; |
edamame22 | 0:a9bcda5b678a | 4626 | while (bufferTail.byteLength > 0) { |
edamame22 | 0:a9bcda5b678a | 4627 | var tailArray = new Uint8Array(bufferTail); |
edamame22 | 0:a9bcda5b678a | 4628 | var isString = tailArray[0] === 0; |
edamame22 | 0:a9bcda5b678a | 4629 | var msgLength = ''; |
edamame22 | 0:a9bcda5b678a | 4630 | |
edamame22 | 0:a9bcda5b678a | 4631 | for (var i = 1; ; i++) { |
edamame22 | 0:a9bcda5b678a | 4632 | if (tailArray[i] == 255) break; |
edamame22 | 0:a9bcda5b678a | 4633 | |
edamame22 | 0:a9bcda5b678a | 4634 | if (msgLength.length > 310) { |
edamame22 | 0:a9bcda5b678a | 4635 | numberTooLong = true; |
edamame22 | 0:a9bcda5b678a | 4636 | break; |
edamame22 | 0:a9bcda5b678a | 4637 | } |
edamame22 | 0:a9bcda5b678a | 4638 | |
edamame22 | 0:a9bcda5b678a | 4639 | msgLength += tailArray[i]; |
edamame22 | 0:a9bcda5b678a | 4640 | } |
edamame22 | 0:a9bcda5b678a | 4641 | |
edamame22 | 0:a9bcda5b678a | 4642 | if(numberTooLong) return callback(err, 0, 1); |
edamame22 | 0:a9bcda5b678a | 4643 | |
edamame22 | 0:a9bcda5b678a | 4644 | bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length); |
edamame22 | 0:a9bcda5b678a | 4645 | msgLength = parseInt(msgLength); |
edamame22 | 0:a9bcda5b678a | 4646 | |
edamame22 | 0:a9bcda5b678a | 4647 | var msg = sliceBuffer(bufferTail, 0, msgLength); |
edamame22 | 0:a9bcda5b678a | 4648 | if (isString) { |
edamame22 | 0:a9bcda5b678a | 4649 | try { |
edamame22 | 0:a9bcda5b678a | 4650 | msg = String.fromCharCode.apply(null, new Uint8Array(msg)); |
edamame22 | 0:a9bcda5b678a | 4651 | } catch (e) { |
edamame22 | 0:a9bcda5b678a | 4652 | // iPhone Safari doesn't let you apply to typed arrays |
edamame22 | 0:a9bcda5b678a | 4653 | var typed = new Uint8Array(msg); |
edamame22 | 0:a9bcda5b678a | 4654 | msg = ''; |
edamame22 | 0:a9bcda5b678a | 4655 | for (var i = 0; i < typed.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4656 | msg += String.fromCharCode(typed[i]); |
edamame22 | 0:a9bcda5b678a | 4657 | } |
edamame22 | 0:a9bcda5b678a | 4658 | } |
edamame22 | 0:a9bcda5b678a | 4659 | } |
edamame22 | 0:a9bcda5b678a | 4660 | |
edamame22 | 0:a9bcda5b678a | 4661 | buffers.push(msg); |
edamame22 | 0:a9bcda5b678a | 4662 | bufferTail = sliceBuffer(bufferTail, msgLength); |
edamame22 | 0:a9bcda5b678a | 4663 | } |
edamame22 | 0:a9bcda5b678a | 4664 | |
edamame22 | 0:a9bcda5b678a | 4665 | var total = buffers.length; |
edamame22 | 0:a9bcda5b678a | 4666 | buffers.forEach(function(buffer, i) { |
edamame22 | 0:a9bcda5b678a | 4667 | callback(exports.decodePacket(buffer, binaryType, true), i, total); |
edamame22 | 0:a9bcda5b678a | 4668 | }); |
edamame22 | 0:a9bcda5b678a | 4669 | }; |
edamame22 | 0:a9bcda5b678a | 4670 | |
edamame22 | 0:a9bcda5b678a | 4671 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 4672 | },{"./keys":26,"after":27,"arraybuffer.slice":28,"base64-arraybuffer":29,"blob":30,"has-binary":31,"utf8":33}],26:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4673 | |
edamame22 | 0:a9bcda5b678a | 4674 | /** |
edamame22 | 0:a9bcda5b678a | 4675 | * Gets the keys for an object. |
edamame22 | 0:a9bcda5b678a | 4676 | * |
edamame22 | 0:a9bcda5b678a | 4677 | * @return {Array} keys |
edamame22 | 0:a9bcda5b678a | 4678 | * @api private |
edamame22 | 0:a9bcda5b678a | 4679 | */ |
edamame22 | 0:a9bcda5b678a | 4680 | |
edamame22 | 0:a9bcda5b678a | 4681 | module.exports = Object.keys || function keys (obj){ |
edamame22 | 0:a9bcda5b678a | 4682 | var arr = []; |
edamame22 | 0:a9bcda5b678a | 4683 | var has = Object.prototype.hasOwnProperty; |
edamame22 | 0:a9bcda5b678a | 4684 | |
edamame22 | 0:a9bcda5b678a | 4685 | for (var i in obj) { |
edamame22 | 0:a9bcda5b678a | 4686 | if (has.call(obj, i)) { |
edamame22 | 0:a9bcda5b678a | 4687 | arr.push(i); |
edamame22 | 0:a9bcda5b678a | 4688 | } |
edamame22 | 0:a9bcda5b678a | 4689 | } |
edamame22 | 0:a9bcda5b678a | 4690 | return arr; |
edamame22 | 0:a9bcda5b678a | 4691 | }; |
edamame22 | 0:a9bcda5b678a | 4692 | |
edamame22 | 0:a9bcda5b678a | 4693 | },{}],27:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4694 | module.exports = after |
edamame22 | 0:a9bcda5b678a | 4695 | |
edamame22 | 0:a9bcda5b678a | 4696 | function after(count, callback, err_cb) { |
edamame22 | 0:a9bcda5b678a | 4697 | var bail = false |
edamame22 | 0:a9bcda5b678a | 4698 | err_cb = err_cb || noop |
edamame22 | 0:a9bcda5b678a | 4699 | proxy.count = count |
edamame22 | 0:a9bcda5b678a | 4700 | |
edamame22 | 0:a9bcda5b678a | 4701 | return (count === 0) ? callback() : proxy |
edamame22 | 0:a9bcda5b678a | 4702 | |
edamame22 | 0:a9bcda5b678a | 4703 | function proxy(err, result) { |
edamame22 | 0:a9bcda5b678a | 4704 | if (proxy.count <= 0) { |
edamame22 | 0:a9bcda5b678a | 4705 | throw new Error('after called too many times') |
edamame22 | 0:a9bcda5b678a | 4706 | } |
edamame22 | 0:a9bcda5b678a | 4707 | --proxy.count |
edamame22 | 0:a9bcda5b678a | 4708 | |
edamame22 | 0:a9bcda5b678a | 4709 | // after first error, rest are passed to err_cb |
edamame22 | 0:a9bcda5b678a | 4710 | if (err) { |
edamame22 | 0:a9bcda5b678a | 4711 | bail = true |
edamame22 | 0:a9bcda5b678a | 4712 | callback(err) |
edamame22 | 0:a9bcda5b678a | 4713 | // future error callbacks will go to error handler |
edamame22 | 0:a9bcda5b678a | 4714 | callback = err_cb |
edamame22 | 0:a9bcda5b678a | 4715 | } else if (proxy.count === 0 && !bail) { |
edamame22 | 0:a9bcda5b678a | 4716 | callback(null, result) |
edamame22 | 0:a9bcda5b678a | 4717 | } |
edamame22 | 0:a9bcda5b678a | 4718 | } |
edamame22 | 0:a9bcda5b678a | 4719 | } |
edamame22 | 0:a9bcda5b678a | 4720 | |
edamame22 | 0:a9bcda5b678a | 4721 | function noop() {} |
edamame22 | 0:a9bcda5b678a | 4722 | |
edamame22 | 0:a9bcda5b678a | 4723 | },{}],28:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4724 | /** |
edamame22 | 0:a9bcda5b678a | 4725 | * An abstraction for slicing an arraybuffer even when |
edamame22 | 0:a9bcda5b678a | 4726 | * ArrayBuffer.prototype.slice is not supported |
edamame22 | 0:a9bcda5b678a | 4727 | * |
edamame22 | 0:a9bcda5b678a | 4728 | * @api public |
edamame22 | 0:a9bcda5b678a | 4729 | */ |
edamame22 | 0:a9bcda5b678a | 4730 | |
edamame22 | 0:a9bcda5b678a | 4731 | module.exports = function(arraybuffer, start, end) { |
edamame22 | 0:a9bcda5b678a | 4732 | var bytes = arraybuffer.byteLength; |
edamame22 | 0:a9bcda5b678a | 4733 | start = start || 0; |
edamame22 | 0:a9bcda5b678a | 4734 | end = end || bytes; |
edamame22 | 0:a9bcda5b678a | 4735 | |
edamame22 | 0:a9bcda5b678a | 4736 | if (arraybuffer.slice) { return arraybuffer.slice(start, end); } |
edamame22 | 0:a9bcda5b678a | 4737 | |
edamame22 | 0:a9bcda5b678a | 4738 | if (start < 0) { start += bytes; } |
edamame22 | 0:a9bcda5b678a | 4739 | if (end < 0) { end += bytes; } |
edamame22 | 0:a9bcda5b678a | 4740 | if (end > bytes) { end = bytes; } |
edamame22 | 0:a9bcda5b678a | 4741 | |
edamame22 | 0:a9bcda5b678a | 4742 | if (start >= bytes || start >= end || bytes === 0) { |
edamame22 | 0:a9bcda5b678a | 4743 | return new ArrayBuffer(0); |
edamame22 | 0:a9bcda5b678a | 4744 | } |
edamame22 | 0:a9bcda5b678a | 4745 | |
edamame22 | 0:a9bcda5b678a | 4746 | var abv = new Uint8Array(arraybuffer); |
edamame22 | 0:a9bcda5b678a | 4747 | var result = new Uint8Array(end - start); |
edamame22 | 0:a9bcda5b678a | 4748 | for (var i = start, ii = 0; i < end; i++, ii++) { |
edamame22 | 0:a9bcda5b678a | 4749 | result[ii] = abv[i]; |
edamame22 | 0:a9bcda5b678a | 4750 | } |
edamame22 | 0:a9bcda5b678a | 4751 | return result.buffer; |
edamame22 | 0:a9bcda5b678a | 4752 | }; |
edamame22 | 0:a9bcda5b678a | 4753 | |
edamame22 | 0:a9bcda5b678a | 4754 | },{}],29:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4755 | /* |
edamame22 | 0:a9bcda5b678a | 4756 | * base64-arraybuffer |
edamame22 | 0:a9bcda5b678a | 4757 | * https://github.com/niklasvh/base64-arraybuffer |
edamame22 | 0:a9bcda5b678a | 4758 | * |
edamame22 | 0:a9bcda5b678a | 4759 | * Copyright (c) 2012 Niklas von Hertzen |
edamame22 | 0:a9bcda5b678a | 4760 | * Licensed under the MIT license. |
edamame22 | 0:a9bcda5b678a | 4761 | */ |
edamame22 | 0:a9bcda5b678a | 4762 | (function(chars){ |
edamame22 | 0:a9bcda5b678a | 4763 | "use strict"; |
edamame22 | 0:a9bcda5b678a | 4764 | |
edamame22 | 0:a9bcda5b678a | 4765 | exports.encode = function(arraybuffer) { |
edamame22 | 0:a9bcda5b678a | 4766 | var bytes = new Uint8Array(arraybuffer), |
edamame22 | 0:a9bcda5b678a | 4767 | i, len = bytes.length, base64 = ""; |
edamame22 | 0:a9bcda5b678a | 4768 | |
edamame22 | 0:a9bcda5b678a | 4769 | for (i = 0; i < len; i+=3) { |
edamame22 | 0:a9bcda5b678a | 4770 | base64 += chars[bytes[i] >> 2]; |
edamame22 | 0:a9bcda5b678a | 4771 | base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; |
edamame22 | 0:a9bcda5b678a | 4772 | base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; |
edamame22 | 0:a9bcda5b678a | 4773 | base64 += chars[bytes[i + 2] & 63]; |
edamame22 | 0:a9bcda5b678a | 4774 | } |
edamame22 | 0:a9bcda5b678a | 4775 | |
edamame22 | 0:a9bcda5b678a | 4776 | if ((len % 3) === 2) { |
edamame22 | 0:a9bcda5b678a | 4777 | base64 = base64.substring(0, base64.length - 1) + "="; |
edamame22 | 0:a9bcda5b678a | 4778 | } else if (len % 3 === 1) { |
edamame22 | 0:a9bcda5b678a | 4779 | base64 = base64.substring(0, base64.length - 2) + "=="; |
edamame22 | 0:a9bcda5b678a | 4780 | } |
edamame22 | 0:a9bcda5b678a | 4781 | |
edamame22 | 0:a9bcda5b678a | 4782 | return base64; |
edamame22 | 0:a9bcda5b678a | 4783 | }; |
edamame22 | 0:a9bcda5b678a | 4784 | |
edamame22 | 0:a9bcda5b678a | 4785 | exports.decode = function(base64) { |
edamame22 | 0:a9bcda5b678a | 4786 | var bufferLength = base64.length * 0.75, |
edamame22 | 0:a9bcda5b678a | 4787 | len = base64.length, i, p = 0, |
edamame22 | 0:a9bcda5b678a | 4788 | encoded1, encoded2, encoded3, encoded4; |
edamame22 | 0:a9bcda5b678a | 4789 | |
edamame22 | 0:a9bcda5b678a | 4790 | if (base64[base64.length - 1] === "=") { |
edamame22 | 0:a9bcda5b678a | 4791 | bufferLength--; |
edamame22 | 0:a9bcda5b678a | 4792 | if (base64[base64.length - 2] === "=") { |
edamame22 | 0:a9bcda5b678a | 4793 | bufferLength--; |
edamame22 | 0:a9bcda5b678a | 4794 | } |
edamame22 | 0:a9bcda5b678a | 4795 | } |
edamame22 | 0:a9bcda5b678a | 4796 | |
edamame22 | 0:a9bcda5b678a | 4797 | var arraybuffer = new ArrayBuffer(bufferLength), |
edamame22 | 0:a9bcda5b678a | 4798 | bytes = new Uint8Array(arraybuffer); |
edamame22 | 0:a9bcda5b678a | 4799 | |
edamame22 | 0:a9bcda5b678a | 4800 | for (i = 0; i < len; i+=4) { |
edamame22 | 0:a9bcda5b678a | 4801 | encoded1 = chars.indexOf(base64[i]); |
edamame22 | 0:a9bcda5b678a | 4802 | encoded2 = chars.indexOf(base64[i+1]); |
edamame22 | 0:a9bcda5b678a | 4803 | encoded3 = chars.indexOf(base64[i+2]); |
edamame22 | 0:a9bcda5b678a | 4804 | encoded4 = chars.indexOf(base64[i+3]); |
edamame22 | 0:a9bcda5b678a | 4805 | |
edamame22 | 0:a9bcda5b678a | 4806 | bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); |
edamame22 | 0:a9bcda5b678a | 4807 | bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); |
edamame22 | 0:a9bcda5b678a | 4808 | bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); |
edamame22 | 0:a9bcda5b678a | 4809 | } |
edamame22 | 0:a9bcda5b678a | 4810 | |
edamame22 | 0:a9bcda5b678a | 4811 | return arraybuffer; |
edamame22 | 0:a9bcda5b678a | 4812 | }; |
edamame22 | 0:a9bcda5b678a | 4813 | })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); |
edamame22 | 0:a9bcda5b678a | 4814 | |
edamame22 | 0:a9bcda5b678a | 4815 | },{}],30:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4816 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 4817 | /** |
edamame22 | 0:a9bcda5b678a | 4818 | * Create a blob builder even when vendor prefixes exist |
edamame22 | 0:a9bcda5b678a | 4819 | */ |
edamame22 | 0:a9bcda5b678a | 4820 | |
edamame22 | 0:a9bcda5b678a | 4821 | var BlobBuilder = global.BlobBuilder |
edamame22 | 0:a9bcda5b678a | 4822 | || global.WebKitBlobBuilder |
edamame22 | 0:a9bcda5b678a | 4823 | || global.MSBlobBuilder |
edamame22 | 0:a9bcda5b678a | 4824 | || global.MozBlobBuilder; |
edamame22 | 0:a9bcda5b678a | 4825 | |
edamame22 | 0:a9bcda5b678a | 4826 | /** |
edamame22 | 0:a9bcda5b678a | 4827 | * Check if Blob constructor is supported |
edamame22 | 0:a9bcda5b678a | 4828 | */ |
edamame22 | 0:a9bcda5b678a | 4829 | |
edamame22 | 0:a9bcda5b678a | 4830 | var blobSupported = (function() { |
edamame22 | 0:a9bcda5b678a | 4831 | try { |
edamame22 | 0:a9bcda5b678a | 4832 | var b = new Blob(['hi']); |
edamame22 | 0:a9bcda5b678a | 4833 | return b.size == 2; |
edamame22 | 0:a9bcda5b678a | 4834 | } catch(e) { |
edamame22 | 0:a9bcda5b678a | 4835 | return false; |
edamame22 | 0:a9bcda5b678a | 4836 | } |
edamame22 | 0:a9bcda5b678a | 4837 | })(); |
edamame22 | 0:a9bcda5b678a | 4838 | |
edamame22 | 0:a9bcda5b678a | 4839 | /** |
edamame22 | 0:a9bcda5b678a | 4840 | * Check if BlobBuilder is supported |
edamame22 | 0:a9bcda5b678a | 4841 | */ |
edamame22 | 0:a9bcda5b678a | 4842 | |
edamame22 | 0:a9bcda5b678a | 4843 | var blobBuilderSupported = BlobBuilder |
edamame22 | 0:a9bcda5b678a | 4844 | && BlobBuilder.prototype.append |
edamame22 | 0:a9bcda5b678a | 4845 | && BlobBuilder.prototype.getBlob; |
edamame22 | 0:a9bcda5b678a | 4846 | |
edamame22 | 0:a9bcda5b678a | 4847 | function BlobBuilderConstructor(ary, options) { |
edamame22 | 0:a9bcda5b678a | 4848 | options = options || {}; |
edamame22 | 0:a9bcda5b678a | 4849 | |
edamame22 | 0:a9bcda5b678a | 4850 | var bb = new BlobBuilder(); |
edamame22 | 0:a9bcda5b678a | 4851 | for (var i = 0; i < ary.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4852 | bb.append(ary[i]); |
edamame22 | 0:a9bcda5b678a | 4853 | } |
edamame22 | 0:a9bcda5b678a | 4854 | return (options.type) ? bb.getBlob(options.type) : bb.getBlob(); |
edamame22 | 0:a9bcda5b678a | 4855 | }; |
edamame22 | 0:a9bcda5b678a | 4856 | |
edamame22 | 0:a9bcda5b678a | 4857 | module.exports = (function() { |
edamame22 | 0:a9bcda5b678a | 4858 | if (blobSupported) { |
edamame22 | 0:a9bcda5b678a | 4859 | return global.Blob; |
edamame22 | 0:a9bcda5b678a | 4860 | } else if (blobBuilderSupported) { |
edamame22 | 0:a9bcda5b678a | 4861 | return BlobBuilderConstructor; |
edamame22 | 0:a9bcda5b678a | 4862 | } else { |
edamame22 | 0:a9bcda5b678a | 4863 | return undefined; |
edamame22 | 0:a9bcda5b678a | 4864 | } |
edamame22 | 0:a9bcda5b678a | 4865 | })(); |
edamame22 | 0:a9bcda5b678a | 4866 | |
edamame22 | 0:a9bcda5b678a | 4867 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 4868 | },{}],31:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4869 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 4870 | |
edamame22 | 0:a9bcda5b678a | 4871 | /* |
edamame22 | 0:a9bcda5b678a | 4872 | * Module requirements. |
edamame22 | 0:a9bcda5b678a | 4873 | */ |
edamame22 | 0:a9bcda5b678a | 4874 | |
edamame22 | 0:a9bcda5b678a | 4875 | var isArray = _dereq_('isarray'); |
edamame22 | 0:a9bcda5b678a | 4876 | |
edamame22 | 0:a9bcda5b678a | 4877 | /** |
edamame22 | 0:a9bcda5b678a | 4878 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 4879 | */ |
edamame22 | 0:a9bcda5b678a | 4880 | |
edamame22 | 0:a9bcda5b678a | 4881 | module.exports = hasBinary; |
edamame22 | 0:a9bcda5b678a | 4882 | |
edamame22 | 0:a9bcda5b678a | 4883 | /** |
edamame22 | 0:a9bcda5b678a | 4884 | * Checks for binary data. |
edamame22 | 0:a9bcda5b678a | 4885 | * |
edamame22 | 0:a9bcda5b678a | 4886 | * Right now only Buffer and ArrayBuffer are supported.. |
edamame22 | 0:a9bcda5b678a | 4887 | * |
edamame22 | 0:a9bcda5b678a | 4888 | * @param {Object} anything |
edamame22 | 0:a9bcda5b678a | 4889 | * @api public |
edamame22 | 0:a9bcda5b678a | 4890 | */ |
edamame22 | 0:a9bcda5b678a | 4891 | |
edamame22 | 0:a9bcda5b678a | 4892 | function hasBinary(data) { |
edamame22 | 0:a9bcda5b678a | 4893 | |
edamame22 | 0:a9bcda5b678a | 4894 | function _hasBinary(obj) { |
edamame22 | 0:a9bcda5b678a | 4895 | if (!obj) return false; |
edamame22 | 0:a9bcda5b678a | 4896 | |
edamame22 | 0:a9bcda5b678a | 4897 | if ( (global.Buffer && global.Buffer.isBuffer(obj)) || |
edamame22 | 0:a9bcda5b678a | 4898 | (global.ArrayBuffer && obj instanceof ArrayBuffer) || |
edamame22 | 0:a9bcda5b678a | 4899 | (global.Blob && obj instanceof Blob) || |
edamame22 | 0:a9bcda5b678a | 4900 | (global.File && obj instanceof File) |
edamame22 | 0:a9bcda5b678a | 4901 | ) { |
edamame22 | 0:a9bcda5b678a | 4902 | return true; |
edamame22 | 0:a9bcda5b678a | 4903 | } |
edamame22 | 0:a9bcda5b678a | 4904 | |
edamame22 | 0:a9bcda5b678a | 4905 | if (isArray(obj)) { |
edamame22 | 0:a9bcda5b678a | 4906 | for (var i = 0; i < obj.length; i++) { |
edamame22 | 0:a9bcda5b678a | 4907 | if (_hasBinary(obj[i])) { |
edamame22 | 0:a9bcda5b678a | 4908 | return true; |
edamame22 | 0:a9bcda5b678a | 4909 | } |
edamame22 | 0:a9bcda5b678a | 4910 | } |
edamame22 | 0:a9bcda5b678a | 4911 | } else if (obj && 'object' == typeof obj) { |
edamame22 | 0:a9bcda5b678a | 4912 | if (obj.toJSON) { |
edamame22 | 0:a9bcda5b678a | 4913 | obj = obj.toJSON(); |
edamame22 | 0:a9bcda5b678a | 4914 | } |
edamame22 | 0:a9bcda5b678a | 4915 | |
edamame22 | 0:a9bcda5b678a | 4916 | for (var key in obj) { |
edamame22 | 0:a9bcda5b678a | 4917 | if (obj.hasOwnProperty(key) && _hasBinary(obj[key])) { |
edamame22 | 0:a9bcda5b678a | 4918 | return true; |
edamame22 | 0:a9bcda5b678a | 4919 | } |
edamame22 | 0:a9bcda5b678a | 4920 | } |
edamame22 | 0:a9bcda5b678a | 4921 | } |
edamame22 | 0:a9bcda5b678a | 4922 | |
edamame22 | 0:a9bcda5b678a | 4923 | return false; |
edamame22 | 0:a9bcda5b678a | 4924 | } |
edamame22 | 0:a9bcda5b678a | 4925 | |
edamame22 | 0:a9bcda5b678a | 4926 | return _hasBinary(data); |
edamame22 | 0:a9bcda5b678a | 4927 | } |
edamame22 | 0:a9bcda5b678a | 4928 | |
edamame22 | 0:a9bcda5b678a | 4929 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 4930 | },{"isarray":32}],32:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4931 | module.exports = Array.isArray || function (arr) { |
edamame22 | 0:a9bcda5b678a | 4932 | return Object.prototype.toString.call(arr) == '[object Array]'; |
edamame22 | 0:a9bcda5b678a | 4933 | }; |
edamame22 | 0:a9bcda5b678a | 4934 | |
edamame22 | 0:a9bcda5b678a | 4935 | },{}],33:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 4936 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 4937 | /*! http://mths.be/utf8js v2.0.0 by @mathias */ |
edamame22 | 0:a9bcda5b678a | 4938 | ;(function(root) { |
edamame22 | 0:a9bcda5b678a | 4939 | |
edamame22 | 0:a9bcda5b678a | 4940 | // Detect free variables `exports` |
edamame22 | 0:a9bcda5b678a | 4941 | var freeExports = typeof exports == 'object' && exports; |
edamame22 | 0:a9bcda5b678a | 4942 | |
edamame22 | 0:a9bcda5b678a | 4943 | // Detect free variable `module` |
edamame22 | 0:a9bcda5b678a | 4944 | var freeModule = typeof module == 'object' && module && |
edamame22 | 0:a9bcda5b678a | 4945 | module.exports == freeExports && module; |
edamame22 | 0:a9bcda5b678a | 4946 | |
edamame22 | 0:a9bcda5b678a | 4947 | // Detect free variable `global`, from Node.js or Browserified code, |
edamame22 | 0:a9bcda5b678a | 4948 | // and use it as `root` |
edamame22 | 0:a9bcda5b678a | 4949 | var freeGlobal = typeof global == 'object' && global; |
edamame22 | 0:a9bcda5b678a | 4950 | if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { |
edamame22 | 0:a9bcda5b678a | 4951 | root = freeGlobal; |
edamame22 | 0:a9bcda5b678a | 4952 | } |
edamame22 | 0:a9bcda5b678a | 4953 | |
edamame22 | 0:a9bcda5b678a | 4954 | /*--------------------------------------------------------------------------*/ |
edamame22 | 0:a9bcda5b678a | 4955 | |
edamame22 | 0:a9bcda5b678a | 4956 | var stringFromCharCode = String.fromCharCode; |
edamame22 | 0:a9bcda5b678a | 4957 | |
edamame22 | 0:a9bcda5b678a | 4958 | // Taken from http://mths.be/punycode |
edamame22 | 0:a9bcda5b678a | 4959 | function ucs2decode(string) { |
edamame22 | 0:a9bcda5b678a | 4960 | var output = []; |
edamame22 | 0:a9bcda5b678a | 4961 | var counter = 0; |
edamame22 | 0:a9bcda5b678a | 4962 | var length = string.length; |
edamame22 | 0:a9bcda5b678a | 4963 | var value; |
edamame22 | 0:a9bcda5b678a | 4964 | var extra; |
edamame22 | 0:a9bcda5b678a | 4965 | while (counter < length) { |
edamame22 | 0:a9bcda5b678a | 4966 | value = string.charCodeAt(counter++); |
edamame22 | 0:a9bcda5b678a | 4967 | if (value >= 0xD800 && value <= 0xDBFF && counter < length) { |
edamame22 | 0:a9bcda5b678a | 4968 | // high surrogate, and there is a next character |
edamame22 | 0:a9bcda5b678a | 4969 | extra = string.charCodeAt(counter++); |
edamame22 | 0:a9bcda5b678a | 4970 | if ((extra & 0xFC00) == 0xDC00) { // low surrogate |
edamame22 | 0:a9bcda5b678a | 4971 | output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); |
edamame22 | 0:a9bcda5b678a | 4972 | } else { |
edamame22 | 0:a9bcda5b678a | 4973 | // unmatched surrogate; only append this code unit, in case the next |
edamame22 | 0:a9bcda5b678a | 4974 | // code unit is the high surrogate of a surrogate pair |
edamame22 | 0:a9bcda5b678a | 4975 | output.push(value); |
edamame22 | 0:a9bcda5b678a | 4976 | counter--; |
edamame22 | 0:a9bcda5b678a | 4977 | } |
edamame22 | 0:a9bcda5b678a | 4978 | } else { |
edamame22 | 0:a9bcda5b678a | 4979 | output.push(value); |
edamame22 | 0:a9bcda5b678a | 4980 | } |
edamame22 | 0:a9bcda5b678a | 4981 | } |
edamame22 | 0:a9bcda5b678a | 4982 | return output; |
edamame22 | 0:a9bcda5b678a | 4983 | } |
edamame22 | 0:a9bcda5b678a | 4984 | |
edamame22 | 0:a9bcda5b678a | 4985 | // Taken from http://mths.be/punycode |
edamame22 | 0:a9bcda5b678a | 4986 | function ucs2encode(array) { |
edamame22 | 0:a9bcda5b678a | 4987 | var length = array.length; |
edamame22 | 0:a9bcda5b678a | 4988 | var index = -1; |
edamame22 | 0:a9bcda5b678a | 4989 | var value; |
edamame22 | 0:a9bcda5b678a | 4990 | var output = ''; |
edamame22 | 0:a9bcda5b678a | 4991 | while (++index < length) { |
edamame22 | 0:a9bcda5b678a | 4992 | value = array[index]; |
edamame22 | 0:a9bcda5b678a | 4993 | if (value > 0xFFFF) { |
edamame22 | 0:a9bcda5b678a | 4994 | value -= 0x10000; |
edamame22 | 0:a9bcda5b678a | 4995 | output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800); |
edamame22 | 0:a9bcda5b678a | 4996 | value = 0xDC00 | value & 0x3FF; |
edamame22 | 0:a9bcda5b678a | 4997 | } |
edamame22 | 0:a9bcda5b678a | 4998 | output += stringFromCharCode(value); |
edamame22 | 0:a9bcda5b678a | 4999 | } |
edamame22 | 0:a9bcda5b678a | 5000 | return output; |
edamame22 | 0:a9bcda5b678a | 5001 | } |
edamame22 | 0:a9bcda5b678a | 5002 | |
edamame22 | 0:a9bcda5b678a | 5003 | /*--------------------------------------------------------------------------*/ |
edamame22 | 0:a9bcda5b678a | 5004 | |
edamame22 | 0:a9bcda5b678a | 5005 | function createByte(codePoint, shift) { |
edamame22 | 0:a9bcda5b678a | 5006 | return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80); |
edamame22 | 0:a9bcda5b678a | 5007 | } |
edamame22 | 0:a9bcda5b678a | 5008 | |
edamame22 | 0:a9bcda5b678a | 5009 | function encodeCodePoint(codePoint) { |
edamame22 | 0:a9bcda5b678a | 5010 | if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence |
edamame22 | 0:a9bcda5b678a | 5011 | return stringFromCharCode(codePoint); |
edamame22 | 0:a9bcda5b678a | 5012 | } |
edamame22 | 0:a9bcda5b678a | 5013 | var symbol = ''; |
edamame22 | 0:a9bcda5b678a | 5014 | if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence |
edamame22 | 0:a9bcda5b678a | 5015 | symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0); |
edamame22 | 0:a9bcda5b678a | 5016 | } |
edamame22 | 0:a9bcda5b678a | 5017 | else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence |
edamame22 | 0:a9bcda5b678a | 5018 | symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0); |
edamame22 | 0:a9bcda5b678a | 5019 | symbol += createByte(codePoint, 6); |
edamame22 | 0:a9bcda5b678a | 5020 | } |
edamame22 | 0:a9bcda5b678a | 5021 | else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence |
edamame22 | 0:a9bcda5b678a | 5022 | symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0); |
edamame22 | 0:a9bcda5b678a | 5023 | symbol += createByte(codePoint, 12); |
edamame22 | 0:a9bcda5b678a | 5024 | symbol += createByte(codePoint, 6); |
edamame22 | 0:a9bcda5b678a | 5025 | } |
edamame22 | 0:a9bcda5b678a | 5026 | symbol += stringFromCharCode((codePoint & 0x3F) | 0x80); |
edamame22 | 0:a9bcda5b678a | 5027 | return symbol; |
edamame22 | 0:a9bcda5b678a | 5028 | } |
edamame22 | 0:a9bcda5b678a | 5029 | |
edamame22 | 0:a9bcda5b678a | 5030 | function utf8encode(string) { |
edamame22 | 0:a9bcda5b678a | 5031 | var codePoints = ucs2decode(string); |
edamame22 | 0:a9bcda5b678a | 5032 | |
edamame22 | 0:a9bcda5b678a | 5033 | // console.log(JSON.stringify(codePoints.map(function(x) { |
edamame22 | 0:a9bcda5b678a | 5034 | // return 'U+' + x.toString(16).toUpperCase(); |
edamame22 | 0:a9bcda5b678a | 5035 | // }))); |
edamame22 | 0:a9bcda5b678a | 5036 | |
edamame22 | 0:a9bcda5b678a | 5037 | var length = codePoints.length; |
edamame22 | 0:a9bcda5b678a | 5038 | var index = -1; |
edamame22 | 0:a9bcda5b678a | 5039 | var codePoint; |
edamame22 | 0:a9bcda5b678a | 5040 | var byteString = ''; |
edamame22 | 0:a9bcda5b678a | 5041 | while (++index < length) { |
edamame22 | 0:a9bcda5b678a | 5042 | codePoint = codePoints[index]; |
edamame22 | 0:a9bcda5b678a | 5043 | byteString += encodeCodePoint(codePoint); |
edamame22 | 0:a9bcda5b678a | 5044 | } |
edamame22 | 0:a9bcda5b678a | 5045 | return byteString; |
edamame22 | 0:a9bcda5b678a | 5046 | } |
edamame22 | 0:a9bcda5b678a | 5047 | |
edamame22 | 0:a9bcda5b678a | 5048 | /*--------------------------------------------------------------------------*/ |
edamame22 | 0:a9bcda5b678a | 5049 | |
edamame22 | 0:a9bcda5b678a | 5050 | function readContinuationByte() { |
edamame22 | 0:a9bcda5b678a | 5051 | if (byteIndex >= byteCount) { |
edamame22 | 0:a9bcda5b678a | 5052 | throw Error('Invalid byte index'); |
edamame22 | 0:a9bcda5b678a | 5053 | } |
edamame22 | 0:a9bcda5b678a | 5054 | |
edamame22 | 0:a9bcda5b678a | 5055 | var continuationByte = byteArray[byteIndex] & 0xFF; |
edamame22 | 0:a9bcda5b678a | 5056 | byteIndex++; |
edamame22 | 0:a9bcda5b678a | 5057 | |
edamame22 | 0:a9bcda5b678a | 5058 | if ((continuationByte & 0xC0) == 0x80) { |
edamame22 | 0:a9bcda5b678a | 5059 | return continuationByte & 0x3F; |
edamame22 | 0:a9bcda5b678a | 5060 | } |
edamame22 | 0:a9bcda5b678a | 5061 | |
edamame22 | 0:a9bcda5b678a | 5062 | // If we end up here, it’s not a continuation byte |
edamame22 | 0:a9bcda5b678a | 5063 | throw Error('Invalid continuation byte'); |
edamame22 | 0:a9bcda5b678a | 5064 | } |
edamame22 | 0:a9bcda5b678a | 5065 | |
edamame22 | 0:a9bcda5b678a | 5066 | function decodeSymbol() { |
edamame22 | 0:a9bcda5b678a | 5067 | var byte1; |
edamame22 | 0:a9bcda5b678a | 5068 | var byte2; |
edamame22 | 0:a9bcda5b678a | 5069 | var byte3; |
edamame22 | 0:a9bcda5b678a | 5070 | var byte4; |
edamame22 | 0:a9bcda5b678a | 5071 | var codePoint; |
edamame22 | 0:a9bcda5b678a | 5072 | |
edamame22 | 0:a9bcda5b678a | 5073 | if (byteIndex > byteCount) { |
edamame22 | 0:a9bcda5b678a | 5074 | throw Error('Invalid byte index'); |
edamame22 | 0:a9bcda5b678a | 5075 | } |
edamame22 | 0:a9bcda5b678a | 5076 | |
edamame22 | 0:a9bcda5b678a | 5077 | if (byteIndex == byteCount) { |
edamame22 | 0:a9bcda5b678a | 5078 | return false; |
edamame22 | 0:a9bcda5b678a | 5079 | } |
edamame22 | 0:a9bcda5b678a | 5080 | |
edamame22 | 0:a9bcda5b678a | 5081 | // Read first byte |
edamame22 | 0:a9bcda5b678a | 5082 | byte1 = byteArray[byteIndex] & 0xFF; |
edamame22 | 0:a9bcda5b678a | 5083 | byteIndex++; |
edamame22 | 0:a9bcda5b678a | 5084 | |
edamame22 | 0:a9bcda5b678a | 5085 | // 1-byte sequence (no continuation bytes) |
edamame22 | 0:a9bcda5b678a | 5086 | if ((byte1 & 0x80) == 0) { |
edamame22 | 0:a9bcda5b678a | 5087 | return byte1; |
edamame22 | 0:a9bcda5b678a | 5088 | } |
edamame22 | 0:a9bcda5b678a | 5089 | |
edamame22 | 0:a9bcda5b678a | 5090 | // 2-byte sequence |
edamame22 | 0:a9bcda5b678a | 5091 | if ((byte1 & 0xE0) == 0xC0) { |
edamame22 | 0:a9bcda5b678a | 5092 | var byte2 = readContinuationByte(); |
edamame22 | 0:a9bcda5b678a | 5093 | codePoint = ((byte1 & 0x1F) << 6) | byte2; |
edamame22 | 0:a9bcda5b678a | 5094 | if (codePoint >= 0x80) { |
edamame22 | 0:a9bcda5b678a | 5095 | return codePoint; |
edamame22 | 0:a9bcda5b678a | 5096 | } else { |
edamame22 | 0:a9bcda5b678a | 5097 | throw Error('Invalid continuation byte'); |
edamame22 | 0:a9bcda5b678a | 5098 | } |
edamame22 | 0:a9bcda5b678a | 5099 | } |
edamame22 | 0:a9bcda5b678a | 5100 | |
edamame22 | 0:a9bcda5b678a | 5101 | // 3-byte sequence (may include unpaired surrogates) |
edamame22 | 0:a9bcda5b678a | 5102 | if ((byte1 & 0xF0) == 0xE0) { |
edamame22 | 0:a9bcda5b678a | 5103 | byte2 = readContinuationByte(); |
edamame22 | 0:a9bcda5b678a | 5104 | byte3 = readContinuationByte(); |
edamame22 | 0:a9bcda5b678a | 5105 | codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3; |
edamame22 | 0:a9bcda5b678a | 5106 | if (codePoint >= 0x0800) { |
edamame22 | 0:a9bcda5b678a | 5107 | return codePoint; |
edamame22 | 0:a9bcda5b678a | 5108 | } else { |
edamame22 | 0:a9bcda5b678a | 5109 | throw Error('Invalid continuation byte'); |
edamame22 | 0:a9bcda5b678a | 5110 | } |
edamame22 | 0:a9bcda5b678a | 5111 | } |
edamame22 | 0:a9bcda5b678a | 5112 | |
edamame22 | 0:a9bcda5b678a | 5113 | // 4-byte sequence |
edamame22 | 0:a9bcda5b678a | 5114 | if ((byte1 & 0xF8) == 0xF0) { |
edamame22 | 0:a9bcda5b678a | 5115 | byte2 = readContinuationByte(); |
edamame22 | 0:a9bcda5b678a | 5116 | byte3 = readContinuationByte(); |
edamame22 | 0:a9bcda5b678a | 5117 | byte4 = readContinuationByte(); |
edamame22 | 0:a9bcda5b678a | 5118 | codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) | |
edamame22 | 0:a9bcda5b678a | 5119 | (byte3 << 0x06) | byte4; |
edamame22 | 0:a9bcda5b678a | 5120 | if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) { |
edamame22 | 0:a9bcda5b678a | 5121 | return codePoint; |
edamame22 | 0:a9bcda5b678a | 5122 | } |
edamame22 | 0:a9bcda5b678a | 5123 | } |
edamame22 | 0:a9bcda5b678a | 5124 | |
edamame22 | 0:a9bcda5b678a | 5125 | throw Error('Invalid UTF-8 detected'); |
edamame22 | 0:a9bcda5b678a | 5126 | } |
edamame22 | 0:a9bcda5b678a | 5127 | |
edamame22 | 0:a9bcda5b678a | 5128 | var byteArray; |
edamame22 | 0:a9bcda5b678a | 5129 | var byteCount; |
edamame22 | 0:a9bcda5b678a | 5130 | var byteIndex; |
edamame22 | 0:a9bcda5b678a | 5131 | function utf8decode(byteString) { |
edamame22 | 0:a9bcda5b678a | 5132 | byteArray = ucs2decode(byteString); |
edamame22 | 0:a9bcda5b678a | 5133 | byteCount = byteArray.length; |
edamame22 | 0:a9bcda5b678a | 5134 | byteIndex = 0; |
edamame22 | 0:a9bcda5b678a | 5135 | var codePoints = []; |
edamame22 | 0:a9bcda5b678a | 5136 | var tmp; |
edamame22 | 0:a9bcda5b678a | 5137 | while ((tmp = decodeSymbol()) !== false) { |
edamame22 | 0:a9bcda5b678a | 5138 | codePoints.push(tmp); |
edamame22 | 0:a9bcda5b678a | 5139 | } |
edamame22 | 0:a9bcda5b678a | 5140 | return ucs2encode(codePoints); |
edamame22 | 0:a9bcda5b678a | 5141 | } |
edamame22 | 0:a9bcda5b678a | 5142 | |
edamame22 | 0:a9bcda5b678a | 5143 | /*--------------------------------------------------------------------------*/ |
edamame22 | 0:a9bcda5b678a | 5144 | |
edamame22 | 0:a9bcda5b678a | 5145 | var utf8 = { |
edamame22 | 0:a9bcda5b678a | 5146 | 'version': '2.0.0', |
edamame22 | 0:a9bcda5b678a | 5147 | 'encode': utf8encode, |
edamame22 | 0:a9bcda5b678a | 5148 | 'decode': utf8decode |
edamame22 | 0:a9bcda5b678a | 5149 | }; |
edamame22 | 0:a9bcda5b678a | 5150 | |
edamame22 | 0:a9bcda5b678a | 5151 | // Some AMD build optimizers, like r.js, check for specific condition patterns |
edamame22 | 0:a9bcda5b678a | 5152 | // like the following: |
edamame22 | 0:a9bcda5b678a | 5153 | if ( |
edamame22 | 0:a9bcda5b678a | 5154 | typeof define == 'function' && |
edamame22 | 0:a9bcda5b678a | 5155 | typeof define.amd == 'object' && |
edamame22 | 0:a9bcda5b678a | 5156 | define.amd |
edamame22 | 0:a9bcda5b678a | 5157 | ) { |
edamame22 | 0:a9bcda5b678a | 5158 | define(function() { |
edamame22 | 0:a9bcda5b678a | 5159 | return utf8; |
edamame22 | 0:a9bcda5b678a | 5160 | }); |
edamame22 | 0:a9bcda5b678a | 5161 | } else if (freeExports && !freeExports.nodeType) { |
edamame22 | 0:a9bcda5b678a | 5162 | if (freeModule) { // in Node.js or RingoJS v0.8.0+ |
edamame22 | 0:a9bcda5b678a | 5163 | freeModule.exports = utf8; |
edamame22 | 0:a9bcda5b678a | 5164 | } else { // in Narwhal or RingoJS v0.7.0- |
edamame22 | 0:a9bcda5b678a | 5165 | var object = {}; |
edamame22 | 0:a9bcda5b678a | 5166 | var hasOwnProperty = object.hasOwnProperty; |
edamame22 | 0:a9bcda5b678a | 5167 | for (var key in utf8) { |
edamame22 | 0:a9bcda5b678a | 5168 | hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]); |
edamame22 | 0:a9bcda5b678a | 5169 | } |
edamame22 | 0:a9bcda5b678a | 5170 | } |
edamame22 | 0:a9bcda5b678a | 5171 | } else { // in Rhino or a web browser |
edamame22 | 0:a9bcda5b678a | 5172 | root.utf8 = utf8; |
edamame22 | 0:a9bcda5b678a | 5173 | } |
edamame22 | 0:a9bcda5b678a | 5174 | |
edamame22 | 0:a9bcda5b678a | 5175 | }(this)); |
edamame22 | 0:a9bcda5b678a | 5176 | |
edamame22 | 0:a9bcda5b678a | 5177 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 5178 | },{}],34:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5179 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 5180 | /** |
edamame22 | 0:a9bcda5b678a | 5181 | * JSON parse. |
edamame22 | 0:a9bcda5b678a | 5182 | * |
edamame22 | 0:a9bcda5b678a | 5183 | * @see Based on jQuery#parseJSON (MIT) and JSON2 |
edamame22 | 0:a9bcda5b678a | 5184 | * @api private |
edamame22 | 0:a9bcda5b678a | 5185 | */ |
edamame22 | 0:a9bcda5b678a | 5186 | |
edamame22 | 0:a9bcda5b678a | 5187 | var rvalidchars = /^[\],:{}\s]*$/; |
edamame22 | 0:a9bcda5b678a | 5188 | var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; |
edamame22 | 0:a9bcda5b678a | 5189 | var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; |
edamame22 | 0:a9bcda5b678a | 5190 | var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g; |
edamame22 | 0:a9bcda5b678a | 5191 | var rtrimLeft = /^\s+/; |
edamame22 | 0:a9bcda5b678a | 5192 | var rtrimRight = /\s+$/; |
edamame22 | 0:a9bcda5b678a | 5193 | |
edamame22 | 0:a9bcda5b678a | 5194 | module.exports = function parsejson(data) { |
edamame22 | 0:a9bcda5b678a | 5195 | if ('string' != typeof data || !data) { |
edamame22 | 0:a9bcda5b678a | 5196 | return null; |
edamame22 | 0:a9bcda5b678a | 5197 | } |
edamame22 | 0:a9bcda5b678a | 5198 | |
edamame22 | 0:a9bcda5b678a | 5199 | data = data.replace(rtrimLeft, '').replace(rtrimRight, ''); |
edamame22 | 0:a9bcda5b678a | 5200 | |
edamame22 | 0:a9bcda5b678a | 5201 | // Attempt to parse using the native JSON parser first |
edamame22 | 0:a9bcda5b678a | 5202 | if (global.JSON && JSON.parse) { |
edamame22 | 0:a9bcda5b678a | 5203 | return JSON.parse(data); |
edamame22 | 0:a9bcda5b678a | 5204 | } |
edamame22 | 0:a9bcda5b678a | 5205 | |
edamame22 | 0:a9bcda5b678a | 5206 | if (rvalidchars.test(data.replace(rvalidescape, '@') |
edamame22 | 0:a9bcda5b678a | 5207 | .replace(rvalidtokens, ']') |
edamame22 | 0:a9bcda5b678a | 5208 | .replace(rvalidbraces, ''))) { |
edamame22 | 0:a9bcda5b678a | 5209 | return (new Function('return ' + data))(); |
edamame22 | 0:a9bcda5b678a | 5210 | } |
edamame22 | 0:a9bcda5b678a | 5211 | }; |
edamame22 | 0:a9bcda5b678a | 5212 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 5213 | },{}],35:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5214 | /** |
edamame22 | 0:a9bcda5b678a | 5215 | * Compiles a querystring |
edamame22 | 0:a9bcda5b678a | 5216 | * Returns string representation of the object |
edamame22 | 0:a9bcda5b678a | 5217 | * |
edamame22 | 0:a9bcda5b678a | 5218 | * @param {Object} |
edamame22 | 0:a9bcda5b678a | 5219 | * @api private |
edamame22 | 0:a9bcda5b678a | 5220 | */ |
edamame22 | 0:a9bcda5b678a | 5221 | |
edamame22 | 0:a9bcda5b678a | 5222 | exports.encode = function (obj) { |
edamame22 | 0:a9bcda5b678a | 5223 | var str = ''; |
edamame22 | 0:a9bcda5b678a | 5224 | |
edamame22 | 0:a9bcda5b678a | 5225 | for (var i in obj) { |
edamame22 | 0:a9bcda5b678a | 5226 | if (obj.hasOwnProperty(i)) { |
edamame22 | 0:a9bcda5b678a | 5227 | if (str.length) str += '&'; |
edamame22 | 0:a9bcda5b678a | 5228 | str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); |
edamame22 | 0:a9bcda5b678a | 5229 | } |
edamame22 | 0:a9bcda5b678a | 5230 | } |
edamame22 | 0:a9bcda5b678a | 5231 | |
edamame22 | 0:a9bcda5b678a | 5232 | return str; |
edamame22 | 0:a9bcda5b678a | 5233 | }; |
edamame22 | 0:a9bcda5b678a | 5234 | |
edamame22 | 0:a9bcda5b678a | 5235 | /** |
edamame22 | 0:a9bcda5b678a | 5236 | * Parses a simple querystring into an object |
edamame22 | 0:a9bcda5b678a | 5237 | * |
edamame22 | 0:a9bcda5b678a | 5238 | * @param {String} qs |
edamame22 | 0:a9bcda5b678a | 5239 | * @api private |
edamame22 | 0:a9bcda5b678a | 5240 | */ |
edamame22 | 0:a9bcda5b678a | 5241 | |
edamame22 | 0:a9bcda5b678a | 5242 | exports.decode = function(qs){ |
edamame22 | 0:a9bcda5b678a | 5243 | var qry = {}; |
edamame22 | 0:a9bcda5b678a | 5244 | var pairs = qs.split('&'); |
edamame22 | 0:a9bcda5b678a | 5245 | for (var i = 0, l = pairs.length; i < l; i++) { |
edamame22 | 0:a9bcda5b678a | 5246 | var pair = pairs[i].split('='); |
edamame22 | 0:a9bcda5b678a | 5247 | qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); |
edamame22 | 0:a9bcda5b678a | 5248 | } |
edamame22 | 0:a9bcda5b678a | 5249 | return qry; |
edamame22 | 0:a9bcda5b678a | 5250 | }; |
edamame22 | 0:a9bcda5b678a | 5251 | |
edamame22 | 0:a9bcda5b678a | 5252 | },{}],36:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5253 | /** |
edamame22 | 0:a9bcda5b678a | 5254 | * Parses an URI |
edamame22 | 0:a9bcda5b678a | 5255 | * |
edamame22 | 0:a9bcda5b678a | 5256 | * @author Steven Levithan <stevenlevithan.com> (MIT license) |
edamame22 | 0:a9bcda5b678a | 5257 | * @api private |
edamame22 | 0:a9bcda5b678a | 5258 | */ |
edamame22 | 0:a9bcda5b678a | 5259 | |
edamame22 | 0:a9bcda5b678a | 5260 | var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; |
edamame22 | 0:a9bcda5b678a | 5261 | |
edamame22 | 0:a9bcda5b678a | 5262 | var parts = [ |
edamame22 | 0:a9bcda5b678a | 5263 | 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' |
edamame22 | 0:a9bcda5b678a | 5264 | ]; |
edamame22 | 0:a9bcda5b678a | 5265 | |
edamame22 | 0:a9bcda5b678a | 5266 | module.exports = function parseuri(str) { |
edamame22 | 0:a9bcda5b678a | 5267 | var src = str, |
edamame22 | 0:a9bcda5b678a | 5268 | b = str.indexOf('['), |
edamame22 | 0:a9bcda5b678a | 5269 | e = str.indexOf(']'); |
edamame22 | 0:a9bcda5b678a | 5270 | |
edamame22 | 0:a9bcda5b678a | 5271 | if (b != -1 && e != -1) { |
edamame22 | 0:a9bcda5b678a | 5272 | str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); |
edamame22 | 0:a9bcda5b678a | 5273 | } |
edamame22 | 0:a9bcda5b678a | 5274 | |
edamame22 | 0:a9bcda5b678a | 5275 | var m = re.exec(str || ''), |
edamame22 | 0:a9bcda5b678a | 5276 | uri = {}, |
edamame22 | 0:a9bcda5b678a | 5277 | i = 14; |
edamame22 | 0:a9bcda5b678a | 5278 | |
edamame22 | 0:a9bcda5b678a | 5279 | while (i--) { |
edamame22 | 0:a9bcda5b678a | 5280 | uri[parts[i]] = m[i] || ''; |
edamame22 | 0:a9bcda5b678a | 5281 | } |
edamame22 | 0:a9bcda5b678a | 5282 | |
edamame22 | 0:a9bcda5b678a | 5283 | if (b != -1 && e != -1) { |
edamame22 | 0:a9bcda5b678a | 5284 | uri.source = src; |
edamame22 | 0:a9bcda5b678a | 5285 | uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); |
edamame22 | 0:a9bcda5b678a | 5286 | uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); |
edamame22 | 0:a9bcda5b678a | 5287 | uri.ipv6uri = true; |
edamame22 | 0:a9bcda5b678a | 5288 | } |
edamame22 | 0:a9bcda5b678a | 5289 | |
edamame22 | 0:a9bcda5b678a | 5290 | return uri; |
edamame22 | 0:a9bcda5b678a | 5291 | }; |
edamame22 | 0:a9bcda5b678a | 5292 | |
edamame22 | 0:a9bcda5b678a | 5293 | },{}],37:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5294 | |
edamame22 | 0:a9bcda5b678a | 5295 | /** |
edamame22 | 0:a9bcda5b678a | 5296 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 5297 | */ |
edamame22 | 0:a9bcda5b678a | 5298 | |
edamame22 | 0:a9bcda5b678a | 5299 | var global = (function() { return this; })(); |
edamame22 | 0:a9bcda5b678a | 5300 | |
edamame22 | 0:a9bcda5b678a | 5301 | /** |
edamame22 | 0:a9bcda5b678a | 5302 | * WebSocket constructor. |
edamame22 | 0:a9bcda5b678a | 5303 | */ |
edamame22 | 0:a9bcda5b678a | 5304 | |
edamame22 | 0:a9bcda5b678a | 5305 | var WebSocket = global.WebSocket || global.MozWebSocket; |
edamame22 | 0:a9bcda5b678a | 5306 | |
edamame22 | 0:a9bcda5b678a | 5307 | /** |
edamame22 | 0:a9bcda5b678a | 5308 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 5309 | */ |
edamame22 | 0:a9bcda5b678a | 5310 | |
edamame22 | 0:a9bcda5b678a | 5311 | module.exports = WebSocket ? ws : null; |
edamame22 | 0:a9bcda5b678a | 5312 | |
edamame22 | 0:a9bcda5b678a | 5313 | /** |
edamame22 | 0:a9bcda5b678a | 5314 | * WebSocket constructor. |
edamame22 | 0:a9bcda5b678a | 5315 | * |
edamame22 | 0:a9bcda5b678a | 5316 | * The third `opts` options object gets ignored in web browsers, since it's |
edamame22 | 0:a9bcda5b678a | 5317 | * non-standard, and throws a TypeError if passed to the constructor. |
edamame22 | 0:a9bcda5b678a | 5318 | * See: https://github.com/einaros/ws/issues/227 |
edamame22 | 0:a9bcda5b678a | 5319 | * |
edamame22 | 0:a9bcda5b678a | 5320 | * @param {String} uri |
edamame22 | 0:a9bcda5b678a | 5321 | * @param {Array} protocols (optional) |
edamame22 | 0:a9bcda5b678a | 5322 | * @param {Object) opts (optional) |
edamame22 | 0:a9bcda5b678a | 5323 | * @api public |
edamame22 | 0:a9bcda5b678a | 5324 | */ |
edamame22 | 0:a9bcda5b678a | 5325 | |
edamame22 | 0:a9bcda5b678a | 5326 | function ws(uri, protocols, opts) { |
edamame22 | 0:a9bcda5b678a | 5327 | var instance; |
edamame22 | 0:a9bcda5b678a | 5328 | if (protocols) { |
edamame22 | 0:a9bcda5b678a | 5329 | instance = new WebSocket(uri, protocols); |
edamame22 | 0:a9bcda5b678a | 5330 | } else { |
edamame22 | 0:a9bcda5b678a | 5331 | instance = new WebSocket(uri); |
edamame22 | 0:a9bcda5b678a | 5332 | } |
edamame22 | 0:a9bcda5b678a | 5333 | return instance; |
edamame22 | 0:a9bcda5b678a | 5334 | } |
edamame22 | 0:a9bcda5b678a | 5335 | |
edamame22 | 0:a9bcda5b678a | 5336 | if (WebSocket) ws.prototype = WebSocket.prototype; |
edamame22 | 0:a9bcda5b678a | 5337 | |
edamame22 | 0:a9bcda5b678a | 5338 | },{}],38:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5339 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 5340 | |
edamame22 | 0:a9bcda5b678a | 5341 | /* |
edamame22 | 0:a9bcda5b678a | 5342 | * Module requirements. |
edamame22 | 0:a9bcda5b678a | 5343 | */ |
edamame22 | 0:a9bcda5b678a | 5344 | |
edamame22 | 0:a9bcda5b678a | 5345 | var isArray = _dereq_('isarray'); |
edamame22 | 0:a9bcda5b678a | 5346 | |
edamame22 | 0:a9bcda5b678a | 5347 | /** |
edamame22 | 0:a9bcda5b678a | 5348 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 5349 | */ |
edamame22 | 0:a9bcda5b678a | 5350 | |
edamame22 | 0:a9bcda5b678a | 5351 | module.exports = hasBinary; |
edamame22 | 0:a9bcda5b678a | 5352 | |
edamame22 | 0:a9bcda5b678a | 5353 | /** |
edamame22 | 0:a9bcda5b678a | 5354 | * Checks for binary data. |
edamame22 | 0:a9bcda5b678a | 5355 | * |
edamame22 | 0:a9bcda5b678a | 5356 | * Right now only Buffer and ArrayBuffer are supported.. |
edamame22 | 0:a9bcda5b678a | 5357 | * |
edamame22 | 0:a9bcda5b678a | 5358 | * @param {Object} anything |
edamame22 | 0:a9bcda5b678a | 5359 | * @api public |
edamame22 | 0:a9bcda5b678a | 5360 | */ |
edamame22 | 0:a9bcda5b678a | 5361 | |
edamame22 | 0:a9bcda5b678a | 5362 | function hasBinary(data) { |
edamame22 | 0:a9bcda5b678a | 5363 | |
edamame22 | 0:a9bcda5b678a | 5364 | function _hasBinary(obj) { |
edamame22 | 0:a9bcda5b678a | 5365 | if (!obj) return false; |
edamame22 | 0:a9bcda5b678a | 5366 | |
edamame22 | 0:a9bcda5b678a | 5367 | if ( (global.Buffer && global.Buffer.isBuffer(obj)) || |
edamame22 | 0:a9bcda5b678a | 5368 | (global.ArrayBuffer && obj instanceof ArrayBuffer) || |
edamame22 | 0:a9bcda5b678a | 5369 | (global.Blob && obj instanceof Blob) || |
edamame22 | 0:a9bcda5b678a | 5370 | (global.File && obj instanceof File) |
edamame22 | 0:a9bcda5b678a | 5371 | ) { |
edamame22 | 0:a9bcda5b678a | 5372 | return true; |
edamame22 | 0:a9bcda5b678a | 5373 | } |
edamame22 | 0:a9bcda5b678a | 5374 | |
edamame22 | 0:a9bcda5b678a | 5375 | if (isArray(obj)) { |
edamame22 | 0:a9bcda5b678a | 5376 | for (var i = 0; i < obj.length; i++) { |
edamame22 | 0:a9bcda5b678a | 5377 | if (_hasBinary(obj[i])) { |
edamame22 | 0:a9bcda5b678a | 5378 | return true; |
edamame22 | 0:a9bcda5b678a | 5379 | } |
edamame22 | 0:a9bcda5b678a | 5380 | } |
edamame22 | 0:a9bcda5b678a | 5381 | } else if (obj && 'object' == typeof obj) { |
edamame22 | 0:a9bcda5b678a | 5382 | if (obj.toJSON) { |
edamame22 | 0:a9bcda5b678a | 5383 | obj = obj.toJSON(); |
edamame22 | 0:a9bcda5b678a | 5384 | } |
edamame22 | 0:a9bcda5b678a | 5385 | |
edamame22 | 0:a9bcda5b678a | 5386 | for (var key in obj) { |
edamame22 | 0:a9bcda5b678a | 5387 | if (Object.prototype.hasOwnProperty.call(obj, key) && _hasBinary(obj[key])) { |
edamame22 | 0:a9bcda5b678a | 5388 | return true; |
edamame22 | 0:a9bcda5b678a | 5389 | } |
edamame22 | 0:a9bcda5b678a | 5390 | } |
edamame22 | 0:a9bcda5b678a | 5391 | } |
edamame22 | 0:a9bcda5b678a | 5392 | |
edamame22 | 0:a9bcda5b678a | 5393 | return false; |
edamame22 | 0:a9bcda5b678a | 5394 | } |
edamame22 | 0:a9bcda5b678a | 5395 | |
edamame22 | 0:a9bcda5b678a | 5396 | return _hasBinary(data); |
edamame22 | 0:a9bcda5b678a | 5397 | } |
edamame22 | 0:a9bcda5b678a | 5398 | |
edamame22 | 0:a9bcda5b678a | 5399 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 5400 | },{"isarray":39}],39:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5401 | module.exports=_dereq_(32) |
edamame22 | 0:a9bcda5b678a | 5402 | },{}],40:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5403 | |
edamame22 | 0:a9bcda5b678a | 5404 | /** |
edamame22 | 0:a9bcda5b678a | 5405 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 5406 | */ |
edamame22 | 0:a9bcda5b678a | 5407 | |
edamame22 | 0:a9bcda5b678a | 5408 | var global = _dereq_('global'); |
edamame22 | 0:a9bcda5b678a | 5409 | |
edamame22 | 0:a9bcda5b678a | 5410 | /** |
edamame22 | 0:a9bcda5b678a | 5411 | * Module exports. |
edamame22 | 0:a9bcda5b678a | 5412 | * |
edamame22 | 0:a9bcda5b678a | 5413 | * Logic borrowed from Modernizr: |
edamame22 | 0:a9bcda5b678a | 5414 | * |
edamame22 | 0:a9bcda5b678a | 5415 | * - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js |
edamame22 | 0:a9bcda5b678a | 5416 | */ |
edamame22 | 0:a9bcda5b678a | 5417 | |
edamame22 | 0:a9bcda5b678a | 5418 | try { |
edamame22 | 0:a9bcda5b678a | 5419 | module.exports = 'XMLHttpRequest' in global && |
edamame22 | 0:a9bcda5b678a | 5420 | 'withCredentials' in new global.XMLHttpRequest(); |
edamame22 | 0:a9bcda5b678a | 5421 | } catch (err) { |
edamame22 | 0:a9bcda5b678a | 5422 | // if XMLHttp support is disabled in IE then it will throw |
edamame22 | 0:a9bcda5b678a | 5423 | // when trying to create |
edamame22 | 0:a9bcda5b678a | 5424 | module.exports = false; |
edamame22 | 0:a9bcda5b678a | 5425 | } |
edamame22 | 0:a9bcda5b678a | 5426 | |
edamame22 | 0:a9bcda5b678a | 5427 | },{"global":41}],41:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5428 | |
edamame22 | 0:a9bcda5b678a | 5429 | /** |
edamame22 | 0:a9bcda5b678a | 5430 | * Returns `this`. Execute this without a "context" (i.e. without it being |
edamame22 | 0:a9bcda5b678a | 5431 | * attached to an object of the left-hand side), and `this` points to the |
edamame22 | 0:a9bcda5b678a | 5432 | * "global" scope of the current JS execution. |
edamame22 | 0:a9bcda5b678a | 5433 | */ |
edamame22 | 0:a9bcda5b678a | 5434 | |
edamame22 | 0:a9bcda5b678a | 5435 | module.exports = (function () { return this; })(); |
edamame22 | 0:a9bcda5b678a | 5436 | |
edamame22 | 0:a9bcda5b678a | 5437 | },{}],42:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5438 | |
edamame22 | 0:a9bcda5b678a | 5439 | var indexOf = [].indexOf; |
edamame22 | 0:a9bcda5b678a | 5440 | |
edamame22 | 0:a9bcda5b678a | 5441 | module.exports = function(arr, obj){ |
edamame22 | 0:a9bcda5b678a | 5442 | if (indexOf) return arr.indexOf(obj); |
edamame22 | 0:a9bcda5b678a | 5443 | for (var i = 0; i < arr.length; ++i) { |
edamame22 | 0:a9bcda5b678a | 5444 | if (arr[i] === obj) return i; |
edamame22 | 0:a9bcda5b678a | 5445 | } |
edamame22 | 0:a9bcda5b678a | 5446 | return -1; |
edamame22 | 0:a9bcda5b678a | 5447 | }; |
edamame22 | 0:a9bcda5b678a | 5448 | },{}],43:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5449 | |
edamame22 | 0:a9bcda5b678a | 5450 | /** |
edamame22 | 0:a9bcda5b678a | 5451 | * HOP ref. |
edamame22 | 0:a9bcda5b678a | 5452 | */ |
edamame22 | 0:a9bcda5b678a | 5453 | |
edamame22 | 0:a9bcda5b678a | 5454 | var has = Object.prototype.hasOwnProperty; |
edamame22 | 0:a9bcda5b678a | 5455 | |
edamame22 | 0:a9bcda5b678a | 5456 | /** |
edamame22 | 0:a9bcda5b678a | 5457 | * Return own keys in `obj`. |
edamame22 | 0:a9bcda5b678a | 5458 | * |
edamame22 | 0:a9bcda5b678a | 5459 | * @param {Object} obj |
edamame22 | 0:a9bcda5b678a | 5460 | * @return {Array} |
edamame22 | 0:a9bcda5b678a | 5461 | * @api public |
edamame22 | 0:a9bcda5b678a | 5462 | */ |
edamame22 | 0:a9bcda5b678a | 5463 | |
edamame22 | 0:a9bcda5b678a | 5464 | exports.keys = Object.keys || function(obj){ |
edamame22 | 0:a9bcda5b678a | 5465 | var keys = []; |
edamame22 | 0:a9bcda5b678a | 5466 | for (var key in obj) { |
edamame22 | 0:a9bcda5b678a | 5467 | if (has.call(obj, key)) { |
edamame22 | 0:a9bcda5b678a | 5468 | keys.push(key); |
edamame22 | 0:a9bcda5b678a | 5469 | } |
edamame22 | 0:a9bcda5b678a | 5470 | } |
edamame22 | 0:a9bcda5b678a | 5471 | return keys; |
edamame22 | 0:a9bcda5b678a | 5472 | }; |
edamame22 | 0:a9bcda5b678a | 5473 | |
edamame22 | 0:a9bcda5b678a | 5474 | /** |
edamame22 | 0:a9bcda5b678a | 5475 | * Return own values in `obj`. |
edamame22 | 0:a9bcda5b678a | 5476 | * |
edamame22 | 0:a9bcda5b678a | 5477 | * @param {Object} obj |
edamame22 | 0:a9bcda5b678a | 5478 | * @return {Array} |
edamame22 | 0:a9bcda5b678a | 5479 | * @api public |
edamame22 | 0:a9bcda5b678a | 5480 | */ |
edamame22 | 0:a9bcda5b678a | 5481 | |
edamame22 | 0:a9bcda5b678a | 5482 | exports.values = function(obj){ |
edamame22 | 0:a9bcda5b678a | 5483 | var vals = []; |
edamame22 | 0:a9bcda5b678a | 5484 | for (var key in obj) { |
edamame22 | 0:a9bcda5b678a | 5485 | if (has.call(obj, key)) { |
edamame22 | 0:a9bcda5b678a | 5486 | vals.push(obj[key]); |
edamame22 | 0:a9bcda5b678a | 5487 | } |
edamame22 | 0:a9bcda5b678a | 5488 | } |
edamame22 | 0:a9bcda5b678a | 5489 | return vals; |
edamame22 | 0:a9bcda5b678a | 5490 | }; |
edamame22 | 0:a9bcda5b678a | 5491 | |
edamame22 | 0:a9bcda5b678a | 5492 | /** |
edamame22 | 0:a9bcda5b678a | 5493 | * Merge `b` into `a`. |
edamame22 | 0:a9bcda5b678a | 5494 | * |
edamame22 | 0:a9bcda5b678a | 5495 | * @param {Object} a |
edamame22 | 0:a9bcda5b678a | 5496 | * @param {Object} b |
edamame22 | 0:a9bcda5b678a | 5497 | * @return {Object} a |
edamame22 | 0:a9bcda5b678a | 5498 | * @api public |
edamame22 | 0:a9bcda5b678a | 5499 | */ |
edamame22 | 0:a9bcda5b678a | 5500 | |
edamame22 | 0:a9bcda5b678a | 5501 | exports.merge = function(a, b){ |
edamame22 | 0:a9bcda5b678a | 5502 | for (var key in b) { |
edamame22 | 0:a9bcda5b678a | 5503 | if (has.call(b, key)) { |
edamame22 | 0:a9bcda5b678a | 5504 | a[key] = b[key]; |
edamame22 | 0:a9bcda5b678a | 5505 | } |
edamame22 | 0:a9bcda5b678a | 5506 | } |
edamame22 | 0:a9bcda5b678a | 5507 | return a; |
edamame22 | 0:a9bcda5b678a | 5508 | }; |
edamame22 | 0:a9bcda5b678a | 5509 | |
edamame22 | 0:a9bcda5b678a | 5510 | /** |
edamame22 | 0:a9bcda5b678a | 5511 | * Return length of `obj`. |
edamame22 | 0:a9bcda5b678a | 5512 | * |
edamame22 | 0:a9bcda5b678a | 5513 | * @param {Object} obj |
edamame22 | 0:a9bcda5b678a | 5514 | * @return {Number} |
edamame22 | 0:a9bcda5b678a | 5515 | * @api public |
edamame22 | 0:a9bcda5b678a | 5516 | */ |
edamame22 | 0:a9bcda5b678a | 5517 | |
edamame22 | 0:a9bcda5b678a | 5518 | exports.length = function(obj){ |
edamame22 | 0:a9bcda5b678a | 5519 | return exports.keys(obj).length; |
edamame22 | 0:a9bcda5b678a | 5520 | }; |
edamame22 | 0:a9bcda5b678a | 5521 | |
edamame22 | 0:a9bcda5b678a | 5522 | /** |
edamame22 | 0:a9bcda5b678a | 5523 | * Check if `obj` is empty. |
edamame22 | 0:a9bcda5b678a | 5524 | * |
edamame22 | 0:a9bcda5b678a | 5525 | * @param {Object} obj |
edamame22 | 0:a9bcda5b678a | 5526 | * @return {Boolean} |
edamame22 | 0:a9bcda5b678a | 5527 | * @api public |
edamame22 | 0:a9bcda5b678a | 5528 | */ |
edamame22 | 0:a9bcda5b678a | 5529 | |
edamame22 | 0:a9bcda5b678a | 5530 | exports.isEmpty = function(obj){ |
edamame22 | 0:a9bcda5b678a | 5531 | return 0 == exports.length(obj); |
edamame22 | 0:a9bcda5b678a | 5532 | }; |
edamame22 | 0:a9bcda5b678a | 5533 | },{}],44:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5534 | /** |
edamame22 | 0:a9bcda5b678a | 5535 | * Parses an URI |
edamame22 | 0:a9bcda5b678a | 5536 | * |
edamame22 | 0:a9bcda5b678a | 5537 | * @author Steven Levithan <stevenlevithan.com> (MIT license) |
edamame22 | 0:a9bcda5b678a | 5538 | * @api private |
edamame22 | 0:a9bcda5b678a | 5539 | */ |
edamame22 | 0:a9bcda5b678a | 5540 | |
edamame22 | 0:a9bcda5b678a | 5541 | var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; |
edamame22 | 0:a9bcda5b678a | 5542 | |
edamame22 | 0:a9bcda5b678a | 5543 | var parts = [ |
edamame22 | 0:a9bcda5b678a | 5544 | 'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host' |
edamame22 | 0:a9bcda5b678a | 5545 | , 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor' |
edamame22 | 0:a9bcda5b678a | 5546 | ]; |
edamame22 | 0:a9bcda5b678a | 5547 | |
edamame22 | 0:a9bcda5b678a | 5548 | module.exports = function parseuri(str) { |
edamame22 | 0:a9bcda5b678a | 5549 | var m = re.exec(str || '') |
edamame22 | 0:a9bcda5b678a | 5550 | , uri = {} |
edamame22 | 0:a9bcda5b678a | 5551 | , i = 14; |
edamame22 | 0:a9bcda5b678a | 5552 | |
edamame22 | 0:a9bcda5b678a | 5553 | while (i--) { |
edamame22 | 0:a9bcda5b678a | 5554 | uri[parts[i]] = m[i] || ''; |
edamame22 | 0:a9bcda5b678a | 5555 | } |
edamame22 | 0:a9bcda5b678a | 5556 | |
edamame22 | 0:a9bcda5b678a | 5557 | return uri; |
edamame22 | 0:a9bcda5b678a | 5558 | }; |
edamame22 | 0:a9bcda5b678a | 5559 | |
edamame22 | 0:a9bcda5b678a | 5560 | },{}],45:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5561 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 5562 | /*global Blob,File*/ |
edamame22 | 0:a9bcda5b678a | 5563 | |
edamame22 | 0:a9bcda5b678a | 5564 | /** |
edamame22 | 0:a9bcda5b678a | 5565 | * Module requirements |
edamame22 | 0:a9bcda5b678a | 5566 | */ |
edamame22 | 0:a9bcda5b678a | 5567 | |
edamame22 | 0:a9bcda5b678a | 5568 | var isArray = _dereq_('isarray'); |
edamame22 | 0:a9bcda5b678a | 5569 | var isBuf = _dereq_('./is-buffer'); |
edamame22 | 0:a9bcda5b678a | 5570 | |
edamame22 | 0:a9bcda5b678a | 5571 | /** |
edamame22 | 0:a9bcda5b678a | 5572 | * Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder. |
edamame22 | 0:a9bcda5b678a | 5573 | * Anything with blobs or files should be fed through removeBlobs before coming |
edamame22 | 0:a9bcda5b678a | 5574 | * here. |
edamame22 | 0:a9bcda5b678a | 5575 | * |
edamame22 | 0:a9bcda5b678a | 5576 | * @param {Object} packet - socket.io event packet |
edamame22 | 0:a9bcda5b678a | 5577 | * @return {Object} with deconstructed packet and list of buffers |
edamame22 | 0:a9bcda5b678a | 5578 | * @api public |
edamame22 | 0:a9bcda5b678a | 5579 | */ |
edamame22 | 0:a9bcda5b678a | 5580 | |
edamame22 | 0:a9bcda5b678a | 5581 | exports.deconstructPacket = function(packet){ |
edamame22 | 0:a9bcda5b678a | 5582 | var buffers = []; |
edamame22 | 0:a9bcda5b678a | 5583 | var packetData = packet.data; |
edamame22 | 0:a9bcda5b678a | 5584 | |
edamame22 | 0:a9bcda5b678a | 5585 | function _deconstructPacket(data) { |
edamame22 | 0:a9bcda5b678a | 5586 | if (!data) return data; |
edamame22 | 0:a9bcda5b678a | 5587 | |
edamame22 | 0:a9bcda5b678a | 5588 | if (isBuf(data)) { |
edamame22 | 0:a9bcda5b678a | 5589 | var placeholder = { _placeholder: true, num: buffers.length }; |
edamame22 | 0:a9bcda5b678a | 5590 | buffers.push(data); |
edamame22 | 0:a9bcda5b678a | 5591 | return placeholder; |
edamame22 | 0:a9bcda5b678a | 5592 | } else if (isArray(data)) { |
edamame22 | 0:a9bcda5b678a | 5593 | var newData = new Array(data.length); |
edamame22 | 0:a9bcda5b678a | 5594 | for (var i = 0; i < data.length; i++) { |
edamame22 | 0:a9bcda5b678a | 5595 | newData[i] = _deconstructPacket(data[i]); |
edamame22 | 0:a9bcda5b678a | 5596 | } |
edamame22 | 0:a9bcda5b678a | 5597 | return newData; |
edamame22 | 0:a9bcda5b678a | 5598 | } else if ('object' == typeof data && !(data instanceof Date)) { |
edamame22 | 0:a9bcda5b678a | 5599 | var newData = {}; |
edamame22 | 0:a9bcda5b678a | 5600 | for (var key in data) { |
edamame22 | 0:a9bcda5b678a | 5601 | newData[key] = _deconstructPacket(data[key]); |
edamame22 | 0:a9bcda5b678a | 5602 | } |
edamame22 | 0:a9bcda5b678a | 5603 | return newData; |
edamame22 | 0:a9bcda5b678a | 5604 | } |
edamame22 | 0:a9bcda5b678a | 5605 | return data; |
edamame22 | 0:a9bcda5b678a | 5606 | } |
edamame22 | 0:a9bcda5b678a | 5607 | |
edamame22 | 0:a9bcda5b678a | 5608 | var pack = packet; |
edamame22 | 0:a9bcda5b678a | 5609 | pack.data = _deconstructPacket(packetData); |
edamame22 | 0:a9bcda5b678a | 5610 | pack.attachments = buffers.length; // number of binary 'attachments' |
edamame22 | 0:a9bcda5b678a | 5611 | return {packet: pack, buffers: buffers}; |
edamame22 | 0:a9bcda5b678a | 5612 | }; |
edamame22 | 0:a9bcda5b678a | 5613 | |
edamame22 | 0:a9bcda5b678a | 5614 | /** |
edamame22 | 0:a9bcda5b678a | 5615 | * Reconstructs a binary packet from its placeholder packet and buffers |
edamame22 | 0:a9bcda5b678a | 5616 | * |
edamame22 | 0:a9bcda5b678a | 5617 | * @param {Object} packet - event packet with placeholders |
edamame22 | 0:a9bcda5b678a | 5618 | * @param {Array} buffers - binary buffers to put in placeholder positions |
edamame22 | 0:a9bcda5b678a | 5619 | * @return {Object} reconstructed packet |
edamame22 | 0:a9bcda5b678a | 5620 | * @api public |
edamame22 | 0:a9bcda5b678a | 5621 | */ |
edamame22 | 0:a9bcda5b678a | 5622 | |
edamame22 | 0:a9bcda5b678a | 5623 | exports.reconstructPacket = function(packet, buffers) { |
edamame22 | 0:a9bcda5b678a | 5624 | var curPlaceHolder = 0; |
edamame22 | 0:a9bcda5b678a | 5625 | |
edamame22 | 0:a9bcda5b678a | 5626 | function _reconstructPacket(data) { |
edamame22 | 0:a9bcda5b678a | 5627 | if (data && data._placeholder) { |
edamame22 | 0:a9bcda5b678a | 5628 | var buf = buffers[data.num]; // appropriate buffer (should be natural order anyway) |
edamame22 | 0:a9bcda5b678a | 5629 | return buf; |
edamame22 | 0:a9bcda5b678a | 5630 | } else if (isArray(data)) { |
edamame22 | 0:a9bcda5b678a | 5631 | for (var i = 0; i < data.length; i++) { |
edamame22 | 0:a9bcda5b678a | 5632 | data[i] = _reconstructPacket(data[i]); |
edamame22 | 0:a9bcda5b678a | 5633 | } |
edamame22 | 0:a9bcda5b678a | 5634 | return data; |
edamame22 | 0:a9bcda5b678a | 5635 | } else if (data && 'object' == typeof data) { |
edamame22 | 0:a9bcda5b678a | 5636 | for (var key in data) { |
edamame22 | 0:a9bcda5b678a | 5637 | data[key] = _reconstructPacket(data[key]); |
edamame22 | 0:a9bcda5b678a | 5638 | } |
edamame22 | 0:a9bcda5b678a | 5639 | return data; |
edamame22 | 0:a9bcda5b678a | 5640 | } |
edamame22 | 0:a9bcda5b678a | 5641 | return data; |
edamame22 | 0:a9bcda5b678a | 5642 | } |
edamame22 | 0:a9bcda5b678a | 5643 | |
edamame22 | 0:a9bcda5b678a | 5644 | packet.data = _reconstructPacket(packet.data); |
edamame22 | 0:a9bcda5b678a | 5645 | packet.attachments = undefined; // no longer useful |
edamame22 | 0:a9bcda5b678a | 5646 | return packet; |
edamame22 | 0:a9bcda5b678a | 5647 | }; |
edamame22 | 0:a9bcda5b678a | 5648 | |
edamame22 | 0:a9bcda5b678a | 5649 | /** |
edamame22 | 0:a9bcda5b678a | 5650 | * Asynchronously removes Blobs or Files from data via |
edamame22 | 0:a9bcda5b678a | 5651 | * FileReader's readAsArrayBuffer method. Used before encoding |
edamame22 | 0:a9bcda5b678a | 5652 | * data as msgpack. Calls callback with the blobless data. |
edamame22 | 0:a9bcda5b678a | 5653 | * |
edamame22 | 0:a9bcda5b678a | 5654 | * @param {Object} data |
edamame22 | 0:a9bcda5b678a | 5655 | * @param {Function} callback |
edamame22 | 0:a9bcda5b678a | 5656 | * @api private |
edamame22 | 0:a9bcda5b678a | 5657 | */ |
edamame22 | 0:a9bcda5b678a | 5658 | |
edamame22 | 0:a9bcda5b678a | 5659 | exports.removeBlobs = function(data, callback) { |
edamame22 | 0:a9bcda5b678a | 5660 | function _removeBlobs(obj, curKey, containingObject) { |
edamame22 | 0:a9bcda5b678a | 5661 | if (!obj) return obj; |
edamame22 | 0:a9bcda5b678a | 5662 | |
edamame22 | 0:a9bcda5b678a | 5663 | // convert any blob |
edamame22 | 0:a9bcda5b678a | 5664 | if ((global.Blob && obj instanceof Blob) || |
edamame22 | 0:a9bcda5b678a | 5665 | (global.File && obj instanceof File)) { |
edamame22 | 0:a9bcda5b678a | 5666 | pendingBlobs++; |
edamame22 | 0:a9bcda5b678a | 5667 | |
edamame22 | 0:a9bcda5b678a | 5668 | // async filereader |
edamame22 | 0:a9bcda5b678a | 5669 | var fileReader = new FileReader(); |
edamame22 | 0:a9bcda5b678a | 5670 | fileReader.onload = function() { // this.result == arraybuffer |
edamame22 | 0:a9bcda5b678a | 5671 | if (containingObject) { |
edamame22 | 0:a9bcda5b678a | 5672 | containingObject[curKey] = this.result; |
edamame22 | 0:a9bcda5b678a | 5673 | } |
edamame22 | 0:a9bcda5b678a | 5674 | else { |
edamame22 | 0:a9bcda5b678a | 5675 | bloblessData = this.result; |
edamame22 | 0:a9bcda5b678a | 5676 | } |
edamame22 | 0:a9bcda5b678a | 5677 | |
edamame22 | 0:a9bcda5b678a | 5678 | // if nothing pending its callback time |
edamame22 | 0:a9bcda5b678a | 5679 | if(! --pendingBlobs) { |
edamame22 | 0:a9bcda5b678a | 5680 | callback(bloblessData); |
edamame22 | 0:a9bcda5b678a | 5681 | } |
edamame22 | 0:a9bcda5b678a | 5682 | }; |
edamame22 | 0:a9bcda5b678a | 5683 | |
edamame22 | 0:a9bcda5b678a | 5684 | fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer |
edamame22 | 0:a9bcda5b678a | 5685 | } else if (isArray(obj)) { // handle array |
edamame22 | 0:a9bcda5b678a | 5686 | for (var i = 0; i < obj.length; i++) { |
edamame22 | 0:a9bcda5b678a | 5687 | _removeBlobs(obj[i], i, obj); |
edamame22 | 0:a9bcda5b678a | 5688 | } |
edamame22 | 0:a9bcda5b678a | 5689 | } else if (obj && 'object' == typeof obj && !isBuf(obj)) { // and object |
edamame22 | 0:a9bcda5b678a | 5690 | for (var key in obj) { |
edamame22 | 0:a9bcda5b678a | 5691 | _removeBlobs(obj[key], key, obj); |
edamame22 | 0:a9bcda5b678a | 5692 | } |
edamame22 | 0:a9bcda5b678a | 5693 | } |
edamame22 | 0:a9bcda5b678a | 5694 | } |
edamame22 | 0:a9bcda5b678a | 5695 | |
edamame22 | 0:a9bcda5b678a | 5696 | var pendingBlobs = 0; |
edamame22 | 0:a9bcda5b678a | 5697 | var bloblessData = data; |
edamame22 | 0:a9bcda5b678a | 5698 | _removeBlobs(bloblessData); |
edamame22 | 0:a9bcda5b678a | 5699 | if (!pendingBlobs) { |
edamame22 | 0:a9bcda5b678a | 5700 | callback(bloblessData); |
edamame22 | 0:a9bcda5b678a | 5701 | } |
edamame22 | 0:a9bcda5b678a | 5702 | }; |
edamame22 | 0:a9bcda5b678a | 5703 | |
edamame22 | 0:a9bcda5b678a | 5704 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 5705 | },{"./is-buffer":47,"isarray":48}],46:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 5706 | |
edamame22 | 0:a9bcda5b678a | 5707 | /** |
edamame22 | 0:a9bcda5b678a | 5708 | * Module dependencies. |
edamame22 | 0:a9bcda5b678a | 5709 | */ |
edamame22 | 0:a9bcda5b678a | 5710 | |
edamame22 | 0:a9bcda5b678a | 5711 | var debug = _dereq_('debug')('socket.io-parser'); |
edamame22 | 0:a9bcda5b678a | 5712 | var json = _dereq_('json3'); |
edamame22 | 0:a9bcda5b678a | 5713 | var isArray = _dereq_('isarray'); |
edamame22 | 0:a9bcda5b678a | 5714 | var Emitter = _dereq_('component-emitter'); |
edamame22 | 0:a9bcda5b678a | 5715 | var binary = _dereq_('./binary'); |
edamame22 | 0:a9bcda5b678a | 5716 | var isBuf = _dereq_('./is-buffer'); |
edamame22 | 0:a9bcda5b678a | 5717 | |
edamame22 | 0:a9bcda5b678a | 5718 | /** |
edamame22 | 0:a9bcda5b678a | 5719 | * Protocol version. |
edamame22 | 0:a9bcda5b678a | 5720 | * |
edamame22 | 0:a9bcda5b678a | 5721 | * @api public |
edamame22 | 0:a9bcda5b678a | 5722 | */ |
edamame22 | 0:a9bcda5b678a | 5723 | |
edamame22 | 0:a9bcda5b678a | 5724 | exports.protocol = 4; |
edamame22 | 0:a9bcda5b678a | 5725 | |
edamame22 | 0:a9bcda5b678a | 5726 | /** |
edamame22 | 0:a9bcda5b678a | 5727 | * Packet types. |
edamame22 | 0:a9bcda5b678a | 5728 | * |
edamame22 | 0:a9bcda5b678a | 5729 | * @api public |
edamame22 | 0:a9bcda5b678a | 5730 | */ |
edamame22 | 0:a9bcda5b678a | 5731 | |
edamame22 | 0:a9bcda5b678a | 5732 | exports.types = [ |
edamame22 | 0:a9bcda5b678a | 5733 | 'CONNECT', |
edamame22 | 0:a9bcda5b678a | 5734 | 'DISCONNECT', |
edamame22 | 0:a9bcda5b678a | 5735 | 'EVENT', |
edamame22 | 0:a9bcda5b678a | 5736 | 'BINARY_EVENT', |
edamame22 | 0:a9bcda5b678a | 5737 | 'ACK', |
edamame22 | 0:a9bcda5b678a | 5738 | 'BINARY_ACK', |
edamame22 | 0:a9bcda5b678a | 5739 | 'ERROR' |
edamame22 | 0:a9bcda5b678a | 5740 | ]; |
edamame22 | 0:a9bcda5b678a | 5741 | |
edamame22 | 0:a9bcda5b678a | 5742 | /** |
edamame22 | 0:a9bcda5b678a | 5743 | * Packet type `connect`. |
edamame22 | 0:a9bcda5b678a | 5744 | * |
edamame22 | 0:a9bcda5b678a | 5745 | * @api public |
edamame22 | 0:a9bcda5b678a | 5746 | */ |
edamame22 | 0:a9bcda5b678a | 5747 | |
edamame22 | 0:a9bcda5b678a | 5748 | exports.CONNECT = 0; |
edamame22 | 0:a9bcda5b678a | 5749 | |
edamame22 | 0:a9bcda5b678a | 5750 | /** |
edamame22 | 0:a9bcda5b678a | 5751 | * Packet type `disconnect`. |
edamame22 | 0:a9bcda5b678a | 5752 | * |
edamame22 | 0:a9bcda5b678a | 5753 | * @api public |
edamame22 | 0:a9bcda5b678a | 5754 | */ |
edamame22 | 0:a9bcda5b678a | 5755 | |
edamame22 | 0:a9bcda5b678a | 5756 | exports.DISCONNECT = 1; |
edamame22 | 0:a9bcda5b678a | 5757 | |
edamame22 | 0:a9bcda5b678a | 5758 | /** |
edamame22 | 0:a9bcda5b678a | 5759 | * Packet type `event`. |
edamame22 | 0:a9bcda5b678a | 5760 | * |
edamame22 | 0:a9bcda5b678a | 5761 | * @api public |
edamame22 | 0:a9bcda5b678a | 5762 | */ |
edamame22 | 0:a9bcda5b678a | 5763 | |
edamame22 | 0:a9bcda5b678a | 5764 | exports.EVENT = 2; |
edamame22 | 0:a9bcda5b678a | 5765 | |
edamame22 | 0:a9bcda5b678a | 5766 | /** |
edamame22 | 0:a9bcda5b678a | 5767 | * Packet type `ack`. |
edamame22 | 0:a9bcda5b678a | 5768 | * |
edamame22 | 0:a9bcda5b678a | 5769 | * @api public |
edamame22 | 0:a9bcda5b678a | 5770 | */ |
edamame22 | 0:a9bcda5b678a | 5771 | |
edamame22 | 0:a9bcda5b678a | 5772 | exports.ACK = 3; |
edamame22 | 0:a9bcda5b678a | 5773 | |
edamame22 | 0:a9bcda5b678a | 5774 | /** |
edamame22 | 0:a9bcda5b678a | 5775 | * Packet type `error`. |
edamame22 | 0:a9bcda5b678a | 5776 | * |
edamame22 | 0:a9bcda5b678a | 5777 | * @api public |
edamame22 | 0:a9bcda5b678a | 5778 | */ |
edamame22 | 0:a9bcda5b678a | 5779 | |
edamame22 | 0:a9bcda5b678a | 5780 | exports.ERROR = 4; |
edamame22 | 0:a9bcda5b678a | 5781 | |
edamame22 | 0:a9bcda5b678a | 5782 | /** |
edamame22 | 0:a9bcda5b678a | 5783 | * Packet type 'binary event' |
edamame22 | 0:a9bcda5b678a | 5784 | * |
edamame22 | 0:a9bcda5b678a | 5785 | * @api public |
edamame22 | 0:a9bcda5b678a | 5786 | */ |
edamame22 | 0:a9bcda5b678a | 5787 | |
edamame22 | 0:a9bcda5b678a | 5788 | exports.BINARY_EVENT = 5; |
edamame22 | 0:a9bcda5b678a | 5789 | |
edamame22 | 0:a9bcda5b678a | 5790 | /** |
edamame22 | 0:a9bcda5b678a | 5791 | * Packet type `binary ack`. For acks with binary arguments. |
edamame22 | 0:a9bcda5b678a | 5792 | * |
edamame22 | 0:a9bcda5b678a | 5793 | * @api public |
edamame22 | 0:a9bcda5b678a | 5794 | */ |
edamame22 | 0:a9bcda5b678a | 5795 | |
edamame22 | 0:a9bcda5b678a | 5796 | exports.BINARY_ACK = 6; |
edamame22 | 0:a9bcda5b678a | 5797 | |
edamame22 | 0:a9bcda5b678a | 5798 | /** |
edamame22 | 0:a9bcda5b678a | 5799 | * Encoder constructor. |
edamame22 | 0:a9bcda5b678a | 5800 | * |
edamame22 | 0:a9bcda5b678a | 5801 | * @api public |
edamame22 | 0:a9bcda5b678a | 5802 | */ |
edamame22 | 0:a9bcda5b678a | 5803 | |
edamame22 | 0:a9bcda5b678a | 5804 | exports.Encoder = Encoder; |
edamame22 | 0:a9bcda5b678a | 5805 | |
edamame22 | 0:a9bcda5b678a | 5806 | /** |
edamame22 | 0:a9bcda5b678a | 5807 | * Decoder constructor. |
edamame22 | 0:a9bcda5b678a | 5808 | * |
edamame22 | 0:a9bcda5b678a | 5809 | * @api public |
edamame22 | 0:a9bcda5b678a | 5810 | */ |
edamame22 | 0:a9bcda5b678a | 5811 | |
edamame22 | 0:a9bcda5b678a | 5812 | exports.Decoder = Decoder; |
edamame22 | 0:a9bcda5b678a | 5813 | |
edamame22 | 0:a9bcda5b678a | 5814 | /** |
edamame22 | 0:a9bcda5b678a | 5815 | * A socket.io Encoder instance |
edamame22 | 0:a9bcda5b678a | 5816 | * |
edamame22 | 0:a9bcda5b678a | 5817 | * @api public |
edamame22 | 0:a9bcda5b678a | 5818 | */ |
edamame22 | 0:a9bcda5b678a | 5819 | |
edamame22 | 0:a9bcda5b678a | 5820 | function Encoder() {} |
edamame22 | 0:a9bcda5b678a | 5821 | |
edamame22 | 0:a9bcda5b678a | 5822 | /** |
edamame22 | 0:a9bcda5b678a | 5823 | * Encode a packet as a single string if non-binary, or as a |
edamame22 | 0:a9bcda5b678a | 5824 | * buffer sequence, depending on packet type. |
edamame22 | 0:a9bcda5b678a | 5825 | * |
edamame22 | 0:a9bcda5b678a | 5826 | * @param {Object} obj - packet object |
edamame22 | 0:a9bcda5b678a | 5827 | * @param {Function} callback - function to handle encodings (likely engine.write) |
edamame22 | 0:a9bcda5b678a | 5828 | * @return Calls callback with Array of encodings |
edamame22 | 0:a9bcda5b678a | 5829 | * @api public |
edamame22 | 0:a9bcda5b678a | 5830 | */ |
edamame22 | 0:a9bcda5b678a | 5831 | |
edamame22 | 0:a9bcda5b678a | 5832 | Encoder.prototype.encode = function(obj, callback){ |
edamame22 | 0:a9bcda5b678a | 5833 | debug('encoding packet %j', obj); |
edamame22 | 0:a9bcda5b678a | 5834 | |
edamame22 | 0:a9bcda5b678a | 5835 | if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) { |
edamame22 | 0:a9bcda5b678a | 5836 | encodeAsBinary(obj, callback); |
edamame22 | 0:a9bcda5b678a | 5837 | } |
edamame22 | 0:a9bcda5b678a | 5838 | else { |
edamame22 | 0:a9bcda5b678a | 5839 | var encoding = encodeAsString(obj); |
edamame22 | 0:a9bcda5b678a | 5840 | callback([encoding]); |
edamame22 | 0:a9bcda5b678a | 5841 | } |
edamame22 | 0:a9bcda5b678a | 5842 | }; |
edamame22 | 0:a9bcda5b678a | 5843 | |
edamame22 | 0:a9bcda5b678a | 5844 | /** |
edamame22 | 0:a9bcda5b678a | 5845 | * Encode packet as string. |
edamame22 | 0:a9bcda5b678a | 5846 | * |
edamame22 | 0:a9bcda5b678a | 5847 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 5848 | * @return {String} encoded |
edamame22 | 0:a9bcda5b678a | 5849 | * @api private |
edamame22 | 0:a9bcda5b678a | 5850 | */ |
edamame22 | 0:a9bcda5b678a | 5851 | |
edamame22 | 0:a9bcda5b678a | 5852 | function encodeAsString(obj) { |
edamame22 | 0:a9bcda5b678a | 5853 | var str = ''; |
edamame22 | 0:a9bcda5b678a | 5854 | var nsp = false; |
edamame22 | 0:a9bcda5b678a | 5855 | |
edamame22 | 0:a9bcda5b678a | 5856 | // first is type |
edamame22 | 0:a9bcda5b678a | 5857 | str += obj.type; |
edamame22 | 0:a9bcda5b678a | 5858 | |
edamame22 | 0:a9bcda5b678a | 5859 | // attachments if we have them |
edamame22 | 0:a9bcda5b678a | 5860 | if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) { |
edamame22 | 0:a9bcda5b678a | 5861 | str += obj.attachments; |
edamame22 | 0:a9bcda5b678a | 5862 | str += '-'; |
edamame22 | 0:a9bcda5b678a | 5863 | } |
edamame22 | 0:a9bcda5b678a | 5864 | |
edamame22 | 0:a9bcda5b678a | 5865 | // if we have a namespace other than `/` |
edamame22 | 0:a9bcda5b678a | 5866 | // we append it followed by a comma `,` |
edamame22 | 0:a9bcda5b678a | 5867 | if (obj.nsp && '/' != obj.nsp) { |
edamame22 | 0:a9bcda5b678a | 5868 | nsp = true; |
edamame22 | 0:a9bcda5b678a | 5869 | str += obj.nsp; |
edamame22 | 0:a9bcda5b678a | 5870 | } |
edamame22 | 0:a9bcda5b678a | 5871 | |
edamame22 | 0:a9bcda5b678a | 5872 | // immediately followed by the id |
edamame22 | 0:a9bcda5b678a | 5873 | if (null != obj.id) { |
edamame22 | 0:a9bcda5b678a | 5874 | if (nsp) { |
edamame22 | 0:a9bcda5b678a | 5875 | str += ','; |
edamame22 | 0:a9bcda5b678a | 5876 | nsp = false; |
edamame22 | 0:a9bcda5b678a | 5877 | } |
edamame22 | 0:a9bcda5b678a | 5878 | str += obj.id; |
edamame22 | 0:a9bcda5b678a | 5879 | } |
edamame22 | 0:a9bcda5b678a | 5880 | |
edamame22 | 0:a9bcda5b678a | 5881 | // json data |
edamame22 | 0:a9bcda5b678a | 5882 | if (null != obj.data) { |
edamame22 | 0:a9bcda5b678a | 5883 | if (nsp) str += ','; |
edamame22 | 0:a9bcda5b678a | 5884 | str += json.stringify(obj.data); |
edamame22 | 0:a9bcda5b678a | 5885 | } |
edamame22 | 0:a9bcda5b678a | 5886 | |
edamame22 | 0:a9bcda5b678a | 5887 | debug('encoded %j as %s', obj, str); |
edamame22 | 0:a9bcda5b678a | 5888 | return str; |
edamame22 | 0:a9bcda5b678a | 5889 | } |
edamame22 | 0:a9bcda5b678a | 5890 | |
edamame22 | 0:a9bcda5b678a | 5891 | /** |
edamame22 | 0:a9bcda5b678a | 5892 | * Encode packet as 'buffer sequence' by removing blobs, and |
edamame22 | 0:a9bcda5b678a | 5893 | * deconstructing packet into object with placeholders and |
edamame22 | 0:a9bcda5b678a | 5894 | * a list of buffers. |
edamame22 | 0:a9bcda5b678a | 5895 | * |
edamame22 | 0:a9bcda5b678a | 5896 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 5897 | * @return {Buffer} encoded |
edamame22 | 0:a9bcda5b678a | 5898 | * @api private |
edamame22 | 0:a9bcda5b678a | 5899 | */ |
edamame22 | 0:a9bcda5b678a | 5900 | |
edamame22 | 0:a9bcda5b678a | 5901 | function encodeAsBinary(obj, callback) { |
edamame22 | 0:a9bcda5b678a | 5902 | |
edamame22 | 0:a9bcda5b678a | 5903 | function writeEncoding(bloblessData) { |
edamame22 | 0:a9bcda5b678a | 5904 | var deconstruction = binary.deconstructPacket(bloblessData); |
edamame22 | 0:a9bcda5b678a | 5905 | var pack = encodeAsString(deconstruction.packet); |
edamame22 | 0:a9bcda5b678a | 5906 | var buffers = deconstruction.buffers; |
edamame22 | 0:a9bcda5b678a | 5907 | |
edamame22 | 0:a9bcda5b678a | 5908 | buffers.unshift(pack); // add packet info to beginning of data list |
edamame22 | 0:a9bcda5b678a | 5909 | callback(buffers); // write all the buffers |
edamame22 | 0:a9bcda5b678a | 5910 | } |
edamame22 | 0:a9bcda5b678a | 5911 | |
edamame22 | 0:a9bcda5b678a | 5912 | binary.removeBlobs(obj, writeEncoding); |
edamame22 | 0:a9bcda5b678a | 5913 | } |
edamame22 | 0:a9bcda5b678a | 5914 | |
edamame22 | 0:a9bcda5b678a | 5915 | /** |
edamame22 | 0:a9bcda5b678a | 5916 | * A socket.io Decoder instance |
edamame22 | 0:a9bcda5b678a | 5917 | * |
edamame22 | 0:a9bcda5b678a | 5918 | * @return {Object} decoder |
edamame22 | 0:a9bcda5b678a | 5919 | * @api public |
edamame22 | 0:a9bcda5b678a | 5920 | */ |
edamame22 | 0:a9bcda5b678a | 5921 | |
edamame22 | 0:a9bcda5b678a | 5922 | function Decoder() { |
edamame22 | 0:a9bcda5b678a | 5923 | this.reconstructor = null; |
edamame22 | 0:a9bcda5b678a | 5924 | } |
edamame22 | 0:a9bcda5b678a | 5925 | |
edamame22 | 0:a9bcda5b678a | 5926 | /** |
edamame22 | 0:a9bcda5b678a | 5927 | * Mix in `Emitter` with Decoder. |
edamame22 | 0:a9bcda5b678a | 5928 | */ |
edamame22 | 0:a9bcda5b678a | 5929 | |
edamame22 | 0:a9bcda5b678a | 5930 | Emitter(Decoder.prototype); |
edamame22 | 0:a9bcda5b678a | 5931 | |
edamame22 | 0:a9bcda5b678a | 5932 | /** |
edamame22 | 0:a9bcda5b678a | 5933 | * Decodes an ecoded packet string into packet JSON. |
edamame22 | 0:a9bcda5b678a | 5934 | * |
edamame22 | 0:a9bcda5b678a | 5935 | * @param {String} obj - encoded packet |
edamame22 | 0:a9bcda5b678a | 5936 | * @return {Object} packet |
edamame22 | 0:a9bcda5b678a | 5937 | * @api public |
edamame22 | 0:a9bcda5b678a | 5938 | */ |
edamame22 | 0:a9bcda5b678a | 5939 | |
edamame22 | 0:a9bcda5b678a | 5940 | Decoder.prototype.add = function(obj) { |
edamame22 | 0:a9bcda5b678a | 5941 | var packet; |
edamame22 | 0:a9bcda5b678a | 5942 | if ('string' == typeof obj) { |
edamame22 | 0:a9bcda5b678a | 5943 | packet = decodeString(obj); |
edamame22 | 0:a9bcda5b678a | 5944 | if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json |
edamame22 | 0:a9bcda5b678a | 5945 | this.reconstructor = new BinaryReconstructor(packet); |
edamame22 | 0:a9bcda5b678a | 5946 | |
edamame22 | 0:a9bcda5b678a | 5947 | // no attachments, labeled binary but no binary data to follow |
edamame22 | 0:a9bcda5b678a | 5948 | if (this.reconstructor.reconPack.attachments === 0) { |
edamame22 | 0:a9bcda5b678a | 5949 | this.emit('decoded', packet); |
edamame22 | 0:a9bcda5b678a | 5950 | } |
edamame22 | 0:a9bcda5b678a | 5951 | } else { // non-binary full packet |
edamame22 | 0:a9bcda5b678a | 5952 | this.emit('decoded', packet); |
edamame22 | 0:a9bcda5b678a | 5953 | } |
edamame22 | 0:a9bcda5b678a | 5954 | } |
edamame22 | 0:a9bcda5b678a | 5955 | else if (isBuf(obj) || obj.base64) { // raw binary data |
edamame22 | 0:a9bcda5b678a | 5956 | if (!this.reconstructor) { |
edamame22 | 0:a9bcda5b678a | 5957 | throw new Error('got binary data when not reconstructing a packet'); |
edamame22 | 0:a9bcda5b678a | 5958 | } else { |
edamame22 | 0:a9bcda5b678a | 5959 | packet = this.reconstructor.takeBinaryData(obj); |
edamame22 | 0:a9bcda5b678a | 5960 | if (packet) { // received final buffer |
edamame22 | 0:a9bcda5b678a | 5961 | this.reconstructor = null; |
edamame22 | 0:a9bcda5b678a | 5962 | this.emit('decoded', packet); |
edamame22 | 0:a9bcda5b678a | 5963 | } |
edamame22 | 0:a9bcda5b678a | 5964 | } |
edamame22 | 0:a9bcda5b678a | 5965 | } |
edamame22 | 0:a9bcda5b678a | 5966 | else { |
edamame22 | 0:a9bcda5b678a | 5967 | throw new Error('Unknown type: ' + obj); |
edamame22 | 0:a9bcda5b678a | 5968 | } |
edamame22 | 0:a9bcda5b678a | 5969 | }; |
edamame22 | 0:a9bcda5b678a | 5970 | |
edamame22 | 0:a9bcda5b678a | 5971 | /** |
edamame22 | 0:a9bcda5b678a | 5972 | * Decode a packet String (JSON data) |
edamame22 | 0:a9bcda5b678a | 5973 | * |
edamame22 | 0:a9bcda5b678a | 5974 | * @param {String} str |
edamame22 | 0:a9bcda5b678a | 5975 | * @return {Object} packet |
edamame22 | 0:a9bcda5b678a | 5976 | * @api private |
edamame22 | 0:a9bcda5b678a | 5977 | */ |
edamame22 | 0:a9bcda5b678a | 5978 | |
edamame22 | 0:a9bcda5b678a | 5979 | function decodeString(str) { |
edamame22 | 0:a9bcda5b678a | 5980 | var p = {}; |
edamame22 | 0:a9bcda5b678a | 5981 | var i = 0; |
edamame22 | 0:a9bcda5b678a | 5982 | |
edamame22 | 0:a9bcda5b678a | 5983 | // look up type |
edamame22 | 0:a9bcda5b678a | 5984 | p.type = Number(str.charAt(0)); |
edamame22 | 0:a9bcda5b678a | 5985 | if (null == exports.types[p.type]) return error(); |
edamame22 | 0:a9bcda5b678a | 5986 | |
edamame22 | 0:a9bcda5b678a | 5987 | // look up attachments if type binary |
edamame22 | 0:a9bcda5b678a | 5988 | if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) { |
edamame22 | 0:a9bcda5b678a | 5989 | var buf = ''; |
edamame22 | 0:a9bcda5b678a | 5990 | while (str.charAt(++i) != '-') { |
edamame22 | 0:a9bcda5b678a | 5991 | buf += str.charAt(i); |
edamame22 | 0:a9bcda5b678a | 5992 | if (i == str.length) break; |
edamame22 | 0:a9bcda5b678a | 5993 | } |
edamame22 | 0:a9bcda5b678a | 5994 | if (buf != Number(buf) || str.charAt(i) != '-') { |
edamame22 | 0:a9bcda5b678a | 5995 | throw new Error('Illegal attachments'); |
edamame22 | 0:a9bcda5b678a | 5996 | } |
edamame22 | 0:a9bcda5b678a | 5997 | p.attachments = Number(buf); |
edamame22 | 0:a9bcda5b678a | 5998 | } |
edamame22 | 0:a9bcda5b678a | 5999 | |
edamame22 | 0:a9bcda5b678a | 6000 | // look up namespace (if any) |
edamame22 | 0:a9bcda5b678a | 6001 | if ('/' == str.charAt(i + 1)) { |
edamame22 | 0:a9bcda5b678a | 6002 | p.nsp = ''; |
edamame22 | 0:a9bcda5b678a | 6003 | while (++i) { |
edamame22 | 0:a9bcda5b678a | 6004 | var c = str.charAt(i); |
edamame22 | 0:a9bcda5b678a | 6005 | if (',' == c) break; |
edamame22 | 0:a9bcda5b678a | 6006 | p.nsp += c; |
edamame22 | 0:a9bcda5b678a | 6007 | if (i == str.length) break; |
edamame22 | 0:a9bcda5b678a | 6008 | } |
edamame22 | 0:a9bcda5b678a | 6009 | } else { |
edamame22 | 0:a9bcda5b678a | 6010 | p.nsp = '/'; |
edamame22 | 0:a9bcda5b678a | 6011 | } |
edamame22 | 0:a9bcda5b678a | 6012 | |
edamame22 | 0:a9bcda5b678a | 6013 | // look up id |
edamame22 | 0:a9bcda5b678a | 6014 | var next = str.charAt(i + 1); |
edamame22 | 0:a9bcda5b678a | 6015 | if ('' !== next && Number(next) == next) { |
edamame22 | 0:a9bcda5b678a | 6016 | p.id = ''; |
edamame22 | 0:a9bcda5b678a | 6017 | while (++i) { |
edamame22 | 0:a9bcda5b678a | 6018 | var c = str.charAt(i); |
edamame22 | 0:a9bcda5b678a | 6019 | if (null == c || Number(c) != c) { |
edamame22 | 0:a9bcda5b678a | 6020 | --i; |
edamame22 | 0:a9bcda5b678a | 6021 | break; |
edamame22 | 0:a9bcda5b678a | 6022 | } |
edamame22 | 0:a9bcda5b678a | 6023 | p.id += str.charAt(i); |
edamame22 | 0:a9bcda5b678a | 6024 | if (i == str.length) break; |
edamame22 | 0:a9bcda5b678a | 6025 | } |
edamame22 | 0:a9bcda5b678a | 6026 | p.id = Number(p.id); |
edamame22 | 0:a9bcda5b678a | 6027 | } |
edamame22 | 0:a9bcda5b678a | 6028 | |
edamame22 | 0:a9bcda5b678a | 6029 | // look up json data |
edamame22 | 0:a9bcda5b678a | 6030 | if (str.charAt(++i)) { |
edamame22 | 0:a9bcda5b678a | 6031 | try { |
edamame22 | 0:a9bcda5b678a | 6032 | p.data = json.parse(str.substr(i)); |
edamame22 | 0:a9bcda5b678a | 6033 | } catch(e){ |
edamame22 | 0:a9bcda5b678a | 6034 | return error(); |
edamame22 | 0:a9bcda5b678a | 6035 | } |
edamame22 | 0:a9bcda5b678a | 6036 | } |
edamame22 | 0:a9bcda5b678a | 6037 | |
edamame22 | 0:a9bcda5b678a | 6038 | debug('decoded %s as %j', str, p); |
edamame22 | 0:a9bcda5b678a | 6039 | return p; |
edamame22 | 0:a9bcda5b678a | 6040 | } |
edamame22 | 0:a9bcda5b678a | 6041 | |
edamame22 | 0:a9bcda5b678a | 6042 | /** |
edamame22 | 0:a9bcda5b678a | 6043 | * Deallocates a parser's resources |
edamame22 | 0:a9bcda5b678a | 6044 | * |
edamame22 | 0:a9bcda5b678a | 6045 | * @api public |
edamame22 | 0:a9bcda5b678a | 6046 | */ |
edamame22 | 0:a9bcda5b678a | 6047 | |
edamame22 | 0:a9bcda5b678a | 6048 | Decoder.prototype.destroy = function() { |
edamame22 | 0:a9bcda5b678a | 6049 | if (this.reconstructor) { |
edamame22 | 0:a9bcda5b678a | 6050 | this.reconstructor.finishedReconstruction(); |
edamame22 | 0:a9bcda5b678a | 6051 | } |
edamame22 | 0:a9bcda5b678a | 6052 | }; |
edamame22 | 0:a9bcda5b678a | 6053 | |
edamame22 | 0:a9bcda5b678a | 6054 | /** |
edamame22 | 0:a9bcda5b678a | 6055 | * A manager of a binary event's 'buffer sequence'. Should |
edamame22 | 0:a9bcda5b678a | 6056 | * be constructed whenever a packet of type BINARY_EVENT is |
edamame22 | 0:a9bcda5b678a | 6057 | * decoded. |
edamame22 | 0:a9bcda5b678a | 6058 | * |
edamame22 | 0:a9bcda5b678a | 6059 | * @param {Object} packet |
edamame22 | 0:a9bcda5b678a | 6060 | * @return {BinaryReconstructor} initialized reconstructor |
edamame22 | 0:a9bcda5b678a | 6061 | * @api private |
edamame22 | 0:a9bcda5b678a | 6062 | */ |
edamame22 | 0:a9bcda5b678a | 6063 | |
edamame22 | 0:a9bcda5b678a | 6064 | function BinaryReconstructor(packet) { |
edamame22 | 0:a9bcda5b678a | 6065 | this.reconPack = packet; |
edamame22 | 0:a9bcda5b678a | 6066 | this.buffers = []; |
edamame22 | 0:a9bcda5b678a | 6067 | } |
edamame22 | 0:a9bcda5b678a | 6068 | |
edamame22 | 0:a9bcda5b678a | 6069 | /** |
edamame22 | 0:a9bcda5b678a | 6070 | * Method to be called when binary data received from connection |
edamame22 | 0:a9bcda5b678a | 6071 | * after a BINARY_EVENT packet. |
edamame22 | 0:a9bcda5b678a | 6072 | * |
edamame22 | 0:a9bcda5b678a | 6073 | * @param {Buffer | ArrayBuffer} binData - the raw binary data received |
edamame22 | 0:a9bcda5b678a | 6074 | * @return {null | Object} returns null if more binary data is expected or |
edamame22 | 0:a9bcda5b678a | 6075 | * a reconstructed packet object if all buffers have been received. |
edamame22 | 0:a9bcda5b678a | 6076 | * @api private |
edamame22 | 0:a9bcda5b678a | 6077 | */ |
edamame22 | 0:a9bcda5b678a | 6078 | |
edamame22 | 0:a9bcda5b678a | 6079 | BinaryReconstructor.prototype.takeBinaryData = function(binData) { |
edamame22 | 0:a9bcda5b678a | 6080 | this.buffers.push(binData); |
edamame22 | 0:a9bcda5b678a | 6081 | if (this.buffers.length == this.reconPack.attachments) { // done with buffer list |
edamame22 | 0:a9bcda5b678a | 6082 | var packet = binary.reconstructPacket(this.reconPack, this.buffers); |
edamame22 | 0:a9bcda5b678a | 6083 | this.finishedReconstruction(); |
edamame22 | 0:a9bcda5b678a | 6084 | return packet; |
edamame22 | 0:a9bcda5b678a | 6085 | } |
edamame22 | 0:a9bcda5b678a | 6086 | return null; |
edamame22 | 0:a9bcda5b678a | 6087 | }; |
edamame22 | 0:a9bcda5b678a | 6088 | |
edamame22 | 0:a9bcda5b678a | 6089 | /** |
edamame22 | 0:a9bcda5b678a | 6090 | * Cleans up binary packet reconstruction variables. |
edamame22 | 0:a9bcda5b678a | 6091 | * |
edamame22 | 0:a9bcda5b678a | 6092 | * @api private |
edamame22 | 0:a9bcda5b678a | 6093 | */ |
edamame22 | 0:a9bcda5b678a | 6094 | |
edamame22 | 0:a9bcda5b678a | 6095 | BinaryReconstructor.prototype.finishedReconstruction = function() { |
edamame22 | 0:a9bcda5b678a | 6096 | this.reconPack = null; |
edamame22 | 0:a9bcda5b678a | 6097 | this.buffers = []; |
edamame22 | 0:a9bcda5b678a | 6098 | }; |
edamame22 | 0:a9bcda5b678a | 6099 | |
edamame22 | 0:a9bcda5b678a | 6100 | function error(data){ |
edamame22 | 0:a9bcda5b678a | 6101 | return { |
edamame22 | 0:a9bcda5b678a | 6102 | type: exports.ERROR, |
edamame22 | 0:a9bcda5b678a | 6103 | data: 'parser error' |
edamame22 | 0:a9bcda5b678a | 6104 | }; |
edamame22 | 0:a9bcda5b678a | 6105 | } |
edamame22 | 0:a9bcda5b678a | 6106 | |
edamame22 | 0:a9bcda5b678a | 6107 | },{"./binary":45,"./is-buffer":47,"component-emitter":9,"debug":10,"isarray":48,"json3":49}],47:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 6108 | (function (global){ |
edamame22 | 0:a9bcda5b678a | 6109 | |
edamame22 | 0:a9bcda5b678a | 6110 | module.exports = isBuf; |
edamame22 | 0:a9bcda5b678a | 6111 | |
edamame22 | 0:a9bcda5b678a | 6112 | /** |
edamame22 | 0:a9bcda5b678a | 6113 | * Returns true if obj is a buffer or an arraybuffer. |
edamame22 | 0:a9bcda5b678a | 6114 | * |
edamame22 | 0:a9bcda5b678a | 6115 | * @api private |
edamame22 | 0:a9bcda5b678a | 6116 | */ |
edamame22 | 0:a9bcda5b678a | 6117 | |
edamame22 | 0:a9bcda5b678a | 6118 | function isBuf(obj) { |
edamame22 | 0:a9bcda5b678a | 6119 | return (global.Buffer && global.Buffer.isBuffer(obj)) || |
edamame22 | 0:a9bcda5b678a | 6120 | (global.ArrayBuffer && obj instanceof ArrayBuffer); |
edamame22 | 0:a9bcda5b678a | 6121 | } |
edamame22 | 0:a9bcda5b678a | 6122 | |
edamame22 | 0:a9bcda5b678a | 6123 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
edamame22 | 0:a9bcda5b678a | 6124 | },{}],48:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 6125 | module.exports=_dereq_(32) |
edamame22 | 0:a9bcda5b678a | 6126 | },{}],49:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 6127 | /*! JSON v3.2.6 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit Cambridge | http://kit.mit-license.org */ |
edamame22 | 0:a9bcda5b678a | 6128 | ;(function (window) { |
edamame22 | 0:a9bcda5b678a | 6129 | // Convenience aliases. |
edamame22 | 0:a9bcda5b678a | 6130 | var getClass = {}.toString, isProperty, forEach, undef; |
edamame22 | 0:a9bcda5b678a | 6131 | |
edamame22 | 0:a9bcda5b678a | 6132 | // Detect the `define` function exposed by asynchronous module loaders. The |
edamame22 | 0:a9bcda5b678a | 6133 | // strict `define` check is necessary for compatibility with `r.js`. |
edamame22 | 0:a9bcda5b678a | 6134 | var isLoader = typeof define === "function" && define.amd; |
edamame22 | 0:a9bcda5b678a | 6135 | |
edamame22 | 0:a9bcda5b678a | 6136 | // Detect native implementations. |
edamame22 | 0:a9bcda5b678a | 6137 | var nativeJSON = typeof JSON == "object" && JSON; |
edamame22 | 0:a9bcda5b678a | 6138 | |
edamame22 | 0:a9bcda5b678a | 6139 | // Set up the JSON 3 namespace, preferring the CommonJS `exports` object if |
edamame22 | 0:a9bcda5b678a | 6140 | // available. |
edamame22 | 0:a9bcda5b678a | 6141 | var JSON3 = typeof exports == "object" && exports && !exports.nodeType && exports; |
edamame22 | 0:a9bcda5b678a | 6142 | |
edamame22 | 0:a9bcda5b678a | 6143 | if (JSON3 && nativeJSON) { |
edamame22 | 0:a9bcda5b678a | 6144 | // Explicitly delegate to the native `stringify` and `parse` |
edamame22 | 0:a9bcda5b678a | 6145 | // implementations in CommonJS environments. |
edamame22 | 0:a9bcda5b678a | 6146 | JSON3.stringify = nativeJSON.stringify; |
edamame22 | 0:a9bcda5b678a | 6147 | JSON3.parse = nativeJSON.parse; |
edamame22 | 0:a9bcda5b678a | 6148 | } else { |
edamame22 | 0:a9bcda5b678a | 6149 | // Export for web browsers, JavaScript engines, and asynchronous module |
edamame22 | 0:a9bcda5b678a | 6150 | // loaders, using the global `JSON` object if available. |
edamame22 | 0:a9bcda5b678a | 6151 | JSON3 = window.JSON = nativeJSON || {}; |
edamame22 | 0:a9bcda5b678a | 6152 | } |
edamame22 | 0:a9bcda5b678a | 6153 | |
edamame22 | 0:a9bcda5b678a | 6154 | // Test the `Date#getUTC*` methods. Based on work by @Yaffle. |
edamame22 | 0:a9bcda5b678a | 6155 | var isExtended = new Date(-3509827334573292); |
edamame22 | 0:a9bcda5b678a | 6156 | try { |
edamame22 | 0:a9bcda5b678a | 6157 | // The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical |
edamame22 | 0:a9bcda5b678a | 6158 | // results for certain dates in Opera >= 10.53. |
edamame22 | 0:a9bcda5b678a | 6159 | isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && |
edamame22 | 0:a9bcda5b678a | 6160 | // Safari < 2.0.2 stores the internal millisecond time value correctly, |
edamame22 | 0:a9bcda5b678a | 6161 | // but clips the values returned by the date methods to the range of |
edamame22 | 0:a9bcda5b678a | 6162 | // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]). |
edamame22 | 0:a9bcda5b678a | 6163 | isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; |
edamame22 | 0:a9bcda5b678a | 6164 | } catch (exception) {} |
edamame22 | 0:a9bcda5b678a | 6165 | |
edamame22 | 0:a9bcda5b678a | 6166 | // Internal: Determines whether the native `JSON.stringify` and `parse` |
edamame22 | 0:a9bcda5b678a | 6167 | // implementations are spec-compliant. Based on work by Ken Snyder. |
edamame22 | 0:a9bcda5b678a | 6168 | function has(name) { |
edamame22 | 0:a9bcda5b678a | 6169 | if (has[name] !== undef) { |
edamame22 | 0:a9bcda5b678a | 6170 | // Return cached feature test result. |
edamame22 | 0:a9bcda5b678a | 6171 | return has[name]; |
edamame22 | 0:a9bcda5b678a | 6172 | } |
edamame22 | 0:a9bcda5b678a | 6173 | |
edamame22 | 0:a9bcda5b678a | 6174 | var isSupported; |
edamame22 | 0:a9bcda5b678a | 6175 | if (name == "bug-string-char-index") { |
edamame22 | 0:a9bcda5b678a | 6176 | // IE <= 7 doesn't support accessing string characters using square |
edamame22 | 0:a9bcda5b678a | 6177 | // bracket notation. IE 8 only supports this for primitives. |
edamame22 | 0:a9bcda5b678a | 6178 | isSupported = "a"[0] != "a"; |
edamame22 | 0:a9bcda5b678a | 6179 | } else if (name == "json") { |
edamame22 | 0:a9bcda5b678a | 6180 | // Indicates whether both `JSON.stringify` and `JSON.parse` are |
edamame22 | 0:a9bcda5b678a | 6181 | // supported. |
edamame22 | 0:a9bcda5b678a | 6182 | isSupported = has("json-stringify") && has("json-parse"); |
edamame22 | 0:a9bcda5b678a | 6183 | } else { |
edamame22 | 0:a9bcda5b678a | 6184 | var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; |
edamame22 | 0:a9bcda5b678a | 6185 | // Test `JSON.stringify`. |
edamame22 | 0:a9bcda5b678a | 6186 | if (name == "json-stringify") { |
edamame22 | 0:a9bcda5b678a | 6187 | var stringify = JSON3.stringify, stringifySupported = typeof stringify == "function" && isExtended; |
edamame22 | 0:a9bcda5b678a | 6188 | if (stringifySupported) { |
edamame22 | 0:a9bcda5b678a | 6189 | // A test function object with a custom `toJSON` method. |
edamame22 | 0:a9bcda5b678a | 6190 | (value = function () { |
edamame22 | 0:a9bcda5b678a | 6191 | return 1; |
edamame22 | 0:a9bcda5b678a | 6192 | }).toJSON = value; |
edamame22 | 0:a9bcda5b678a | 6193 | try { |
edamame22 | 0:a9bcda5b678a | 6194 | stringifySupported = |
edamame22 | 0:a9bcda5b678a | 6195 | // Firefox 3.1b1 and b2 serialize string, number, and boolean |
edamame22 | 0:a9bcda5b678a | 6196 | // primitives as object literals. |
edamame22 | 0:a9bcda5b678a | 6197 | stringify(0) === "0" && |
edamame22 | 0:a9bcda5b678a | 6198 | // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object |
edamame22 | 0:a9bcda5b678a | 6199 | // literals. |
edamame22 | 0:a9bcda5b678a | 6200 | stringify(new Number()) === "0" && |
edamame22 | 0:a9bcda5b678a | 6201 | stringify(new String()) == '""' && |
edamame22 | 0:a9bcda5b678a | 6202 | // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or |
edamame22 | 0:a9bcda5b678a | 6203 | // does not define a canonical JSON representation (this applies to |
edamame22 | 0:a9bcda5b678a | 6204 | // objects with `toJSON` properties as well, *unless* they are nested |
edamame22 | 0:a9bcda5b678a | 6205 | // within an object or array). |
edamame22 | 0:a9bcda5b678a | 6206 | stringify(getClass) === undef && |
edamame22 | 0:a9bcda5b678a | 6207 | // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and |
edamame22 | 0:a9bcda5b678a | 6208 | // FF 3.1b3 pass this test. |
edamame22 | 0:a9bcda5b678a | 6209 | stringify(undef) === undef && |
edamame22 | 0:a9bcda5b678a | 6210 | // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s, |
edamame22 | 0:a9bcda5b678a | 6211 | // respectively, if the value is omitted entirely. |
edamame22 | 0:a9bcda5b678a | 6212 | stringify() === undef && |
edamame22 | 0:a9bcda5b678a | 6213 | // FF 3.1b1, 2 throw an error if the given value is not a number, |
edamame22 | 0:a9bcda5b678a | 6214 | // string, array, object, Boolean, or `null` literal. This applies to |
edamame22 | 0:a9bcda5b678a | 6215 | // objects with custom `toJSON` methods as well, unless they are nested |
edamame22 | 0:a9bcda5b678a | 6216 | // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON` |
edamame22 | 0:a9bcda5b678a | 6217 | // methods entirely. |
edamame22 | 0:a9bcda5b678a | 6218 | stringify(value) === "1" && |
edamame22 | 0:a9bcda5b678a | 6219 | stringify([value]) == "[1]" && |
edamame22 | 0:a9bcda5b678a | 6220 | // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of |
edamame22 | 0:a9bcda5b678a | 6221 | // `"[null]"`. |
edamame22 | 0:a9bcda5b678a | 6222 | stringify([undef]) == "[null]" && |
edamame22 | 0:a9bcda5b678a | 6223 | // YUI 3.0.0b1 fails to serialize `null` literals. |
edamame22 | 0:a9bcda5b678a | 6224 | stringify(null) == "null" && |
edamame22 | 0:a9bcda5b678a | 6225 | // FF 3.1b1, 2 halts serialization if an array contains a function: |
edamame22 | 0:a9bcda5b678a | 6226 | // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3 |
edamame22 | 0:a9bcda5b678a | 6227 | // elides non-JSON values from objects and arrays, unless they |
edamame22 | 0:a9bcda5b678a | 6228 | // define custom `toJSON` methods. |
edamame22 | 0:a9bcda5b678a | 6229 | stringify([undef, getClass, null]) == "[null,null,null]" && |
edamame22 | 0:a9bcda5b678a | 6230 | // Simple serialization test. FF 3.1b1 uses Unicode escape sequences |
edamame22 | 0:a9bcda5b678a | 6231 | // where character escape codes are expected (e.g., `\b` => `\u0008`). |
edamame22 | 0:a9bcda5b678a | 6232 | stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && |
edamame22 | 0:a9bcda5b678a | 6233 | // FF 3.1b1 and b2 ignore the `filter` and `width` arguments. |
edamame22 | 0:a9bcda5b678a | 6234 | stringify(null, value) === "1" && |
edamame22 | 0:a9bcda5b678a | 6235 | stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && |
edamame22 | 0:a9bcda5b678a | 6236 | // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly |
edamame22 | 0:a9bcda5b678a | 6237 | // serialize extended years. |
edamame22 | 0:a9bcda5b678a | 6238 | stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && |
edamame22 | 0:a9bcda5b678a | 6239 | // The milliseconds are optional in ES 5, but required in 5.1. |
edamame22 | 0:a9bcda5b678a | 6240 | stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && |
edamame22 | 0:a9bcda5b678a | 6241 | // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative |
edamame22 | 0:a9bcda5b678a | 6242 | // four-digit years instead of six-digit years. Credits: @Yaffle. |
edamame22 | 0:a9bcda5b678a | 6243 | stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && |
edamame22 | 0:a9bcda5b678a | 6244 | // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond |
edamame22 | 0:a9bcda5b678a | 6245 | // values less than 1000. Credits: @Yaffle. |
edamame22 | 0:a9bcda5b678a | 6246 | stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; |
edamame22 | 0:a9bcda5b678a | 6247 | } catch (exception) { |
edamame22 | 0:a9bcda5b678a | 6248 | stringifySupported = false; |
edamame22 | 0:a9bcda5b678a | 6249 | } |
edamame22 | 0:a9bcda5b678a | 6250 | } |
edamame22 | 0:a9bcda5b678a | 6251 | isSupported = stringifySupported; |
edamame22 | 0:a9bcda5b678a | 6252 | } |
edamame22 | 0:a9bcda5b678a | 6253 | // Test `JSON.parse`. |
edamame22 | 0:a9bcda5b678a | 6254 | if (name == "json-parse") { |
edamame22 | 0:a9bcda5b678a | 6255 | var parse = JSON3.parse; |
edamame22 | 0:a9bcda5b678a | 6256 | if (typeof parse == "function") { |
edamame22 | 0:a9bcda5b678a | 6257 | try { |
edamame22 | 0:a9bcda5b678a | 6258 | // FF 3.1b1, b2 will throw an exception if a bare literal is provided. |
edamame22 | 0:a9bcda5b678a | 6259 | // Conforming implementations should also coerce the initial argument to |
edamame22 | 0:a9bcda5b678a | 6260 | // a string prior to parsing. |
edamame22 | 0:a9bcda5b678a | 6261 | if (parse("0") === 0 && !parse(false)) { |
edamame22 | 0:a9bcda5b678a | 6262 | // Simple parsing test. |
edamame22 | 0:a9bcda5b678a | 6263 | value = parse(serialized); |
edamame22 | 0:a9bcda5b678a | 6264 | var parseSupported = value["a"].length == 5 && value["a"][0] === 1; |
edamame22 | 0:a9bcda5b678a | 6265 | if (parseSupported) { |
edamame22 | 0:a9bcda5b678a | 6266 | try { |
edamame22 | 0:a9bcda5b678a | 6267 | // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings. |
edamame22 | 0:a9bcda5b678a | 6268 | parseSupported = !parse('"\t"'); |
edamame22 | 0:a9bcda5b678a | 6269 | } catch (exception) {} |
edamame22 | 0:a9bcda5b678a | 6270 | if (parseSupported) { |
edamame22 | 0:a9bcda5b678a | 6271 | try { |
edamame22 | 0:a9bcda5b678a | 6272 | // FF 4.0 and 4.0.1 allow leading `+` signs and leading |
edamame22 | 0:a9bcda5b678a | 6273 | // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow |
edamame22 | 0:a9bcda5b678a | 6274 | // certain octal literals. |
edamame22 | 0:a9bcda5b678a | 6275 | parseSupported = parse("01") !== 1; |
edamame22 | 0:a9bcda5b678a | 6276 | } catch (exception) {} |
edamame22 | 0:a9bcda5b678a | 6277 | } |
edamame22 | 0:a9bcda5b678a | 6278 | if (parseSupported) { |
edamame22 | 0:a9bcda5b678a | 6279 | try { |
edamame22 | 0:a9bcda5b678a | 6280 | // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal |
edamame22 | 0:a9bcda5b678a | 6281 | // points. These environments, along with FF 3.1b1 and 2, |
edamame22 | 0:a9bcda5b678a | 6282 | // also allow trailing commas in JSON objects and arrays. |
edamame22 | 0:a9bcda5b678a | 6283 | parseSupported = parse("1.") !== 1; |
edamame22 | 0:a9bcda5b678a | 6284 | } catch (exception) {} |
edamame22 | 0:a9bcda5b678a | 6285 | } |
edamame22 | 0:a9bcda5b678a | 6286 | } |
edamame22 | 0:a9bcda5b678a | 6287 | } |
edamame22 | 0:a9bcda5b678a | 6288 | } catch (exception) { |
edamame22 | 0:a9bcda5b678a | 6289 | parseSupported = false; |
edamame22 | 0:a9bcda5b678a | 6290 | } |
edamame22 | 0:a9bcda5b678a | 6291 | } |
edamame22 | 0:a9bcda5b678a | 6292 | isSupported = parseSupported; |
edamame22 | 0:a9bcda5b678a | 6293 | } |
edamame22 | 0:a9bcda5b678a | 6294 | } |
edamame22 | 0:a9bcda5b678a | 6295 | return has[name] = !!isSupported; |
edamame22 | 0:a9bcda5b678a | 6296 | } |
edamame22 | 0:a9bcda5b678a | 6297 | |
edamame22 | 0:a9bcda5b678a | 6298 | if (!has("json")) { |
edamame22 | 0:a9bcda5b678a | 6299 | // Common `[[Class]]` name aliases. |
edamame22 | 0:a9bcda5b678a | 6300 | var functionClass = "[object Function]"; |
edamame22 | 0:a9bcda5b678a | 6301 | var dateClass = "[object Date]"; |
edamame22 | 0:a9bcda5b678a | 6302 | var numberClass = "[object Number]"; |
edamame22 | 0:a9bcda5b678a | 6303 | var stringClass = "[object String]"; |
edamame22 | 0:a9bcda5b678a | 6304 | var arrayClass = "[object Array]"; |
edamame22 | 0:a9bcda5b678a | 6305 | var booleanClass = "[object Boolean]"; |
edamame22 | 0:a9bcda5b678a | 6306 | |
edamame22 | 0:a9bcda5b678a | 6307 | // Detect incomplete support for accessing string characters by index. |
edamame22 | 0:a9bcda5b678a | 6308 | var charIndexBuggy = has("bug-string-char-index"); |
edamame22 | 0:a9bcda5b678a | 6309 | |
edamame22 | 0:a9bcda5b678a | 6310 | // Define additional utility methods if the `Date` methods are buggy. |
edamame22 | 0:a9bcda5b678a | 6311 | if (!isExtended) { |
edamame22 | 0:a9bcda5b678a | 6312 | var floor = Math.floor; |
edamame22 | 0:a9bcda5b678a | 6313 | // A mapping between the months of the year and the number of days between |
edamame22 | 0:a9bcda5b678a | 6314 | // January 1st and the first of the respective month. |
edamame22 | 0:a9bcda5b678a | 6315 | var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; |
edamame22 | 0:a9bcda5b678a | 6316 | // Internal: Calculates the number of days between the Unix epoch and the |
edamame22 | 0:a9bcda5b678a | 6317 | // first day of the given month. |
edamame22 | 0:a9bcda5b678a | 6318 | var getDay = function (year, month) { |
edamame22 | 0:a9bcda5b678a | 6319 | return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); |
edamame22 | 0:a9bcda5b678a | 6320 | }; |
edamame22 | 0:a9bcda5b678a | 6321 | } |
edamame22 | 0:a9bcda5b678a | 6322 | |
edamame22 | 0:a9bcda5b678a | 6323 | // Internal: Determines if a property is a direct property of the given |
edamame22 | 0:a9bcda5b678a | 6324 | // object. Delegates to the native `Object#hasOwnProperty` method. |
edamame22 | 0:a9bcda5b678a | 6325 | if (!(isProperty = {}.hasOwnProperty)) { |
edamame22 | 0:a9bcda5b678a | 6326 | isProperty = function (property) { |
edamame22 | 0:a9bcda5b678a | 6327 | var members = {}, constructor; |
edamame22 | 0:a9bcda5b678a | 6328 | if ((members.__proto__ = null, members.__proto__ = { |
edamame22 | 0:a9bcda5b678a | 6329 | // The *proto* property cannot be set multiple times in recent |
edamame22 | 0:a9bcda5b678a | 6330 | // versions of Firefox and SeaMonkey. |
edamame22 | 0:a9bcda5b678a | 6331 | "toString": 1 |
edamame22 | 0:a9bcda5b678a | 6332 | }, members).toString != getClass) { |
edamame22 | 0:a9bcda5b678a | 6333 | // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but |
edamame22 | 0:a9bcda5b678a | 6334 | // supports the mutable *proto* property. |
edamame22 | 0:a9bcda5b678a | 6335 | isProperty = function (property) { |
edamame22 | 0:a9bcda5b678a | 6336 | // Capture and break the object's prototype chain (see section 8.6.2 |
edamame22 | 0:a9bcda5b678a | 6337 | // of the ES 5.1 spec). The parenthesized expression prevents an |
edamame22 | 0:a9bcda5b678a | 6338 | // unsafe transformation by the Closure Compiler. |
edamame22 | 0:a9bcda5b678a | 6339 | var original = this.__proto__, result = property in (this.__proto__ = null, this); |
edamame22 | 0:a9bcda5b678a | 6340 | // Restore the original prototype chain. |
edamame22 | 0:a9bcda5b678a | 6341 | this.__proto__ = original; |
edamame22 | 0:a9bcda5b678a | 6342 | return result; |
edamame22 | 0:a9bcda5b678a | 6343 | }; |
edamame22 | 0:a9bcda5b678a | 6344 | } else { |
edamame22 | 0:a9bcda5b678a | 6345 | // Capture a reference to the top-level `Object` constructor. |
edamame22 | 0:a9bcda5b678a | 6346 | constructor = members.constructor; |
edamame22 | 0:a9bcda5b678a | 6347 | // Use the `constructor` property to simulate `Object#hasOwnProperty` in |
edamame22 | 0:a9bcda5b678a | 6348 | // other environments. |
edamame22 | 0:a9bcda5b678a | 6349 | isProperty = function (property) { |
edamame22 | 0:a9bcda5b678a | 6350 | var parent = (this.constructor || constructor).prototype; |
edamame22 | 0:a9bcda5b678a | 6351 | return property in this && !(property in parent && this[property] === parent[property]); |
edamame22 | 0:a9bcda5b678a | 6352 | }; |
edamame22 | 0:a9bcda5b678a | 6353 | } |
edamame22 | 0:a9bcda5b678a | 6354 | members = null; |
edamame22 | 0:a9bcda5b678a | 6355 | return isProperty.call(this, property); |
edamame22 | 0:a9bcda5b678a | 6356 | }; |
edamame22 | 0:a9bcda5b678a | 6357 | } |
edamame22 | 0:a9bcda5b678a | 6358 | |
edamame22 | 0:a9bcda5b678a | 6359 | // Internal: A set of primitive types used by `isHostType`. |
edamame22 | 0:a9bcda5b678a | 6360 | var PrimitiveTypes = { |
edamame22 | 0:a9bcda5b678a | 6361 | 'boolean': 1, |
edamame22 | 0:a9bcda5b678a | 6362 | 'number': 1, |
edamame22 | 0:a9bcda5b678a | 6363 | 'string': 1, |
edamame22 | 0:a9bcda5b678a | 6364 | 'undefined': 1 |
edamame22 | 0:a9bcda5b678a | 6365 | }; |
edamame22 | 0:a9bcda5b678a | 6366 | |
edamame22 | 0:a9bcda5b678a | 6367 | // Internal: Determines if the given object `property` value is a |
edamame22 | 0:a9bcda5b678a | 6368 | // non-primitive. |
edamame22 | 0:a9bcda5b678a | 6369 | var isHostType = function (object, property) { |
edamame22 | 0:a9bcda5b678a | 6370 | var type = typeof object[property]; |
edamame22 | 0:a9bcda5b678a | 6371 | return type == 'object' ? !!object[property] : !PrimitiveTypes[type]; |
edamame22 | 0:a9bcda5b678a | 6372 | }; |
edamame22 | 0:a9bcda5b678a | 6373 | |
edamame22 | 0:a9bcda5b678a | 6374 | // Internal: Normalizes the `for...in` iteration algorithm across |
edamame22 | 0:a9bcda5b678a | 6375 | // environments. Each enumerated key is yielded to a `callback` function. |
edamame22 | 0:a9bcda5b678a | 6376 | forEach = function (object, callback) { |
edamame22 | 0:a9bcda5b678a | 6377 | var size = 0, Properties, members, property; |
edamame22 | 0:a9bcda5b678a | 6378 | |
edamame22 | 0:a9bcda5b678a | 6379 | // Tests for bugs in the current environment's `for...in` algorithm. The |
edamame22 | 0:a9bcda5b678a | 6380 | // `valueOf` property inherits the non-enumerable flag from |
edamame22 | 0:a9bcda5b678a | 6381 | // `Object.prototype` in older versions of IE, Netscape, and Mozilla. |
edamame22 | 0:a9bcda5b678a | 6382 | (Properties = function () { |
edamame22 | 0:a9bcda5b678a | 6383 | this.valueOf = 0; |
edamame22 | 0:a9bcda5b678a | 6384 | }).prototype.valueOf = 0; |
edamame22 | 0:a9bcda5b678a | 6385 | |
edamame22 | 0:a9bcda5b678a | 6386 | // Iterate over a new instance of the `Properties` class. |
edamame22 | 0:a9bcda5b678a | 6387 | members = new Properties(); |
edamame22 | 0:a9bcda5b678a | 6388 | for (property in members) { |
edamame22 | 0:a9bcda5b678a | 6389 | // Ignore all properties inherited from `Object.prototype`. |
edamame22 | 0:a9bcda5b678a | 6390 | if (isProperty.call(members, property)) { |
edamame22 | 0:a9bcda5b678a | 6391 | size++; |
edamame22 | 0:a9bcda5b678a | 6392 | } |
edamame22 | 0:a9bcda5b678a | 6393 | } |
edamame22 | 0:a9bcda5b678a | 6394 | Properties = members = null; |
edamame22 | 0:a9bcda5b678a | 6395 | |
edamame22 | 0:a9bcda5b678a | 6396 | // Normalize the iteration algorithm. |
edamame22 | 0:a9bcda5b678a | 6397 | if (!size) { |
edamame22 | 0:a9bcda5b678a | 6398 | // A list of non-enumerable properties inherited from `Object.prototype`. |
edamame22 | 0:a9bcda5b678a | 6399 | members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; |
edamame22 | 0:a9bcda5b678a | 6400 | // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable |
edamame22 | 0:a9bcda5b678a | 6401 | // properties. |
edamame22 | 0:a9bcda5b678a | 6402 | forEach = function (object, callback) { |
edamame22 | 0:a9bcda5b678a | 6403 | var isFunction = getClass.call(object) == functionClass, property, length; |
edamame22 | 0:a9bcda5b678a | 6404 | var hasProperty = !isFunction && typeof object.constructor != 'function' && isHostType(object, 'hasOwnProperty') ? object.hasOwnProperty : isProperty; |
edamame22 | 0:a9bcda5b678a | 6405 | for (property in object) { |
edamame22 | 0:a9bcda5b678a | 6406 | // Gecko <= 1.0 enumerates the `prototype` property of functions under |
edamame22 | 0:a9bcda5b678a | 6407 | // certain conditions; IE does not. |
edamame22 | 0:a9bcda5b678a | 6408 | if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { |
edamame22 | 0:a9bcda5b678a | 6409 | callback(property); |
edamame22 | 0:a9bcda5b678a | 6410 | } |
edamame22 | 0:a9bcda5b678a | 6411 | } |
edamame22 | 0:a9bcda5b678a | 6412 | // Manually invoke the callback for each non-enumerable property. |
edamame22 | 0:a9bcda5b678a | 6413 | for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); |
edamame22 | 0:a9bcda5b678a | 6414 | }; |
edamame22 | 0:a9bcda5b678a | 6415 | } else if (size == 2) { |
edamame22 | 0:a9bcda5b678a | 6416 | // Safari <= 2.0.4 enumerates shadowed properties twice. |
edamame22 | 0:a9bcda5b678a | 6417 | forEach = function (object, callback) { |
edamame22 | 0:a9bcda5b678a | 6418 | // Create a set of iterated properties. |
edamame22 | 0:a9bcda5b678a | 6419 | var members = {}, isFunction = getClass.call(object) == functionClass, property; |
edamame22 | 0:a9bcda5b678a | 6420 | for (property in object) { |
edamame22 | 0:a9bcda5b678a | 6421 | // Store each property name to prevent double enumeration. The |
edamame22 | 0:a9bcda5b678a | 6422 | // `prototype` property of functions is not enumerated due to cross- |
edamame22 | 0:a9bcda5b678a | 6423 | // environment inconsistencies. |
edamame22 | 0:a9bcda5b678a | 6424 | if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { |
edamame22 | 0:a9bcda5b678a | 6425 | callback(property); |
edamame22 | 0:a9bcda5b678a | 6426 | } |
edamame22 | 0:a9bcda5b678a | 6427 | } |
edamame22 | 0:a9bcda5b678a | 6428 | }; |
edamame22 | 0:a9bcda5b678a | 6429 | } else { |
edamame22 | 0:a9bcda5b678a | 6430 | // No bugs detected; use the standard `for...in` algorithm. |
edamame22 | 0:a9bcda5b678a | 6431 | forEach = function (object, callback) { |
edamame22 | 0:a9bcda5b678a | 6432 | var isFunction = getClass.call(object) == functionClass, property, isConstructor; |
edamame22 | 0:a9bcda5b678a | 6433 | for (property in object) { |
edamame22 | 0:a9bcda5b678a | 6434 | if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { |
edamame22 | 0:a9bcda5b678a | 6435 | callback(property); |
edamame22 | 0:a9bcda5b678a | 6436 | } |
edamame22 | 0:a9bcda5b678a | 6437 | } |
edamame22 | 0:a9bcda5b678a | 6438 | // Manually invoke the callback for the `constructor` property due to |
edamame22 | 0:a9bcda5b678a | 6439 | // cross-environment inconsistencies. |
edamame22 | 0:a9bcda5b678a | 6440 | if (isConstructor || isProperty.call(object, (property = "constructor"))) { |
edamame22 | 0:a9bcda5b678a | 6441 | callback(property); |
edamame22 | 0:a9bcda5b678a | 6442 | } |
edamame22 | 0:a9bcda5b678a | 6443 | }; |
edamame22 | 0:a9bcda5b678a | 6444 | } |
edamame22 | 0:a9bcda5b678a | 6445 | return forEach(object, callback); |
edamame22 | 0:a9bcda5b678a | 6446 | }; |
edamame22 | 0:a9bcda5b678a | 6447 | |
edamame22 | 0:a9bcda5b678a | 6448 | // Public: Serializes a JavaScript `value` as a JSON string. The optional |
edamame22 | 0:a9bcda5b678a | 6449 | // `filter` argument may specify either a function that alters how object and |
edamame22 | 0:a9bcda5b678a | 6450 | // array members are serialized, or an array of strings and numbers that |
edamame22 | 0:a9bcda5b678a | 6451 | // indicates which properties should be serialized. The optional `width` |
edamame22 | 0:a9bcda5b678a | 6452 | // argument may be either a string or number that specifies the indentation |
edamame22 | 0:a9bcda5b678a | 6453 | // level of the output. |
edamame22 | 0:a9bcda5b678a | 6454 | if (!has("json-stringify")) { |
edamame22 | 0:a9bcda5b678a | 6455 | // Internal: A map of control characters and their escaped equivalents. |
edamame22 | 0:a9bcda5b678a | 6456 | var Escapes = { |
edamame22 | 0:a9bcda5b678a | 6457 | 92: "\\\\", |
edamame22 | 0:a9bcda5b678a | 6458 | 34: '\\"', |
edamame22 | 0:a9bcda5b678a | 6459 | 8: "\\b", |
edamame22 | 0:a9bcda5b678a | 6460 | 12: "\\f", |
edamame22 | 0:a9bcda5b678a | 6461 | 10: "\\n", |
edamame22 | 0:a9bcda5b678a | 6462 | 13: "\\r", |
edamame22 | 0:a9bcda5b678a | 6463 | 9: "\\t" |
edamame22 | 0:a9bcda5b678a | 6464 | }; |
edamame22 | 0:a9bcda5b678a | 6465 | |
edamame22 | 0:a9bcda5b678a | 6466 | // Internal: Converts `value` into a zero-padded string such that its |
edamame22 | 0:a9bcda5b678a | 6467 | // length is at least equal to `width`. The `width` must be <= 6. |
edamame22 | 0:a9bcda5b678a | 6468 | var leadingZeroes = "000000"; |
edamame22 | 0:a9bcda5b678a | 6469 | var toPaddedString = function (width, value) { |
edamame22 | 0:a9bcda5b678a | 6470 | // The `|| 0` expression is necessary to work around a bug in |
edamame22 | 0:a9bcda5b678a | 6471 | // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`. |
edamame22 | 0:a9bcda5b678a | 6472 | return (leadingZeroes + (value || 0)).slice(-width); |
edamame22 | 0:a9bcda5b678a | 6473 | }; |
edamame22 | 0:a9bcda5b678a | 6474 | |
edamame22 | 0:a9bcda5b678a | 6475 | // Internal: Double-quotes a string `value`, replacing all ASCII control |
edamame22 | 0:a9bcda5b678a | 6476 | // characters (characters with code unit values between 0 and 31) with |
edamame22 | 0:a9bcda5b678a | 6477 | // their escaped equivalents. This is an implementation of the |
edamame22 | 0:a9bcda5b678a | 6478 | // `Quote(value)` operation defined in ES 5.1 section 15.12.3. |
edamame22 | 0:a9bcda5b678a | 6479 | var unicodePrefix = "\\u00"; |
edamame22 | 0:a9bcda5b678a | 6480 | var quote = function (value) { |
edamame22 | 0:a9bcda5b678a | 6481 | var result = '"', index = 0, length = value.length, isLarge = length > 10 && charIndexBuggy, symbols; |
edamame22 | 0:a9bcda5b678a | 6482 | if (isLarge) { |
edamame22 | 0:a9bcda5b678a | 6483 | symbols = value.split(""); |
edamame22 | 0:a9bcda5b678a | 6484 | } |
edamame22 | 0:a9bcda5b678a | 6485 | for (; index < length; index++) { |
edamame22 | 0:a9bcda5b678a | 6486 | var charCode = value.charCodeAt(index); |
edamame22 | 0:a9bcda5b678a | 6487 | // If the character is a control character, append its Unicode or |
edamame22 | 0:a9bcda5b678a | 6488 | // shorthand escape sequence; otherwise, append the character as-is. |
edamame22 | 0:a9bcda5b678a | 6489 | switch (charCode) { |
edamame22 | 0:a9bcda5b678a | 6490 | case 8: case 9: case 10: case 12: case 13: case 34: case 92: |
edamame22 | 0:a9bcda5b678a | 6491 | result += Escapes[charCode]; |
edamame22 | 0:a9bcda5b678a | 6492 | break; |
edamame22 | 0:a9bcda5b678a | 6493 | default: |
edamame22 | 0:a9bcda5b678a | 6494 | if (charCode < 32) { |
edamame22 | 0:a9bcda5b678a | 6495 | result += unicodePrefix + toPaddedString(2, charCode.toString(16)); |
edamame22 | 0:a9bcda5b678a | 6496 | break; |
edamame22 | 0:a9bcda5b678a | 6497 | } |
edamame22 | 0:a9bcda5b678a | 6498 | result += isLarge ? symbols[index] : charIndexBuggy ? value.charAt(index) : value[index]; |
edamame22 | 0:a9bcda5b678a | 6499 | } |
edamame22 | 0:a9bcda5b678a | 6500 | } |
edamame22 | 0:a9bcda5b678a | 6501 | return result + '"'; |
edamame22 | 0:a9bcda5b678a | 6502 | }; |
edamame22 | 0:a9bcda5b678a | 6503 | |
edamame22 | 0:a9bcda5b678a | 6504 | // Internal: Recursively serializes an object. Implements the |
edamame22 | 0:a9bcda5b678a | 6505 | // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations. |
edamame22 | 0:a9bcda5b678a | 6506 | var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { |
edamame22 | 0:a9bcda5b678a | 6507 | var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; |
edamame22 | 0:a9bcda5b678a | 6508 | try { |
edamame22 | 0:a9bcda5b678a | 6509 | // Necessary for host object support. |
edamame22 | 0:a9bcda5b678a | 6510 | value = object[property]; |
edamame22 | 0:a9bcda5b678a | 6511 | } catch (exception) {} |
edamame22 | 0:a9bcda5b678a | 6512 | if (typeof value == "object" && value) { |
edamame22 | 0:a9bcda5b678a | 6513 | className = getClass.call(value); |
edamame22 | 0:a9bcda5b678a | 6514 | if (className == dateClass && !isProperty.call(value, "toJSON")) { |
edamame22 | 0:a9bcda5b678a | 6515 | if (value > -1 / 0 && value < 1 / 0) { |
edamame22 | 0:a9bcda5b678a | 6516 | // Dates are serialized according to the `Date#toJSON` method |
edamame22 | 0:a9bcda5b678a | 6517 | // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15 |
edamame22 | 0:a9bcda5b678a | 6518 | // for the ISO 8601 date time string format. |
edamame22 | 0:a9bcda5b678a | 6519 | if (getDay) { |
edamame22 | 0:a9bcda5b678a | 6520 | // Manually compute the year, month, date, hours, minutes, |
edamame22 | 0:a9bcda5b678a | 6521 | // seconds, and milliseconds if the `getUTC*` methods are |
edamame22 | 0:a9bcda5b678a | 6522 | // buggy. Adapted from @Yaffle's `date-shim` project. |
edamame22 | 0:a9bcda5b678a | 6523 | date = floor(value / 864e5); |
edamame22 | 0:a9bcda5b678a | 6524 | for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); |
edamame22 | 0:a9bcda5b678a | 6525 | for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); |
edamame22 | 0:a9bcda5b678a | 6526 | date = 1 + date - getDay(year, month); |
edamame22 | 0:a9bcda5b678a | 6527 | // The `time` value specifies the time within the day (see ES |
edamame22 | 0:a9bcda5b678a | 6528 | // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used |
edamame22 | 0:a9bcda5b678a | 6529 | // to compute `A modulo B`, as the `%` operator does not |
edamame22 | 0:a9bcda5b678a | 6530 | // correspond to the `modulo` operation for negative numbers. |
edamame22 | 0:a9bcda5b678a | 6531 | time = (value % 864e5 + 864e5) % 864e5; |
edamame22 | 0:a9bcda5b678a | 6532 | // The hours, minutes, seconds, and milliseconds are obtained by |
edamame22 | 0:a9bcda5b678a | 6533 | // decomposing the time within the day. See section 15.9.1.10. |
edamame22 | 0:a9bcda5b678a | 6534 | hours = floor(time / 36e5) % 24; |
edamame22 | 0:a9bcda5b678a | 6535 | minutes = floor(time / 6e4) % 60; |
edamame22 | 0:a9bcda5b678a | 6536 | seconds = floor(time / 1e3) % 60; |
edamame22 | 0:a9bcda5b678a | 6537 | milliseconds = time % 1e3; |
edamame22 | 0:a9bcda5b678a | 6538 | } else { |
edamame22 | 0:a9bcda5b678a | 6539 | year = value.getUTCFullYear(); |
edamame22 | 0:a9bcda5b678a | 6540 | month = value.getUTCMonth(); |
edamame22 | 0:a9bcda5b678a | 6541 | date = value.getUTCDate(); |
edamame22 | 0:a9bcda5b678a | 6542 | hours = value.getUTCHours(); |
edamame22 | 0:a9bcda5b678a | 6543 | minutes = value.getUTCMinutes(); |
edamame22 | 0:a9bcda5b678a | 6544 | seconds = value.getUTCSeconds(); |
edamame22 | 0:a9bcda5b678a | 6545 | milliseconds = value.getUTCMilliseconds(); |
edamame22 | 0:a9bcda5b678a | 6546 | } |
edamame22 | 0:a9bcda5b678a | 6547 | // Serialize extended years correctly. |
edamame22 | 0:a9bcda5b678a | 6548 | value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + |
edamame22 | 0:a9bcda5b678a | 6549 | "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + |
edamame22 | 0:a9bcda5b678a | 6550 | // Months, dates, hours, minutes, and seconds should have two |
edamame22 | 0:a9bcda5b678a | 6551 | // digits; milliseconds should have three. |
edamame22 | 0:a9bcda5b678a | 6552 | "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + |
edamame22 | 0:a9bcda5b678a | 6553 | // Milliseconds are optional in ES 5.0, but required in 5.1. |
edamame22 | 0:a9bcda5b678a | 6554 | "." + toPaddedString(3, milliseconds) + "Z"; |
edamame22 | 0:a9bcda5b678a | 6555 | } else { |
edamame22 | 0:a9bcda5b678a | 6556 | value = null; |
edamame22 | 0:a9bcda5b678a | 6557 | } |
edamame22 | 0:a9bcda5b678a | 6558 | } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { |
edamame22 | 0:a9bcda5b678a | 6559 | // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the |
edamame22 | 0:a9bcda5b678a | 6560 | // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3 |
edamame22 | 0:a9bcda5b678a | 6561 | // ignores all `toJSON` methods on these objects unless they are |
edamame22 | 0:a9bcda5b678a | 6562 | // defined directly on an instance. |
edamame22 | 0:a9bcda5b678a | 6563 | value = value.toJSON(property); |
edamame22 | 0:a9bcda5b678a | 6564 | } |
edamame22 | 0:a9bcda5b678a | 6565 | } |
edamame22 | 0:a9bcda5b678a | 6566 | if (callback) { |
edamame22 | 0:a9bcda5b678a | 6567 | // If a replacement function was provided, call it to obtain the value |
edamame22 | 0:a9bcda5b678a | 6568 | // for serialization. |
edamame22 | 0:a9bcda5b678a | 6569 | value = callback.call(object, property, value); |
edamame22 | 0:a9bcda5b678a | 6570 | } |
edamame22 | 0:a9bcda5b678a | 6571 | if (value === null) { |
edamame22 | 0:a9bcda5b678a | 6572 | return "null"; |
edamame22 | 0:a9bcda5b678a | 6573 | } |
edamame22 | 0:a9bcda5b678a | 6574 | className = getClass.call(value); |
edamame22 | 0:a9bcda5b678a | 6575 | if (className == booleanClass) { |
edamame22 | 0:a9bcda5b678a | 6576 | // Booleans are represented literally. |
edamame22 | 0:a9bcda5b678a | 6577 | return "" + value; |
edamame22 | 0:a9bcda5b678a | 6578 | } else if (className == numberClass) { |
edamame22 | 0:a9bcda5b678a | 6579 | // JSON numbers must be finite. `Infinity` and `NaN` are serialized as |
edamame22 | 0:a9bcda5b678a | 6580 | // `"null"`. |
edamame22 | 0:a9bcda5b678a | 6581 | return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; |
edamame22 | 0:a9bcda5b678a | 6582 | } else if (className == stringClass) { |
edamame22 | 0:a9bcda5b678a | 6583 | // Strings are double-quoted and escaped. |
edamame22 | 0:a9bcda5b678a | 6584 | return quote("" + value); |
edamame22 | 0:a9bcda5b678a | 6585 | } |
edamame22 | 0:a9bcda5b678a | 6586 | // Recursively serialize objects and arrays. |
edamame22 | 0:a9bcda5b678a | 6587 | if (typeof value == "object") { |
edamame22 | 0:a9bcda5b678a | 6588 | // Check for cyclic structures. This is a linear search; performance |
edamame22 | 0:a9bcda5b678a | 6589 | // is inversely proportional to the number of unique nested objects. |
edamame22 | 0:a9bcda5b678a | 6590 | for (length = stack.length; length--;) { |
edamame22 | 0:a9bcda5b678a | 6591 | if (stack[length] === value) { |
edamame22 | 0:a9bcda5b678a | 6592 | // Cyclic structures cannot be serialized by `JSON.stringify`. |
edamame22 | 0:a9bcda5b678a | 6593 | throw TypeError(); |
edamame22 | 0:a9bcda5b678a | 6594 | } |
edamame22 | 0:a9bcda5b678a | 6595 | } |
edamame22 | 0:a9bcda5b678a | 6596 | // Add the object to the stack of traversed objects. |
edamame22 | 0:a9bcda5b678a | 6597 | stack.push(value); |
edamame22 | 0:a9bcda5b678a | 6598 | results = []; |
edamame22 | 0:a9bcda5b678a | 6599 | // Save the current indentation level and indent one additional level. |
edamame22 | 0:a9bcda5b678a | 6600 | prefix = indentation; |
edamame22 | 0:a9bcda5b678a | 6601 | indentation += whitespace; |
edamame22 | 0:a9bcda5b678a | 6602 | if (className == arrayClass) { |
edamame22 | 0:a9bcda5b678a | 6603 | // Recursively serialize array elements. |
edamame22 | 0:a9bcda5b678a | 6604 | for (index = 0, length = value.length; index < length; index++) { |
edamame22 | 0:a9bcda5b678a | 6605 | element = serialize(index, value, callback, properties, whitespace, indentation, stack); |
edamame22 | 0:a9bcda5b678a | 6606 | results.push(element === undef ? "null" : element); |
edamame22 | 0:a9bcda5b678a | 6607 | } |
edamame22 | 0:a9bcda5b678a | 6608 | result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; |
edamame22 | 0:a9bcda5b678a | 6609 | } else { |
edamame22 | 0:a9bcda5b678a | 6610 | // Recursively serialize object members. Members are selected from |
edamame22 | 0:a9bcda5b678a | 6611 | // either a user-specified list of property names, or the object |
edamame22 | 0:a9bcda5b678a | 6612 | // itself. |
edamame22 | 0:a9bcda5b678a | 6613 | forEach(properties || value, function (property) { |
edamame22 | 0:a9bcda5b678a | 6614 | var element = serialize(property, value, callback, properties, whitespace, indentation, stack); |
edamame22 | 0:a9bcda5b678a | 6615 | if (element !== undef) { |
edamame22 | 0:a9bcda5b678a | 6616 | // According to ES 5.1 section 15.12.3: "If `gap` {whitespace} |
edamame22 | 0:a9bcda5b678a | 6617 | // is not the empty string, let `member` {quote(property) + ":"} |
edamame22 | 0:a9bcda5b678a | 6618 | // be the concatenation of `member` and the `space` character." |
edamame22 | 0:a9bcda5b678a | 6619 | // The "`space` character" refers to the literal space |
edamame22 | 0:a9bcda5b678a | 6620 | // character, not the `space` {width} argument provided to |
edamame22 | 0:a9bcda5b678a | 6621 | // `JSON.stringify`. |
edamame22 | 0:a9bcda5b678a | 6622 | results.push(quote(property) + ":" + (whitespace ? " " : "") + element); |
edamame22 | 0:a9bcda5b678a | 6623 | } |
edamame22 | 0:a9bcda5b678a | 6624 | }); |
edamame22 | 0:a9bcda5b678a | 6625 | result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; |
edamame22 | 0:a9bcda5b678a | 6626 | } |
edamame22 | 0:a9bcda5b678a | 6627 | // Remove the object from the traversed object stack. |
edamame22 | 0:a9bcda5b678a | 6628 | stack.pop(); |
edamame22 | 0:a9bcda5b678a | 6629 | return result; |
edamame22 | 0:a9bcda5b678a | 6630 | } |
edamame22 | 0:a9bcda5b678a | 6631 | }; |
edamame22 | 0:a9bcda5b678a | 6632 | |
edamame22 | 0:a9bcda5b678a | 6633 | // Public: `JSON.stringify`. See ES 5.1 section 15.12.3. |
edamame22 | 0:a9bcda5b678a | 6634 | JSON3.stringify = function (source, filter, width) { |
edamame22 | 0:a9bcda5b678a | 6635 | var whitespace, callback, properties, className; |
edamame22 | 0:a9bcda5b678a | 6636 | if (typeof filter == "function" || typeof filter == "object" && filter) { |
edamame22 | 0:a9bcda5b678a | 6637 | if ((className = getClass.call(filter)) == functionClass) { |
edamame22 | 0:a9bcda5b678a | 6638 | callback = filter; |
edamame22 | 0:a9bcda5b678a | 6639 | } else if (className == arrayClass) { |
edamame22 | 0:a9bcda5b678a | 6640 | // Convert the property names array into a makeshift set. |
edamame22 | 0:a9bcda5b678a | 6641 | properties = {}; |
edamame22 | 0:a9bcda5b678a | 6642 | for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); |
edamame22 | 0:a9bcda5b678a | 6643 | } |
edamame22 | 0:a9bcda5b678a | 6644 | } |
edamame22 | 0:a9bcda5b678a | 6645 | if (width) { |
edamame22 | 0:a9bcda5b678a | 6646 | if ((className = getClass.call(width)) == numberClass) { |
edamame22 | 0:a9bcda5b678a | 6647 | // Convert the `width` to an integer and create a string containing |
edamame22 | 0:a9bcda5b678a | 6648 | // `width` number of space characters. |
edamame22 | 0:a9bcda5b678a | 6649 | if ((width -= width % 1) > 0) { |
edamame22 | 0:a9bcda5b678a | 6650 | for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); |
edamame22 | 0:a9bcda5b678a | 6651 | } |
edamame22 | 0:a9bcda5b678a | 6652 | } else if (className == stringClass) { |
edamame22 | 0:a9bcda5b678a | 6653 | whitespace = width.length <= 10 ? width : width.slice(0, 10); |
edamame22 | 0:a9bcda5b678a | 6654 | } |
edamame22 | 0:a9bcda5b678a | 6655 | } |
edamame22 | 0:a9bcda5b678a | 6656 | // Opera <= 7.54u2 discards the values associated with empty string keys |
edamame22 | 0:a9bcda5b678a | 6657 | // (`""`) only if they are used directly within an object member list |
edamame22 | 0:a9bcda5b678a | 6658 | // (e.g., `!("" in { "": 1})`). |
edamame22 | 0:a9bcda5b678a | 6659 | return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); |
edamame22 | 0:a9bcda5b678a | 6660 | }; |
edamame22 | 0:a9bcda5b678a | 6661 | } |
edamame22 | 0:a9bcda5b678a | 6662 | |
edamame22 | 0:a9bcda5b678a | 6663 | // Public: Parses a JSON source string. |
edamame22 | 0:a9bcda5b678a | 6664 | if (!has("json-parse")) { |
edamame22 | 0:a9bcda5b678a | 6665 | var fromCharCode = String.fromCharCode; |
edamame22 | 0:a9bcda5b678a | 6666 | |
edamame22 | 0:a9bcda5b678a | 6667 | // Internal: A map of escaped control characters and their unescaped |
edamame22 | 0:a9bcda5b678a | 6668 | // equivalents. |
edamame22 | 0:a9bcda5b678a | 6669 | var Unescapes = { |
edamame22 | 0:a9bcda5b678a | 6670 | 92: "\\", |
edamame22 | 0:a9bcda5b678a | 6671 | 34: '"', |
edamame22 | 0:a9bcda5b678a | 6672 | 47: "/", |
edamame22 | 0:a9bcda5b678a | 6673 | 98: "\b", |
edamame22 | 0:a9bcda5b678a | 6674 | 116: "\t", |
edamame22 | 0:a9bcda5b678a | 6675 | 110: "\n", |
edamame22 | 0:a9bcda5b678a | 6676 | 102: "\f", |
edamame22 | 0:a9bcda5b678a | 6677 | 114: "\r" |
edamame22 | 0:a9bcda5b678a | 6678 | }; |
edamame22 | 0:a9bcda5b678a | 6679 | |
edamame22 | 0:a9bcda5b678a | 6680 | // Internal: Stores the parser state. |
edamame22 | 0:a9bcda5b678a | 6681 | var Index, Source; |
edamame22 | 0:a9bcda5b678a | 6682 | |
edamame22 | 0:a9bcda5b678a | 6683 | // Internal: Resets the parser state and throws a `SyntaxError`. |
edamame22 | 0:a9bcda5b678a | 6684 | var abort = function() { |
edamame22 | 0:a9bcda5b678a | 6685 | Index = Source = null; |
edamame22 | 0:a9bcda5b678a | 6686 | throw SyntaxError(); |
edamame22 | 0:a9bcda5b678a | 6687 | }; |
edamame22 | 0:a9bcda5b678a | 6688 | |
edamame22 | 0:a9bcda5b678a | 6689 | // Internal: Returns the next token, or `"$"` if the parser has reached |
edamame22 | 0:a9bcda5b678a | 6690 | // the end of the source string. A token may be a string, number, `null` |
edamame22 | 0:a9bcda5b678a | 6691 | // literal, or Boolean literal. |
edamame22 | 0:a9bcda5b678a | 6692 | var lex = function () { |
edamame22 | 0:a9bcda5b678a | 6693 | var source = Source, length = source.length, value, begin, position, isSigned, charCode; |
edamame22 | 0:a9bcda5b678a | 6694 | while (Index < length) { |
edamame22 | 0:a9bcda5b678a | 6695 | charCode = source.charCodeAt(Index); |
edamame22 | 0:a9bcda5b678a | 6696 | switch (charCode) { |
edamame22 | 0:a9bcda5b678a | 6697 | case 9: case 10: case 13: case 32: |
edamame22 | 0:a9bcda5b678a | 6698 | // Skip whitespace tokens, including tabs, carriage returns, line |
edamame22 | 0:a9bcda5b678a | 6699 | // feeds, and space characters. |
edamame22 | 0:a9bcda5b678a | 6700 | Index++; |
edamame22 | 0:a9bcda5b678a | 6701 | break; |
edamame22 | 0:a9bcda5b678a | 6702 | case 123: case 125: case 91: case 93: case 58: case 44: |
edamame22 | 0:a9bcda5b678a | 6703 | // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at |
edamame22 | 0:a9bcda5b678a | 6704 | // the current position. |
edamame22 | 0:a9bcda5b678a | 6705 | value = charIndexBuggy ? source.charAt(Index) : source[Index]; |
edamame22 | 0:a9bcda5b678a | 6706 | Index++; |
edamame22 | 0:a9bcda5b678a | 6707 | return value; |
edamame22 | 0:a9bcda5b678a | 6708 | case 34: |
edamame22 | 0:a9bcda5b678a | 6709 | // `"` delimits a JSON string; advance to the next character and |
edamame22 | 0:a9bcda5b678a | 6710 | // begin parsing the string. String tokens are prefixed with the |
edamame22 | 0:a9bcda5b678a | 6711 | // sentinel `@` character to distinguish them from punctuators and |
edamame22 | 0:a9bcda5b678a | 6712 | // end-of-string tokens. |
edamame22 | 0:a9bcda5b678a | 6713 | for (value = "@", Index++; Index < length;) { |
edamame22 | 0:a9bcda5b678a | 6714 | charCode = source.charCodeAt(Index); |
edamame22 | 0:a9bcda5b678a | 6715 | if (charCode < 32) { |
edamame22 | 0:a9bcda5b678a | 6716 | // Unescaped ASCII control characters (those with a code unit |
edamame22 | 0:a9bcda5b678a | 6717 | // less than the space character) are not permitted. |
edamame22 | 0:a9bcda5b678a | 6718 | abort(); |
edamame22 | 0:a9bcda5b678a | 6719 | } else if (charCode == 92) { |
edamame22 | 0:a9bcda5b678a | 6720 | // A reverse solidus (`\`) marks the beginning of an escaped |
edamame22 | 0:a9bcda5b678a | 6721 | // control character (including `"`, `\`, and `/`) or Unicode |
edamame22 | 0:a9bcda5b678a | 6722 | // escape sequence. |
edamame22 | 0:a9bcda5b678a | 6723 | charCode = source.charCodeAt(++Index); |
edamame22 | 0:a9bcda5b678a | 6724 | switch (charCode) { |
edamame22 | 0:a9bcda5b678a | 6725 | case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: |
edamame22 | 0:a9bcda5b678a | 6726 | // Revive escaped control characters. |
edamame22 | 0:a9bcda5b678a | 6727 | value += Unescapes[charCode]; |
edamame22 | 0:a9bcda5b678a | 6728 | Index++; |
edamame22 | 0:a9bcda5b678a | 6729 | break; |
edamame22 | 0:a9bcda5b678a | 6730 | case 117: |
edamame22 | 0:a9bcda5b678a | 6731 | // `\u` marks the beginning of a Unicode escape sequence. |
edamame22 | 0:a9bcda5b678a | 6732 | // Advance to the first character and validate the |
edamame22 | 0:a9bcda5b678a | 6733 | // four-digit code point. |
edamame22 | 0:a9bcda5b678a | 6734 | begin = ++Index; |
edamame22 | 0:a9bcda5b678a | 6735 | for (position = Index + 4; Index < position; Index++) { |
edamame22 | 0:a9bcda5b678a | 6736 | charCode = source.charCodeAt(Index); |
edamame22 | 0:a9bcda5b678a | 6737 | // A valid sequence comprises four hexdigits (case- |
edamame22 | 0:a9bcda5b678a | 6738 | // insensitive) that form a single hexadecimal value. |
edamame22 | 0:a9bcda5b678a | 6739 | if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { |
edamame22 | 0:a9bcda5b678a | 6740 | // Invalid Unicode escape sequence. |
edamame22 | 0:a9bcda5b678a | 6741 | abort(); |
edamame22 | 0:a9bcda5b678a | 6742 | } |
edamame22 | 0:a9bcda5b678a | 6743 | } |
edamame22 | 0:a9bcda5b678a | 6744 | // Revive the escaped character. |
edamame22 | 0:a9bcda5b678a | 6745 | value += fromCharCode("0x" + source.slice(begin, Index)); |
edamame22 | 0:a9bcda5b678a | 6746 | break; |
edamame22 | 0:a9bcda5b678a | 6747 | default: |
edamame22 | 0:a9bcda5b678a | 6748 | // Invalid escape sequence. |
edamame22 | 0:a9bcda5b678a | 6749 | abort(); |
edamame22 | 0:a9bcda5b678a | 6750 | } |
edamame22 | 0:a9bcda5b678a | 6751 | } else { |
edamame22 | 0:a9bcda5b678a | 6752 | if (charCode == 34) { |
edamame22 | 0:a9bcda5b678a | 6753 | // An unescaped double-quote character marks the end of the |
edamame22 | 0:a9bcda5b678a | 6754 | // string. |
edamame22 | 0:a9bcda5b678a | 6755 | break; |
edamame22 | 0:a9bcda5b678a | 6756 | } |
edamame22 | 0:a9bcda5b678a | 6757 | charCode = source.charCodeAt(Index); |
edamame22 | 0:a9bcda5b678a | 6758 | begin = Index; |
edamame22 | 0:a9bcda5b678a | 6759 | // Optimize for the common case where a string is valid. |
edamame22 | 0:a9bcda5b678a | 6760 | while (charCode >= 32 && charCode != 92 && charCode != 34) { |
edamame22 | 0:a9bcda5b678a | 6761 | charCode = source.charCodeAt(++Index); |
edamame22 | 0:a9bcda5b678a | 6762 | } |
edamame22 | 0:a9bcda5b678a | 6763 | // Append the string as-is. |
edamame22 | 0:a9bcda5b678a | 6764 | value += source.slice(begin, Index); |
edamame22 | 0:a9bcda5b678a | 6765 | } |
edamame22 | 0:a9bcda5b678a | 6766 | } |
edamame22 | 0:a9bcda5b678a | 6767 | if (source.charCodeAt(Index) == 34) { |
edamame22 | 0:a9bcda5b678a | 6768 | // Advance to the next character and return the revived string. |
edamame22 | 0:a9bcda5b678a | 6769 | Index++; |
edamame22 | 0:a9bcda5b678a | 6770 | return value; |
edamame22 | 0:a9bcda5b678a | 6771 | } |
edamame22 | 0:a9bcda5b678a | 6772 | // Unterminated string. |
edamame22 | 0:a9bcda5b678a | 6773 | abort(); |
edamame22 | 0:a9bcda5b678a | 6774 | default: |
edamame22 | 0:a9bcda5b678a | 6775 | // Parse numbers and literals. |
edamame22 | 0:a9bcda5b678a | 6776 | begin = Index; |
edamame22 | 0:a9bcda5b678a | 6777 | // Advance past the negative sign, if one is specified. |
edamame22 | 0:a9bcda5b678a | 6778 | if (charCode == 45) { |
edamame22 | 0:a9bcda5b678a | 6779 | isSigned = true; |
edamame22 | 0:a9bcda5b678a | 6780 | charCode = source.charCodeAt(++Index); |
edamame22 | 0:a9bcda5b678a | 6781 | } |
edamame22 | 0:a9bcda5b678a | 6782 | // Parse an integer or floating-point value. |
edamame22 | 0:a9bcda5b678a | 6783 | if (charCode >= 48 && charCode <= 57) { |
edamame22 | 0:a9bcda5b678a | 6784 | // Leading zeroes are interpreted as octal literals. |
edamame22 | 0:a9bcda5b678a | 6785 | if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { |
edamame22 | 0:a9bcda5b678a | 6786 | // Illegal octal literal. |
edamame22 | 0:a9bcda5b678a | 6787 | abort(); |
edamame22 | 0:a9bcda5b678a | 6788 | } |
edamame22 | 0:a9bcda5b678a | 6789 | isSigned = false; |
edamame22 | 0:a9bcda5b678a | 6790 | // Parse the integer component. |
edamame22 | 0:a9bcda5b678a | 6791 | for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); |
edamame22 | 0:a9bcda5b678a | 6792 | // Floats cannot contain a leading decimal point; however, this |
edamame22 | 0:a9bcda5b678a | 6793 | // case is already accounted for by the parser. |
edamame22 | 0:a9bcda5b678a | 6794 | if (source.charCodeAt(Index) == 46) { |
edamame22 | 0:a9bcda5b678a | 6795 | position = ++Index; |
edamame22 | 0:a9bcda5b678a | 6796 | // Parse the decimal component. |
edamame22 | 0:a9bcda5b678a | 6797 | for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); |
edamame22 | 0:a9bcda5b678a | 6798 | if (position == Index) { |
edamame22 | 0:a9bcda5b678a | 6799 | // Illegal trailing decimal. |
edamame22 | 0:a9bcda5b678a | 6800 | abort(); |
edamame22 | 0:a9bcda5b678a | 6801 | } |
edamame22 | 0:a9bcda5b678a | 6802 | Index = position; |
edamame22 | 0:a9bcda5b678a | 6803 | } |
edamame22 | 0:a9bcda5b678a | 6804 | // Parse exponents. The `e` denoting the exponent is |
edamame22 | 0:a9bcda5b678a | 6805 | // case-insensitive. |
edamame22 | 0:a9bcda5b678a | 6806 | charCode = source.charCodeAt(Index); |
edamame22 | 0:a9bcda5b678a | 6807 | if (charCode == 101 || charCode == 69) { |
edamame22 | 0:a9bcda5b678a | 6808 | charCode = source.charCodeAt(++Index); |
edamame22 | 0:a9bcda5b678a | 6809 | // Skip past the sign following the exponent, if one is |
edamame22 | 0:a9bcda5b678a | 6810 | // specified. |
edamame22 | 0:a9bcda5b678a | 6811 | if (charCode == 43 || charCode == 45) { |
edamame22 | 0:a9bcda5b678a | 6812 | Index++; |
edamame22 | 0:a9bcda5b678a | 6813 | } |
edamame22 | 0:a9bcda5b678a | 6814 | // Parse the exponential component. |
edamame22 | 0:a9bcda5b678a | 6815 | for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); |
edamame22 | 0:a9bcda5b678a | 6816 | if (position == Index) { |
edamame22 | 0:a9bcda5b678a | 6817 | // Illegal empty exponent. |
edamame22 | 0:a9bcda5b678a | 6818 | abort(); |
edamame22 | 0:a9bcda5b678a | 6819 | } |
edamame22 | 0:a9bcda5b678a | 6820 | Index = position; |
edamame22 | 0:a9bcda5b678a | 6821 | } |
edamame22 | 0:a9bcda5b678a | 6822 | // Coerce the parsed value to a JavaScript number. |
edamame22 | 0:a9bcda5b678a | 6823 | return +source.slice(begin, Index); |
edamame22 | 0:a9bcda5b678a | 6824 | } |
edamame22 | 0:a9bcda5b678a | 6825 | // A negative sign may only precede numbers. |
edamame22 | 0:a9bcda5b678a | 6826 | if (isSigned) { |
edamame22 | 0:a9bcda5b678a | 6827 | abort(); |
edamame22 | 0:a9bcda5b678a | 6828 | } |
edamame22 | 0:a9bcda5b678a | 6829 | // `true`, `false`, and `null` literals. |
edamame22 | 0:a9bcda5b678a | 6830 | if (source.slice(Index, Index + 4) == "true") { |
edamame22 | 0:a9bcda5b678a | 6831 | Index += 4; |
edamame22 | 0:a9bcda5b678a | 6832 | return true; |
edamame22 | 0:a9bcda5b678a | 6833 | } else if (source.slice(Index, Index + 5) == "false") { |
edamame22 | 0:a9bcda5b678a | 6834 | Index += 5; |
edamame22 | 0:a9bcda5b678a | 6835 | return false; |
edamame22 | 0:a9bcda5b678a | 6836 | } else if (source.slice(Index, Index + 4) == "null") { |
edamame22 | 0:a9bcda5b678a | 6837 | Index += 4; |
edamame22 | 0:a9bcda5b678a | 6838 | return null; |
edamame22 | 0:a9bcda5b678a | 6839 | } |
edamame22 | 0:a9bcda5b678a | 6840 | // Unrecognized token. |
edamame22 | 0:a9bcda5b678a | 6841 | abort(); |
edamame22 | 0:a9bcda5b678a | 6842 | } |
edamame22 | 0:a9bcda5b678a | 6843 | } |
edamame22 | 0:a9bcda5b678a | 6844 | // Return the sentinel `$` character if the parser has reached the end |
edamame22 | 0:a9bcda5b678a | 6845 | // of the source string. |
edamame22 | 0:a9bcda5b678a | 6846 | return "$"; |
edamame22 | 0:a9bcda5b678a | 6847 | }; |
edamame22 | 0:a9bcda5b678a | 6848 | |
edamame22 | 0:a9bcda5b678a | 6849 | // Internal: Parses a JSON `value` token. |
edamame22 | 0:a9bcda5b678a | 6850 | var get = function (value) { |
edamame22 | 0:a9bcda5b678a | 6851 | var results, hasMembers; |
edamame22 | 0:a9bcda5b678a | 6852 | if (value == "$") { |
edamame22 | 0:a9bcda5b678a | 6853 | // Unexpected end of input. |
edamame22 | 0:a9bcda5b678a | 6854 | abort(); |
edamame22 | 0:a9bcda5b678a | 6855 | } |
edamame22 | 0:a9bcda5b678a | 6856 | if (typeof value == "string") { |
edamame22 | 0:a9bcda5b678a | 6857 | if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { |
edamame22 | 0:a9bcda5b678a | 6858 | // Remove the sentinel `@` character. |
edamame22 | 0:a9bcda5b678a | 6859 | return value.slice(1); |
edamame22 | 0:a9bcda5b678a | 6860 | } |
edamame22 | 0:a9bcda5b678a | 6861 | // Parse object and array literals. |
edamame22 | 0:a9bcda5b678a | 6862 | if (value == "[") { |
edamame22 | 0:a9bcda5b678a | 6863 | // Parses a JSON array, returning a new JavaScript array. |
edamame22 | 0:a9bcda5b678a | 6864 | results = []; |
edamame22 | 0:a9bcda5b678a | 6865 | for (;; hasMembers || (hasMembers = true)) { |
edamame22 | 0:a9bcda5b678a | 6866 | value = lex(); |
edamame22 | 0:a9bcda5b678a | 6867 | // A closing square bracket marks the end of the array literal. |
edamame22 | 0:a9bcda5b678a | 6868 | if (value == "]") { |
edamame22 | 0:a9bcda5b678a | 6869 | break; |
edamame22 | 0:a9bcda5b678a | 6870 | } |
edamame22 | 0:a9bcda5b678a | 6871 | // If the array literal contains elements, the current token |
edamame22 | 0:a9bcda5b678a | 6872 | // should be a comma separating the previous element from the |
edamame22 | 0:a9bcda5b678a | 6873 | // next. |
edamame22 | 0:a9bcda5b678a | 6874 | if (hasMembers) { |
edamame22 | 0:a9bcda5b678a | 6875 | if (value == ",") { |
edamame22 | 0:a9bcda5b678a | 6876 | value = lex(); |
edamame22 | 0:a9bcda5b678a | 6877 | if (value == "]") { |
edamame22 | 0:a9bcda5b678a | 6878 | // Unexpected trailing `,` in array literal. |
edamame22 | 0:a9bcda5b678a | 6879 | abort(); |
edamame22 | 0:a9bcda5b678a | 6880 | } |
edamame22 | 0:a9bcda5b678a | 6881 | } else { |
edamame22 | 0:a9bcda5b678a | 6882 | // A `,` must separate each array element. |
edamame22 | 0:a9bcda5b678a | 6883 | abort(); |
edamame22 | 0:a9bcda5b678a | 6884 | } |
edamame22 | 0:a9bcda5b678a | 6885 | } |
edamame22 | 0:a9bcda5b678a | 6886 | // Elisions and leading commas are not permitted. |
edamame22 | 0:a9bcda5b678a | 6887 | if (value == ",") { |
edamame22 | 0:a9bcda5b678a | 6888 | abort(); |
edamame22 | 0:a9bcda5b678a | 6889 | } |
edamame22 | 0:a9bcda5b678a | 6890 | results.push(get(value)); |
edamame22 | 0:a9bcda5b678a | 6891 | } |
edamame22 | 0:a9bcda5b678a | 6892 | return results; |
edamame22 | 0:a9bcda5b678a | 6893 | } else if (value == "{") { |
edamame22 | 0:a9bcda5b678a | 6894 | // Parses a JSON object, returning a new JavaScript object. |
edamame22 | 0:a9bcda5b678a | 6895 | results = {}; |
edamame22 | 0:a9bcda5b678a | 6896 | for (;; hasMembers || (hasMembers = true)) { |
edamame22 | 0:a9bcda5b678a | 6897 | value = lex(); |
edamame22 | 0:a9bcda5b678a | 6898 | // A closing curly brace marks the end of the object literal. |
edamame22 | 0:a9bcda5b678a | 6899 | if (value == "}") { |
edamame22 | 0:a9bcda5b678a | 6900 | break; |
edamame22 | 0:a9bcda5b678a | 6901 | } |
edamame22 | 0:a9bcda5b678a | 6902 | // If the object literal contains members, the current token |
edamame22 | 0:a9bcda5b678a | 6903 | // should be a comma separator. |
edamame22 | 0:a9bcda5b678a | 6904 | if (hasMembers) { |
edamame22 | 0:a9bcda5b678a | 6905 | if (value == ",") { |
edamame22 | 0:a9bcda5b678a | 6906 | value = lex(); |
edamame22 | 0:a9bcda5b678a | 6907 | if (value == "}") { |
edamame22 | 0:a9bcda5b678a | 6908 | // Unexpected trailing `,` in object literal. |
edamame22 | 0:a9bcda5b678a | 6909 | abort(); |
edamame22 | 0:a9bcda5b678a | 6910 | } |
edamame22 | 0:a9bcda5b678a | 6911 | } else { |
edamame22 | 0:a9bcda5b678a | 6912 | // A `,` must separate each object member. |
edamame22 | 0:a9bcda5b678a | 6913 | abort(); |
edamame22 | 0:a9bcda5b678a | 6914 | } |
edamame22 | 0:a9bcda5b678a | 6915 | } |
edamame22 | 0:a9bcda5b678a | 6916 | // Leading commas are not permitted, object property names must be |
edamame22 | 0:a9bcda5b678a | 6917 | // double-quoted strings, and a `:` must separate each property |
edamame22 | 0:a9bcda5b678a | 6918 | // name and value. |
edamame22 | 0:a9bcda5b678a | 6919 | if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { |
edamame22 | 0:a9bcda5b678a | 6920 | abort(); |
edamame22 | 0:a9bcda5b678a | 6921 | } |
edamame22 | 0:a9bcda5b678a | 6922 | results[value.slice(1)] = get(lex()); |
edamame22 | 0:a9bcda5b678a | 6923 | } |
edamame22 | 0:a9bcda5b678a | 6924 | return results; |
edamame22 | 0:a9bcda5b678a | 6925 | } |
edamame22 | 0:a9bcda5b678a | 6926 | // Unexpected token encountered. |
edamame22 | 0:a9bcda5b678a | 6927 | abort(); |
edamame22 | 0:a9bcda5b678a | 6928 | } |
edamame22 | 0:a9bcda5b678a | 6929 | return value; |
edamame22 | 0:a9bcda5b678a | 6930 | }; |
edamame22 | 0:a9bcda5b678a | 6931 | |
edamame22 | 0:a9bcda5b678a | 6932 | // Internal: Updates a traversed object member. |
edamame22 | 0:a9bcda5b678a | 6933 | var update = function(source, property, callback) { |
edamame22 | 0:a9bcda5b678a | 6934 | var element = walk(source, property, callback); |
edamame22 | 0:a9bcda5b678a | 6935 | if (element === undef) { |
edamame22 | 0:a9bcda5b678a | 6936 | delete source[property]; |
edamame22 | 0:a9bcda5b678a | 6937 | } else { |
edamame22 | 0:a9bcda5b678a | 6938 | source[property] = element; |
edamame22 | 0:a9bcda5b678a | 6939 | } |
edamame22 | 0:a9bcda5b678a | 6940 | }; |
edamame22 | 0:a9bcda5b678a | 6941 | |
edamame22 | 0:a9bcda5b678a | 6942 | // Internal: Recursively traverses a parsed JSON object, invoking the |
edamame22 | 0:a9bcda5b678a | 6943 | // `callback` function for each value. This is an implementation of the |
edamame22 | 0:a9bcda5b678a | 6944 | // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2. |
edamame22 | 0:a9bcda5b678a | 6945 | var walk = function (source, property, callback) { |
edamame22 | 0:a9bcda5b678a | 6946 | var value = source[property], length; |
edamame22 | 0:a9bcda5b678a | 6947 | if (typeof value == "object" && value) { |
edamame22 | 0:a9bcda5b678a | 6948 | // `forEach` can't be used to traverse an array in Opera <= 8.54 |
edamame22 | 0:a9bcda5b678a | 6949 | // because its `Object#hasOwnProperty` implementation returns `false` |
edamame22 | 0:a9bcda5b678a | 6950 | // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`). |
edamame22 | 0:a9bcda5b678a | 6951 | if (getClass.call(value) == arrayClass) { |
edamame22 | 0:a9bcda5b678a | 6952 | for (length = value.length; length--;) { |
edamame22 | 0:a9bcda5b678a | 6953 | update(value, length, callback); |
edamame22 | 0:a9bcda5b678a | 6954 | } |
edamame22 | 0:a9bcda5b678a | 6955 | } else { |
edamame22 | 0:a9bcda5b678a | 6956 | forEach(value, function (property) { |
edamame22 | 0:a9bcda5b678a | 6957 | update(value, property, callback); |
edamame22 | 0:a9bcda5b678a | 6958 | }); |
edamame22 | 0:a9bcda5b678a | 6959 | } |
edamame22 | 0:a9bcda5b678a | 6960 | } |
edamame22 | 0:a9bcda5b678a | 6961 | return callback.call(source, property, value); |
edamame22 | 0:a9bcda5b678a | 6962 | }; |
edamame22 | 0:a9bcda5b678a | 6963 | |
edamame22 | 0:a9bcda5b678a | 6964 | // Public: `JSON.parse`. See ES 5.1 section 15.12.2. |
edamame22 | 0:a9bcda5b678a | 6965 | JSON3.parse = function (source, callback) { |
edamame22 | 0:a9bcda5b678a | 6966 | var result, value; |
edamame22 | 0:a9bcda5b678a | 6967 | Index = 0; |
edamame22 | 0:a9bcda5b678a | 6968 | Source = "" + source; |
edamame22 | 0:a9bcda5b678a | 6969 | result = get(lex()); |
edamame22 | 0:a9bcda5b678a | 6970 | // If a JSON string contains multiple tokens, it is invalid. |
edamame22 | 0:a9bcda5b678a | 6971 | if (lex() != "$") { |
edamame22 | 0:a9bcda5b678a | 6972 | abort(); |
edamame22 | 0:a9bcda5b678a | 6973 | } |
edamame22 | 0:a9bcda5b678a | 6974 | // Reset the parser state. |
edamame22 | 0:a9bcda5b678a | 6975 | Index = Source = null; |
edamame22 | 0:a9bcda5b678a | 6976 | return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; |
edamame22 | 0:a9bcda5b678a | 6977 | }; |
edamame22 | 0:a9bcda5b678a | 6978 | } |
edamame22 | 0:a9bcda5b678a | 6979 | } |
edamame22 | 0:a9bcda5b678a | 6980 | |
edamame22 | 0:a9bcda5b678a | 6981 | // Export for asynchronous module loaders. |
edamame22 | 0:a9bcda5b678a | 6982 | if (isLoader) { |
edamame22 | 0:a9bcda5b678a | 6983 | define(function () { |
edamame22 | 0:a9bcda5b678a | 6984 | return JSON3; |
edamame22 | 0:a9bcda5b678a | 6985 | }); |
edamame22 | 0:a9bcda5b678a | 6986 | } |
edamame22 | 0:a9bcda5b678a | 6987 | }(this)); |
edamame22 | 0:a9bcda5b678a | 6988 | |
edamame22 | 0:a9bcda5b678a | 6989 | },{}],50:[function(_dereq_,module,exports){ |
edamame22 | 0:a9bcda5b678a | 6990 | module.exports = toArray |
edamame22 | 0:a9bcda5b678a | 6991 | |
edamame22 | 0:a9bcda5b678a | 6992 | function toArray(list, index) { |
edamame22 | 0:a9bcda5b678a | 6993 | var array = [] |
edamame22 | 0:a9bcda5b678a | 6994 | |
edamame22 | 0:a9bcda5b678a | 6995 | index = index || 0 |
edamame22 | 0:a9bcda5b678a | 6996 | |
edamame22 | 0:a9bcda5b678a | 6997 | for (var i = index || 0; i < list.length; i++) { |
edamame22 | 0:a9bcda5b678a | 6998 | array[i - index] = list[i] |
edamame22 | 0:a9bcda5b678a | 6999 | } |
edamame22 | 0:a9bcda5b678a | 7000 | |
edamame22 | 0:a9bcda5b678a | 7001 | return array |
edamame22 | 0:a9bcda5b678a | 7002 | } |
edamame22 | 0:a9bcda5b678a | 7003 | |
edamame22 | 0:a9bcda5b678a | 7004 | },{}]},{},[1]) |
edamame22 | 0:a9bcda5b678a | 7005 | (1) |
edamame22 | 0:a9bcda5b678a | 7006 | }); |