Created
November 9, 2022 10:08
-
-
Save akari0624/f159aea17bb552c83168f3d397a2d339 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Socket.IO v4.5.3 | |
* (c) 2014-2022 Guillermo Rauch | |
* Released under the MIT License. | |
*/ | |
(function(global, factory) { | |
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | |
typeof define === 'function' && define.amd ? define(factory) : | |
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.acyOfficialWebsiteUseIO = factory()); | |
})(this, (function() { | |
'use strict'; | |
function _typeof(obj) { | |
"@babel/helpers - typeof"; | |
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) { | |
return typeof obj; | |
} : function(obj) { | |
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; | |
}, _typeof(obj); | |
} | |
function _classCallCheck(instance, Constructor) { | |
if (!(instance instanceof Constructor)) { | |
throw new TypeError("Cannot call a class as a function"); | |
} | |
} | |
function _defineProperties(target, props) { | |
for (var i = 0; i < props.length; i++) { | |
var descriptor = props[i]; | |
descriptor.enumerable = descriptor.enumerable || false; | |
descriptor.configurable = true; | |
if ("value" in descriptor) descriptor.writable = true; | |
Object.defineProperty(target, descriptor.key, descriptor); | |
} | |
} | |
function _createClass(Constructor, protoProps, staticProps) { | |
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |
if (staticProps) _defineProperties(Constructor, staticProps); | |
Object.defineProperty(Constructor, "prototype", { | |
writable: false | |
}); | |
return Constructor; | |
} | |
function _extends() { | |
_extends = Object.assign ? Object.assign.bind() : function(target) { | |
for (var i = 1; i < arguments.length; i++) { | |
var source = arguments[i]; | |
for (var key in source) { | |
if (Object.prototype.hasOwnProperty.call(source, key)) { | |
target[key] = source[key]; | |
} | |
} | |
} | |
return target; | |
}; | |
return _extends.apply(this, arguments); | |
} | |
function _inherits(subClass, superClass) { | |
if (typeof superClass !== "function" && superClass !== null) { | |
throw new TypeError("Super expression must either be null or a function"); | |
} | |
subClass.prototype = Object.create(superClass && superClass.prototype, { | |
constructor: { | |
value: subClass, | |
writable: true, | |
configurable: true | |
} | |
}); | |
Object.defineProperty(subClass, "prototype", { | |
writable: false | |
}); | |
if (superClass) _setPrototypeOf(subClass, superClass); | |
} | |
function _getPrototypeOf(o) { | |
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { | |
return o.__proto__ || Object.getPrototypeOf(o); | |
}; | |
return _getPrototypeOf(o); | |
} | |
function _setPrototypeOf(o, p) { | |
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { | |
o.__proto__ = p; | |
return o; | |
}; | |
return _setPrototypeOf(o, p); | |
} | |
function _isNativeReflectConstruct() { | |
if (typeof Reflect === "undefined" || !Reflect.construct) return false; | |
if (Reflect.construct.sham) return false; | |
if (typeof Proxy === "function") return true; | |
try { | |
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {})); | |
return true; | |
} catch (e) { | |
return false; | |
} | |
} | |
function _construct(Parent, args, Class) { | |
if (_isNativeReflectConstruct()) { | |
_construct = Reflect.construct.bind(); | |
} else { | |
_construct = function _construct(Parent, args, Class) { | |
var a = [null]; | |
a.push.apply(a, args); | |
var Constructor = Function.bind.apply(Parent, a); | |
var instance = new Constructor(); | |
if (Class) _setPrototypeOf(instance, Class.prototype); | |
return instance; | |
}; | |
} | |
return _construct.apply(null, arguments); | |
} | |
function _isNativeFunction(fn) { | |
return Function.toString.call(fn).indexOf("[native code]") !== -1; | |
} | |
function _wrapNativeSuper(Class) { | |
var _cache = typeof Map === "function" ? new Map() : undefined; | |
_wrapNativeSuper = function _wrapNativeSuper(Class) { | |
if (Class === null || !_isNativeFunction(Class)) return Class; | |
if (typeof Class !== "function") { | |
throw new TypeError("Super expression must either be null or a function"); | |
} | |
if (typeof _cache !== "undefined") { | |
if (_cache.has(Class)) return _cache.get(Class); | |
_cache.set(Class, Wrapper); | |
} | |
function Wrapper() { | |
return _construct(Class, arguments, _getPrototypeOf(this).constructor); | |
} | |
Wrapper.prototype = Object.create(Class.prototype, { | |
constructor: { | |
value: Wrapper, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
return _setPrototypeOf(Wrapper, Class); | |
}; | |
return _wrapNativeSuper(Class); | |
} | |
function _assertThisInitialized(self) { | |
if (self === void 0) { | |
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | |
} | |
return self; | |
} | |
function _possibleConstructorReturn(self, call) { | |
if (call && (typeof call === "object" || typeof call === "function")) { | |
return call; | |
} else if (call !== void 0) { | |
throw new TypeError("Derived constructors may only return object or undefined"); | |
} | |
return _assertThisInitialized(self); | |
} | |
function _createSuper(Derived) { | |
var hasNativeReflectConstruct = _isNativeReflectConstruct(); | |
return function _createSuperInternal() { | |
var Super = _getPrototypeOf(Derived), | |
result; | |
if (hasNativeReflectConstruct) { | |
var NewTarget = _getPrototypeOf(this).constructor; | |
result = Reflect.construct(Super, arguments, NewTarget); | |
} else { | |
result = Super.apply(this, arguments); | |
} | |
return _possibleConstructorReturn(this, result); | |
}; | |
} | |
function _superPropBase(object, property) { | |
while (!Object.prototype.hasOwnProperty.call(object, property)) { | |
object = _getPrototypeOf(object); | |
if (object === null) break; | |
} | |
return object; | |
} | |
function _get() { | |
if (typeof Reflect !== "undefined" && Reflect.get) { | |
_get = Reflect.get.bind(); | |
} else { | |
_get = function _get(target, property, receiver) { | |
var base = _superPropBase(target, property); | |
if (!base) return; | |
var desc = Object.getOwnPropertyDescriptor(base, property); | |
if (desc.get) { | |
return desc.get.call(arguments.length < 3 ? target : receiver); | |
} | |
return desc.value; | |
}; | |
} | |
return _get.apply(this, arguments); | |
} | |
function _unsupportedIterableToArray(o, minLen) { | |
if (!o) return; | |
if (typeof o === "string") return _arrayLikeToArray(o, minLen); | |
var n = Object.prototype.toString.call(o).slice(8, -1); | |
if (n === "Object" && o.constructor) n = o.constructor.name; | |
if (n === "Map" || n === "Set") return Array.from(o); | |
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); | |
} | |
function _arrayLikeToArray(arr, len) { | |
if (len == null || len > arr.length) len = arr.length; | |
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; | |
return arr2; | |
} | |
function _createForOfIteratorHelper(o, allowArrayLike) { | |
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; | |
if (!it) { | |
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { | |
if (it) o = it; | |
var i = 0; | |
var F = function() {}; | |
return { | |
s: F, | |
n: function() { | |
if (i >= o.length) return { | |
done: true | |
}; | |
return { | |
done: false, | |
value: o[i++] | |
}; | |
}, | |
e: function(e) { | |
throw e; | |
}, | |
f: F | |
}; | |
} | |
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); | |
} | |
var normalCompletion = true, | |
didErr = false, | |
err; | |
return { | |
s: function() { | |
it = it.call(o); | |
}, | |
n: function() { | |
var step = it.next(); | |
normalCompletion = step.done; | |
return step; | |
}, | |
e: function(e) { | |
didErr = true; | |
err = e; | |
}, | |
f: function() { | |
try { | |
if (!normalCompletion && it.return != null) it.return(); | |
} finally { | |
if (didErr) throw err; | |
} | |
} | |
}; | |
} | |
var PACKET_TYPES = Object.create(null); // no Map = no polyfill | |
PACKET_TYPES["open"] = "0"; | |
PACKET_TYPES["close"] = "1"; | |
PACKET_TYPES["ping"] = "2"; | |
PACKET_TYPES["pong"] = "3"; | |
PACKET_TYPES["message"] = "4"; | |
PACKET_TYPES["upgrade"] = "5"; | |
PACKET_TYPES["noop"] = "6"; | |
var PACKET_TYPES_REVERSE = Object.create(null); | |
Object.keys(PACKET_TYPES).forEach(function(key) { | |
PACKET_TYPES_REVERSE[PACKET_TYPES[key]] = key; | |
}); | |
var ERROR_PACKET = { | |
type: "error", | |
data: "parser error" | |
}; | |
var withNativeBlob$1 = typeof Blob === "function" || typeof Blob !== "undefined" && Object.prototype.toString.call(Blob) === "[object BlobConstructor]"; | |
var withNativeArrayBuffer$2 = typeof ArrayBuffer === "function"; // ArrayBuffer.isView method is not defined in IE10 | |
var isView$1 = function isView(obj) { | |
return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj && obj.buffer instanceof ArrayBuffer; | |
}; | |
var encodePacket = function encodePacket(_ref, supportsBinary, callback) { | |
var type = _ref.type, | |
data = _ref.data; | |
if (withNativeBlob$1 && data instanceof Blob) { | |
if (supportsBinary) { | |
return callback(data); | |
} else { | |
return encodeBlobAsBase64(data, callback); | |
} | |
} else if (withNativeArrayBuffer$2 && (data instanceof ArrayBuffer || isView$1(data))) { | |
if (supportsBinary) { | |
return callback(data); | |
} else { | |
return encodeBlobAsBase64(new Blob([data]), callback); | |
} | |
} // plain string | |
return callback(PACKET_TYPES[type] + (data || "")); | |
}; | |
var encodeBlobAsBase64 = function encodeBlobAsBase64(data, callback) { | |
var fileReader = new FileReader(); | |
fileReader.onload = function() { | |
var content = fileReader.result.split(",")[1]; | |
callback("b" + content); | |
}; | |
return fileReader.readAsDataURL(data); | |
}; | |
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; // Use a lookup table to find the index. | |
var lookup$1 = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256); | |
for (var i$1 = 0; i$1 < chars.length; i$1++) { | |
lookup$1[chars.charCodeAt(i$1)] = i$1; | |
} | |
var decode$1 = function decode(base64) { | |
var bufferLength = base64.length * 0.75, | |
len = base64.length, | |
i, | |
p = 0, | |
encoded1, | |
encoded2, | |
encoded3, | |
encoded4; | |
if (base64[base64.length - 1] === '=') { | |
bufferLength--; | |
if (base64[base64.length - 2] === '=') { | |
bufferLength--; | |
} | |
} | |
var arraybuffer = new ArrayBuffer(bufferLength), | |
bytes = new Uint8Array(arraybuffer); | |
for (i = 0; i < len; i += 4) { | |
encoded1 = lookup$1[base64.charCodeAt(i)]; | |
encoded2 = lookup$1[base64.charCodeAt(i + 1)]; | |
encoded3 = lookup$1[base64.charCodeAt(i + 2)]; | |
encoded4 = lookup$1[base64.charCodeAt(i + 3)]; | |
bytes[p++] = encoded1 << 2 | encoded2 >> 4; | |
bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2; | |
bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63; | |
} | |
return arraybuffer; | |
}; | |
var withNativeArrayBuffer$1 = typeof ArrayBuffer === "function"; | |
var decodePacket = function decodePacket(encodedPacket, binaryType) { | |
if (typeof encodedPacket !== "string") { | |
return { | |
type: "message", | |
data: mapBinary(encodedPacket, binaryType) | |
}; | |
} | |
var type = encodedPacket.charAt(0); | |
if (type === "b") { | |
return { | |
type: "message", | |
data: decodeBase64Packet(encodedPacket.substring(1), binaryType) | |
}; | |
} | |
var packetType = PACKET_TYPES_REVERSE[type]; | |
if (!packetType) { | |
return ERROR_PACKET; | |
} | |
return encodedPacket.length > 1 ? { | |
type: PACKET_TYPES_REVERSE[type], | |
data: encodedPacket.substring(1) | |
} : { | |
type: PACKET_TYPES_REVERSE[type] | |
}; | |
}; | |
var decodeBase64Packet = function decodeBase64Packet(data, binaryType) { | |
if (withNativeArrayBuffer$1) { | |
var decoded = decode$1(data); | |
return mapBinary(decoded, binaryType); | |
} else { | |
return { | |
base64: true, | |
data: data | |
}; // fallback for old browsers | |
} | |
}; | |
var mapBinary = function mapBinary(data, binaryType) { | |
switch (binaryType) { | |
case "blob": | |
return data instanceof ArrayBuffer ? new Blob([data]) : data; | |
case "arraybuffer": | |
default: | |
return data; | |
// assuming the data is already an ArrayBuffer | |
} | |
}; | |
var SEPARATOR = String.fromCharCode(30); // see https://en.wikipedia.org/wiki/Delimiter#ASCII_delimited_text | |
var encodePayload = function encodePayload(packets, callback) { | |
// some packets may be added to the array while encoding, so the initial length must be saved | |
var length = packets.length; | |
var encodedPackets = new Array(length); | |
var count = 0; | |
packets.forEach(function(packet, i) { | |
// force base64 encoding for binary packets | |
encodePacket(packet, false, function(encodedPacket) { | |
encodedPackets[i] = encodedPacket; | |
if (++count === length) { | |
callback(encodedPackets.join(SEPARATOR)); | |
} | |
}); | |
}); | |
}; | |
var decodePayload = function decodePayload(encodedPayload, binaryType) { | |
var encodedPackets = encodedPayload.split(SEPARATOR); | |
var packets = []; | |
for (var i = 0; i < encodedPackets.length; i++) { | |
var decodedPacket = decodePacket(encodedPackets[i], binaryType); | |
packets.push(decodedPacket); | |
if (decodedPacket.type === "error") { | |
break; | |
} | |
} | |
return packets; | |
}; | |
var protocol$1 = 4; | |
/** | |
* Initialize a new `Emitter`. | |
* | |
* @api public | |
*/ | |
function Emitter(obj) { | |
if (obj) return mixin(obj); | |
} | |
/** | |
* Mixin the emitter properties. | |
* | |
* @param {Object} obj | |
* @return {Object} | |
* @api private | |
*/ | |
function mixin(obj) { | |
for (var key in Emitter.prototype) { | |
obj[key] = Emitter.prototype[key]; | |
} | |
return obj; | |
} | |
/** | |
* Listen on the given `event` with `fn`. | |
* | |
* @param {String} event | |
* @param {Function} fn | |
* @return {Emitter} | |
* @api public | |
*/ | |
Emitter.prototype.on = Emitter.prototype.addEventListener = function(event, fn) { | |
this._callbacks = this._callbacks || {}; | |
(this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn); | |
return this; | |
}; | |
/** | |
* Adds an `event` listener that will be invoked a single | |
* time then automatically removed. | |
* | |
* @param {String} event | |
* @param {Function} fn | |
* @return {Emitter} | |
* @api public | |
*/ | |
Emitter.prototype.once = function(event, fn) { | |
function on() { | |
this.off(event, on); | |
fn.apply(this, arguments); | |
} | |
on.fn = fn; | |
this.on(event, on); | |
return this; | |
}; | |
/** | |
* Remove the given callback for `event` or all | |
* registered callbacks. | |
* | |
* @param {String} event | |
* @param {Function} fn | |
* @return {Emitter} | |
* @api public | |
*/ | |
Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function(event, fn) { | |
this._callbacks = this._callbacks || {}; // all | |
if (0 == arguments.length) { | |
this._callbacks = {}; | |
return this; | |
} // specific event | |
var callbacks = this._callbacks['$' + event]; | |
if (!callbacks) return this; // remove all handlers | |
if (1 == arguments.length) { | |
delete this._callbacks['$' + event]; | |
return this; | |
} // remove specific handler | |
var cb; | |
for (var i = 0; i < callbacks.length; i++) { | |
cb = callbacks[i]; | |
if (cb === fn || cb.fn === fn) { | |
callbacks.splice(i, 1); | |
break; | |
} | |
} // Remove event specific arrays for event types that no | |
// one is subscribed for to avoid memory leak. | |
if (callbacks.length === 0) { | |
delete this._callbacks['$' + event]; | |
} | |
return this; | |
}; | |
/** | |
* Emit `event` with the given args. | |
* | |
* @param {String} event | |
* @param {Mixed} ... | |
* @return {Emitter} | |
*/ | |
Emitter.prototype.emit = function(event) { | |
this._callbacks = this._callbacks || {}; | |
var args = new Array(arguments.length - 1), | |
callbacks = this._callbacks['$' + event]; | |
for (var i = 1; i < arguments.length; i++) { | |
args[i - 1] = arguments[i]; | |
} | |
if (callbacks) { | |
callbacks = callbacks.slice(0); | |
for (var i = 0, len = callbacks.length; i < len; ++i) { | |
callbacks[i].apply(this, args); | |
} | |
} | |
return this; | |
}; // alias used for reserved events (protected method) | |
Emitter.prototype.emitReserved = Emitter.prototype.emit; | |
/** | |
* Return array of callbacks for `event`. | |
* | |
* @param {String} event | |
* @return {Array} | |
* @api public | |
*/ | |
Emitter.prototype.listeners = function(event) { | |
this._callbacks = this._callbacks || {}; | |
return this._callbacks['$' + event] || []; | |
}; | |
/** | |
* Check if this emitter has `event` handlers. | |
* | |
* @param {String} event | |
* @return {Boolean} | |
* @api public | |
*/ | |
Emitter.prototype.hasListeners = function(event) { | |
return !!this.listeners(event).length; | |
}; | |
var globalThisShim = function() { | |
if (typeof self !== "undefined") { | |
return self; | |
} else if (typeof window !== "undefined") { | |
return window; | |
} else { | |
return Function("return this")(); | |
} | |
}(); | |
function pick(obj) { | |
for (var _len = arguments.length, attr = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | |
attr[_key - 1] = arguments[_key]; | |
} | |
return attr.reduce(function(acc, k) { | |
if (obj.hasOwnProperty(k)) { | |
acc[k] = obj[k]; | |
} | |
return acc; | |
}, {}); | |
} // Keep a reference to the real timeout functions so they can be used when overridden | |
var NATIVE_SET_TIMEOUT = setTimeout; | |
var NATIVE_CLEAR_TIMEOUT = clearTimeout; | |
function installTimerFunctions(obj, opts) { | |
if (opts.useNativeTimers) { | |
obj.setTimeoutFn = NATIVE_SET_TIMEOUT.bind(globalThisShim); | |
obj.clearTimeoutFn = NATIVE_CLEAR_TIMEOUT.bind(globalThisShim); | |
} else { | |
obj.setTimeoutFn = setTimeout.bind(globalThisShim); | |
obj.clearTimeoutFn = clearTimeout.bind(globalThisShim); | |
} | |
} // base64 encoded buffers are about 33% bigger (https://en.wikipedia.org/wiki/Base64) | |
var BASE64_OVERHEAD = 1.33; // we could also have used `new Blob([obj]).size`, but it isn't supported in IE9 | |
function byteLength(obj) { | |
if (typeof obj === "string") { | |
return utf8Length(obj); | |
} // arraybuffer or blob | |
return Math.ceil((obj.byteLength || obj.size) * BASE64_OVERHEAD); | |
} | |
function utf8Length(str) { | |
var c = 0, | |
length = 0; | |
for (var i = 0, l = str.length; i < l; i++) { | |
c = str.charCodeAt(i); | |
if (c < 0x80) { | |
length += 1; | |
} else if (c < 0x800) { | |
length += 2; | |
} else if (c < 0xd800 || c >= 0xe000) { | |
length += 3; | |
} else { | |
i++; | |
length += 4; | |
} | |
} | |
return length; | |
} | |
var TransportError = /*#__PURE__*/ function(_Error) { | |
_inherits(TransportError, _Error); | |
var _super = _createSuper(TransportError); | |
function TransportError(reason, description, context) { | |
var _this; | |
_classCallCheck(this, TransportError); | |
_this = _super.call(this, reason); | |
_this.description = description; | |
_this.context = context; | |
_this.type = "TransportError"; | |
return _this; | |
} | |
return _createClass(TransportError); | |
}( /*#__PURE__*/ _wrapNativeSuper(Error)); | |
var Transport = /*#__PURE__*/ function(_Emitter) { | |
_inherits(Transport, _Emitter); | |
var _super2 = _createSuper(Transport); | |
/** | |
* Transport abstract constructor. | |
* | |
* @param {Object} options. | |
* @api private | |
*/ | |
function Transport(opts) { | |
var _this2; | |
_classCallCheck(this, Transport); | |
_this2 = _super2.call(this); | |
_this2.writable = false; | |
installTimerFunctions(_assertThisInitialized(_this2), opts); | |
_this2.opts = opts; | |
_this2.query = opts.query; | |
_this2.readyState = ""; | |
_this2.socket = opts.socket; | |
return _this2; | |
} | |
/** | |
* Emits an error. | |
* | |
* @param {String} reason | |
* @param description | |
* @param context - the error context | |
* @return {Transport} for chaining | |
* @api protected | |
*/ | |
_createClass(Transport, [{ | |
key: "onError", | |
value: function onError(reason, description, context) { | |
_get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "error", new TransportError(reason, description, context)); | |
return this; | |
} | |
/** | |
* Opens the transport. | |
* | |
* @api public | |
*/ | |
}, { | |
key: "open", | |
value: function open() { | |
if ("closed" === this.readyState || "" === this.readyState) { | |
this.readyState = "opening"; | |
this.doOpen(); | |
} | |
return this; | |
} | |
/** | |
* Closes the transport. | |
* | |
* @api public | |
*/ | |
}, { | |
key: "close", | |
value: function close() { | |
if ("opening" === this.readyState || "open" === this.readyState) { | |
this.doClose(); | |
this.onClose(); | |
} | |
return this; | |
} | |
/** | |
* Sends multiple packets. | |
* | |
* @param {Array} packets | |
* @api public | |
*/ | |
}, { | |
key: "send", | |
value: function send(packets) { | |
if ("open" === this.readyState) { | |
this.write(packets); | |
} | |
} | |
/** | |
* Called upon open | |
* | |
* @api protected | |
*/ | |
}, { | |
key: "onOpen", | |
value: function onOpen() { | |
this.readyState = "open"; | |
this.writable = true; | |
_get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "open"); | |
} | |
/** | |
* Called with data. | |
* | |
* @param {String} data | |
* @api protected | |
*/ | |
}, { | |
key: "onData", | |
value: function onData(data) { | |
var packet = decodePacket(data, this.socket.binaryType); | |
this.onPacket(packet); | |
} | |
/** | |
* Called with a decoded packet. | |
* | |
* @api protected | |
*/ | |
}, { | |
key: "onPacket", | |
value: function onPacket(packet) { | |
_get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "packet", packet); | |
} | |
/** | |
* Called upon close. | |
* | |
* @api protected | |
*/ | |
}, { | |
key: "onClose", | |
value: function onClose(details) { | |
this.readyState = "closed"; | |
_get(_getPrototypeOf(Transport.prototype), "emitReserved", this).call(this, "close", details); | |
} | |
}]); | |
return Transport; | |
}(Emitter); | |
// imported from https://github.com/unshiftio/yeast | |
var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split(''), | |
length = 64, | |
map = {}; | |
var seed = 0, | |
i = 0, | |
prev; | |
/** | |
* Return a string representing the specified number. | |
* | |
* @param {Number} num The number to convert. | |
* @returns {String} The string representation of the number. | |
* @api public | |
*/ | |
function encode$1(num) { | |
var encoded = ''; | |
do { | |
encoded = alphabet[num % length] + encoded; | |
num = Math.floor(num / length); | |
} while (num > 0); | |
return encoded; | |
} | |
/** | |
* Yeast: A tiny growing id generator. | |
* | |
* @returns {String} A unique id. | |
* @api public | |
*/ | |
function yeast() { | |
var now = encode$1(+new Date()); | |
if (now !== prev) return seed = 0, prev = now; | |
return now + '.' + encode$1(seed++); | |
} // | |
// Map each character to its index. | |
// | |
for (; i < length; i++) { | |
map[alphabet[i]] = i; | |
} | |
// imported from https://github.com/galkn/querystring | |
/** | |
* Compiles a querystring | |
* Returns string representation of the object | |
* | |
* @param {Object} | |
* @api private | |
*/ | |
function encode(obj) { | |
var str = ''; | |
for (var i in obj) { | |
if (obj.hasOwnProperty(i)) { | |
if (str.length) str += '&'; | |
str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]); | |
} | |
} | |
return str; | |
} | |
/** | |
* Parses a simple querystring into an object | |
* | |
* @param {String} qs | |
* @api private | |
*/ | |
function decode(qs) { | |
var qry = {}; | |
var pairs = qs.split('&'); | |
for (var i = 0, l = pairs.length; i < l; i++) { | |
var pair = pairs[i].split('='); | |
qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); | |
} | |
return qry; | |
} | |
// imported from https://github.com/component/has-cors | |
var value = false; | |
try { | |
value = typeof XMLHttpRequest !== 'undefined' && 'withCredentials' in new XMLHttpRequest(); | |
} catch (err) { // if XMLHttp support is disabled in IE then it will throw | |
// when trying to create | |
} | |
var hasCORS = value; | |
// browser shim for xmlhttprequest module | |
function XHR(opts) { | |
var xdomain = opts.xdomain; // XMLHttpRequest can be disabled on IE | |
try { | |
if ("undefined" !== typeof XMLHttpRequest && (!xdomain || hasCORS)) { | |
return new XMLHttpRequest(); | |
} | |
} catch (e) {} | |
if (!xdomain) { | |
try { | |
return new globalThisShim[["Active"].concat("Object").join("X")]("Microsoft.XMLHTTP"); | |
} catch (e) {} | |
} | |
} | |
function empty() {} | |
var hasXHR2 = function() { | |
var xhr = new XHR({ | |
xdomain: false | |
}); | |
return null != xhr.responseType; | |
}(); | |
var Polling = /*#__PURE__*/ function(_Transport) { | |
_inherits(Polling, _Transport); | |
var _super = _createSuper(Polling); | |
/** | |
* XHR Polling constructor. | |
* | |
* @param {Object} opts | |
* @api public | |
*/ | |
function Polling(opts) { | |
var _this; | |
_classCallCheck(this, Polling); | |
_this = _super.call(this, opts); | |
_this.polling = false; | |
if (typeof location !== "undefined") { | |
var isSSL = "https:" === location.protocol; | |
var port = location.port; // some user agents have empty `location.port` | |
if (!port) { | |
port = isSSL ? "443" : "80"; | |
} | |
_this.xd = typeof location !== "undefined" && opts.hostname !== location.hostname || port !== opts.port; | |
_this.xs = opts.secure !== isSSL; | |
} | |
/** | |
* XHR supports binary | |
*/ | |
var forceBase64 = opts && opts.forceBase64; | |
_this.supportsBinary = hasXHR2 && !forceBase64; | |
return _this; | |
} | |
/** | |
* Transport name. | |
*/ | |
_createClass(Polling, [{ | |
key: "name", | |
get: function get() { | |
return "polling"; | |
} | |
/** | |
* Opens the socket (triggers polling). We write a PING message to determine | |
* when the transport is open. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "doOpen", | |
value: function doOpen() { | |
this.poll(); | |
} | |
/** | |
* Pauses polling. | |
* | |
* @param {Function} callback upon buffers are flushed and transport is paused | |
* @api private | |
*/ | |
}, { | |
key: "pause", | |
value: function pause(onPause) { | |
var _this2 = this; | |
this.readyState = "pausing"; | |
var pause = function pause() { | |
_this2.readyState = "paused"; | |
onPause(); | |
}; | |
if (this.polling || !this.writable) { | |
var total = 0; | |
if (this.polling) { | |
total++; | |
this.once("pollComplete", function() { | |
--total || pause(); | |
}); | |
} | |
if (!this.writable) { | |
total++; | |
this.once("drain", function() { | |
--total || pause(); | |
}); | |
} | |
} else { | |
pause(); | |
} | |
} | |
/** | |
* Starts polling cycle. | |
* | |
* @api public | |
*/ | |
}, { | |
key: "poll", | |
value: function poll() { | |
this.polling = true; | |
this.doPoll(); | |
this.emitReserved("poll"); | |
} | |
/** | |
* Overloads onData to detect payloads. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onData", | |
value: function onData(data) { | |
var _this3 = this; | |
var callback = function callback(packet) { | |
// if its the first message we consider the transport open | |
if ("opening" === _this3.readyState && packet.type === "open") { | |
_this3.onOpen(); | |
} // if its a close packet, we close the ongoing requests | |
if ("close" === packet.type) { | |
_this3.onClose({ | |
description: "transport closed by the server" | |
}); | |
return false; | |
} // otherwise bypass onData and handle the message | |
_this3.onPacket(packet); | |
}; // decode payload | |
decodePayload(data, this.socket.binaryType).forEach(callback); // if an event did not trigger closing | |
if ("closed" !== this.readyState) { | |
// if we got data we're not polling | |
this.polling = false; | |
this.emitReserved("pollComplete"); | |
if ("open" === this.readyState) { | |
this.poll(); | |
} | |
} | |
} | |
/** | |
* For polling, send a close packet. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "doClose", | |
value: function doClose() { | |
var _this4 = this; | |
var close = function close() { | |
_this4.write([{ | |
type: "close" | |
}]); | |
}; | |
if ("open" === this.readyState) { | |
close(); | |
} else { | |
// in case we're trying to close while | |
// handshaking is in progress (GH-164) | |
this.once("open", close); | |
} | |
} | |
/** | |
* Writes a packets payload. | |
* | |
* @param {Array} data packets | |
* @param {Function} drain callback | |
* @api private | |
*/ | |
}, { | |
key: "write", | |
value: function write(packets) { | |
var _this5 = this; | |
this.writable = false; | |
encodePayload(packets, function(data) { | |
_this5.doWrite(data, function() { | |
_this5.writable = true; | |
_this5.emitReserved("drain"); | |
}); | |
}); | |
} | |
/** | |
* Generates uri for connection. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "uri", | |
value: function uri() { | |
var query = this.query || {}; | |
var schema = this.opts.secure ? "https" : "http"; | |
var port = ""; // cache busting is forced | |
if (false !== this.opts.timestampRequests) { | |
query[this.opts.timestampParam] = yeast(); | |
} | |
if (!this.supportsBinary && !query.sid) { | |
query.b64 = 1; | |
} // avoid port if default for schema | |
if (this.opts.port && ("https" === schema && Number(this.opts.port) !== 443 || "http" === schema && Number(this.opts.port) !== 80)) { | |
port = ":" + this.opts.port; | |
} | |
var encodedQuery = encode(query); | |
var ipv6 = this.opts.hostname.indexOf(":") !== -1; | |
return schema + "://" + (ipv6 ? "[" + this.opts.hostname + "]" : this.opts.hostname) + port + this.opts.path + (encodedQuery.length ? "?" + encodedQuery : ""); | |
} | |
/** | |
* Creates a request. | |
* | |
* @param {String} method | |
* @api private | |
*/ | |
}, { | |
key: "request", | |
value: function request() { | |
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | |
_extends(opts, { | |
xd: this.xd, | |
xs: this.xs | |
}, this.opts); | |
return new Request(this.uri(), opts); | |
} | |
/** | |
* Sends data. | |
* | |
* @param {String} data to send. | |
* @param {Function} called upon flush. | |
* @api private | |
*/ | |
}, { | |
key: "doWrite", | |
value: function doWrite(data, fn) { | |
var _this6 = this; | |
var req = this.request({ | |
method: "POST", | |
data: data | |
}); | |
req.on("success", fn); | |
req.on("error", function(xhrStatus, context) { | |
_this6.onError("xhr post error", xhrStatus, context); | |
}); | |
} | |
/** | |
* Starts a poll cycle. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "doPoll", | |
value: function doPoll() { | |
var _this7 = this; | |
var req = this.request(); | |
req.on("data", this.onData.bind(this)); | |
req.on("error", function(xhrStatus, context) { | |
_this7.onError("xhr poll error", xhrStatus, context); | |
}); | |
this.pollXhr = req; | |
} | |
}]); | |
return Polling; | |
}(Transport); | |
var Request = /*#__PURE__*/ function(_Emitter) { | |
_inherits(Request, _Emitter); | |
var _super2 = _createSuper(Request); | |
/** | |
* Request constructor | |
* | |
* @param {Object} options | |
* @api public | |
*/ | |
function Request(uri, opts) { | |
var _this8; | |
_classCallCheck(this, Request); | |
_this8 = _super2.call(this); | |
installTimerFunctions(_assertThisInitialized(_this8), opts); | |
_this8.opts = opts; | |
_this8.method = opts.method || "GET"; | |
_this8.uri = uri; | |
_this8.async = false !== opts.async; | |
_this8.data = undefined !== opts.data ? opts.data : null; | |
_this8.create(); | |
return _this8; | |
} | |
/** | |
* Creates the XHR object and sends the request. | |
* | |
* @api private | |
*/ | |
_createClass(Request, [{ | |
key: "create", | |
value: function create() { | |
var _this9 = this; | |
var opts = pick(this.opts, "agent", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "autoUnref"); | |
opts.xdomain = !!this.opts.xd; | |
opts.xscheme = !!this.opts.xs; | |
var xhr = this.xhr = new XHR(opts); | |
try { | |
xhr.open(this.method, this.uri, this.async); | |
try { | |
if (this.opts.extraHeaders) { | |
xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true); | |
for (var i in this.opts.extraHeaders) { | |
if (this.opts.extraHeaders.hasOwnProperty(i)) { | |
xhr.setRequestHeader(i, this.opts.extraHeaders[i]); | |
} | |
} | |
} | |
} catch (e) {} | |
if ("POST" === this.method) { | |
try { | |
xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8"); | |
} catch (e) {} | |
} | |
try { | |
xhr.setRequestHeader("Accept", "*/*"); | |
} catch (e) {} // ie6 check | |
if ("withCredentials" in xhr) { | |
xhr.withCredentials = this.opts.withCredentials; | |
} | |
if (this.opts.requestTimeout) { | |
xhr.timeout = this.opts.requestTimeout; | |
} | |
xhr.onreadystatechange = function() { | |
if (4 !== xhr.readyState) return; | |
if (200 === xhr.status || 1223 === xhr.status) { | |
_this9.onLoad(); | |
} else { | |
// make sure the `error` event handler that's user-set | |
// does not throw in the same tick and gets caught here | |
_this9.setTimeoutFn(function() { | |
_this9.onError(typeof xhr.status === "number" ? xhr.status : 0); | |
}, 0); | |
} | |
}; | |
xhr.send(this.data); | |
} catch (e) { | |
// Need to defer since .create() is called directly from the constructor | |
// and thus the 'error' event can only be only bound *after* this exception | |
// occurs. Therefore, also, we cannot throw here at all. | |
this.setTimeoutFn(function() { | |
_this9.onError(e); | |
}, 0); | |
return; | |
} | |
if (typeof document !== "undefined") { | |
this.index = Request.requestsCount++; | |
Request.requests[this.index] = this; | |
} | |
} | |
/** | |
* Called upon error. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onError", | |
value: function onError(err) { | |
this.emitReserved("error", err, this.xhr); | |
this.cleanup(true); | |
} | |
/** | |
* Cleans up house. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "cleanup", | |
value: function cleanup(fromError) { | |
if ("undefined" === typeof this.xhr || null === this.xhr) { | |
return; | |
} | |
this.xhr.onreadystatechange = empty; | |
if (fromError) { | |
try { | |
this.xhr.abort(); | |
} catch (e) {} | |
} | |
if (typeof document !== "undefined") { | |
delete Request.requests[this.index]; | |
} | |
this.xhr = null; | |
} | |
/** | |
* Called upon load. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onLoad", | |
value: function onLoad() { | |
var data = this.xhr.responseText; | |
if (data !== null) { | |
this.emitReserved("data", data); | |
this.emitReserved("success"); | |
this.cleanup(); | |
} | |
} | |
/** | |
* Aborts the request. | |
* | |
* @api public | |
*/ | |
}, { | |
key: "abort", | |
value: function abort() { | |
this.cleanup(); | |
} | |
}]); | |
return Request; | |
}(Emitter); | |
Request.requestsCount = 0; | |
Request.requests = {}; | |
/** | |
* Aborts pending requests when unloading the window. This is needed to prevent | |
* memory leaks (e.g. when using IE) and to ensure that no spurious error is | |
* emitted. | |
*/ | |
if (typeof document !== "undefined") { | |
// @ts-ignore | |
if (typeof attachEvent === "function") { | |
// @ts-ignore | |
attachEvent("onunload", unloadHandler); | |
} else if (typeof addEventListener === "function") { | |
var terminationEvent = "onpagehide" in globalThisShim ? "pagehide" : "unload"; | |
addEventListener(terminationEvent, unloadHandler, false); | |
} | |
} | |
function unloadHandler() { | |
for (var i in Request.requests) { | |
if (Request.requests.hasOwnProperty(i)) { | |
Request.requests[i].abort(); | |
} | |
} | |
} | |
var nextTick = function() { | |
var isPromiseAvailable = typeof Promise === "function" && typeof Promise.resolve === "function"; | |
if (isPromiseAvailable) { | |
return function(cb) { | |
return Promise.resolve().then(cb); | |
}; | |
} else { | |
return function(cb, setTimeoutFn) { | |
return setTimeoutFn(cb, 0); | |
}; | |
} | |
}(); | |
var WebSocket = globalThisShim.WebSocket || globalThisShim.MozWebSocket; | |
var usingBrowserWebSocket = true; | |
var defaultBinaryType = "arraybuffer"; | |
var isReactNative = typeof navigator !== "undefined" && typeof navigator.product === "string" && navigator.product.toLowerCase() === "reactnative"; | |
var WS = /*#__PURE__*/ function(_Transport) { | |
_inherits(WS, _Transport); | |
var _super = _createSuper(WS); | |
/** | |
* WebSocket transport constructor. | |
* | |
* @api {Object} connection options | |
* @api public | |
*/ | |
function WS(opts) { | |
var _this; | |
_classCallCheck(this, WS); | |
_this = _super.call(this, opts); | |
_this.supportsBinary = !opts.forceBase64; | |
return _this; | |
} | |
/** | |
* Transport name. | |
* | |
* @api public | |
*/ | |
_createClass(WS, [{ | |
key: "name", | |
get: function get() { | |
return "websocket"; | |
} | |
/** | |
* Opens socket. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "doOpen", | |
value: function doOpen() { | |
if (!this.check()) { | |
// let probe timeout | |
return; | |
} | |
var uri = this.uri(); | |
var protocols = this.opts.protocols; // React Native only supports the 'headers' option, and will print a warning if anything else is passed | |
var opts = isReactNative ? {} : pick(this.opts, "agent", "perMessageDeflate", "pfx", "key", "passphrase", "cert", "ca", "ciphers", "rejectUnauthorized", "localAddress", "protocolVersion", "origin", "maxPayload", "family", "checkServerIdentity"); | |
if (this.opts.extraHeaders) { | |
opts.headers = this.opts.extraHeaders; | |
} | |
try { | |
this.ws = usingBrowserWebSocket && !isReactNative ? protocols ? new WebSocket(uri, protocols) : new WebSocket(uri) : new WebSocket(uri, protocols, opts); | |
} catch (err) { | |
return this.emitReserved("error", err); | |
} | |
this.ws.binaryType = this.socket.binaryType || defaultBinaryType; | |
this.addEventListeners(); | |
} | |
/** | |
* Adds event listeners to the socket | |
* | |
* @api private | |
*/ | |
}, { | |
key: "addEventListeners", | |
value: function addEventListeners() { | |
var _this2 = this; | |
this.ws.onopen = function() { | |
if (_this2.opts.autoUnref) { | |
_this2.ws._socket.unref(); | |
} | |
_this2.onOpen(); | |
}; | |
this.ws.onclose = function(closeEvent) { | |
return _this2.onClose({ | |
description: "websocket connection closed", | |
context: closeEvent | |
}); | |
}; | |
this.ws.onmessage = function(ev) { | |
return _this2.onData(ev.data); | |
}; | |
this.ws.onerror = function(e) { | |
return _this2.onError("websocket error", e); | |
}; | |
} | |
/** | |
* Writes data to socket. | |
* | |
* @param {Array} array of packets. | |
* @api private | |
*/ | |
}, { | |
key: "write", | |
value: function write(packets) { | |
var _this3 = this; | |
this.writable = false; // encodePacket efficient as it uses WS framing | |
// no need for encodePayload | |
var _loop = function _loop(i) { | |
var packet = packets[i]; | |
var lastPacket = i === packets.length - 1; | |
encodePacket(packet, _this3.supportsBinary, function(data) { | |
// always create a new object (GH-437) | |
var opts = {}; | |
// have a chance of informing us about it yet, in that case send will | |
// throw an error | |
try { | |
if (usingBrowserWebSocket) { | |
// TypeError is thrown when passing the second argument on Safari | |
_this3.ws.send(data); | |
} | |
} catch (e) {} | |
if (lastPacket) { | |
// fake drain | |
// defer to next tick to allow Socket to clear writeBuffer | |
nextTick(function() { | |
_this3.writable = true; | |
_this3.emitReserved("drain"); | |
}, _this3.setTimeoutFn); | |
} | |
}); | |
}; | |
for (var i = 0; i < packets.length; i++) { | |
_loop(i); | |
} | |
} | |
/** | |
* Closes socket. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "doClose", | |
value: function doClose() { | |
if (typeof this.ws !== "undefined") { | |
this.ws.close(); | |
this.ws = null; | |
} | |
} | |
/** | |
* Generates uri for connection. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "uri", | |
value: function uri() { | |
var query = this.query || {}; | |
var schema = this.opts.secure ? "wss" : "ws"; | |
var port = ""; // avoid port if default for schema | |
if (this.opts.port && ("wss" === schema && Number(this.opts.port) !== 443 || "ws" === schema && Number(this.opts.port) !== 80)) { | |
port = ":" + this.opts.port; | |
} // append timestamp to URI | |
if (this.opts.timestampRequests) { | |
query[this.opts.timestampParam] = yeast(); | |
} // communicate binary support capabilities | |
if (!this.supportsBinary) { | |
query.b64 = 1; | |
} | |
var encodedQuery = encode(query); | |
var ipv6 = this.opts.hostname.indexOf(":") !== -1; | |
return schema + "://" + (ipv6 ? "[" + this.opts.hostname + "]" : this.opts.hostname) + port + this.opts.path + (encodedQuery.length ? "?" + encodedQuery : ""); | |
} | |
/** | |
* Feature detection for WebSocket. | |
* | |
* @return {Boolean} whether this transport is available. | |
* @api public | |
*/ | |
}, { | |
key: "check", | |
value: function check() { | |
return !!WebSocket; | |
} | |
}]); | |
return WS; | |
}(Transport); | |
var transports = { | |
websocket: WS, | |
polling: Polling | |
}; | |
// imported from https://github.com/galkn/parseuri | |
/** | |
* Parses an URI | |
* | |
* @author Steven Levithan <stevenlevithan.com> (MIT license) | |
* @api private | |
*/ | |
var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/; | |
var parts = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor']; | |
function parse(str) { | |
var src = str, | |
b = str.indexOf('['), | |
e = str.indexOf(']'); | |
if (b != -1 && e != -1) { | |
str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length); | |
} | |
var m = re.exec(str || ''), | |
uri = {}, | |
i = 14; | |
while (i--) { | |
uri[parts[i]] = m[i] || ''; | |
} | |
if (b != -1 && e != -1) { | |
uri.source = src; | |
uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':'); | |
uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':'); | |
uri.ipv6uri = true; | |
} | |
uri.pathNames = pathNames(uri, uri['path']); | |
uri.queryKey = queryKey(uri, uri['query']); | |
return uri; | |
} | |
function pathNames(obj, path) { | |
var regx = /\/{2,9}/g, | |
names = path.replace(regx, "/").split("/"); | |
if (path.slice(0, 1) == '/' || path.length === 0) { | |
names.splice(0, 1); | |
} | |
if (path.slice(-1) == '/') { | |
names.splice(names.length - 1, 1); | |
} | |
return names; | |
} | |
function queryKey(uri, query) { | |
var data = {}; | |
query.replace(/(?:^|&)([^&=]*)=?([^&]*)/g, function($0, $1, $2) { | |
if ($1) { | |
data[$1] = $2; | |
} | |
}); | |
return data; | |
} | |
var Socket$1 = /*#__PURE__*/ function(_Emitter) { | |
_inherits(Socket, _Emitter); | |
var _super = _createSuper(Socket); | |
/** | |
* Socket constructor. | |
* | |
* @param {String|Object} uri or options | |
* @param {Object} opts - options | |
* @api public | |
*/ | |
function Socket(uri) { | |
var _this; | |
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | |
_classCallCheck(this, Socket); | |
_this = _super.call(this); | |
if (uri && "object" === _typeof(uri)) { | |
opts = uri; | |
uri = null; | |
} | |
if (uri) { | |
uri = parse(uri); | |
opts.hostname = uri.host; | |
opts.secure = uri.protocol === "https" || uri.protocol === "wss"; | |
opts.port = uri.port; | |
if (uri.query) opts.query = uri.query; | |
} else if (opts.host) { | |
opts.hostname = parse(opts.host).host; | |
} | |
installTimerFunctions(_assertThisInitialized(_this), opts); | |
_this.secure = null != opts.secure ? opts.secure : typeof location !== "undefined" && "https:" === location.protocol; | |
if (opts.hostname && !opts.port) { | |
// if no port is specified manually, use the protocol default | |
opts.port = _this.secure ? "443" : "80"; | |
} | |
_this.hostname = opts.hostname || (typeof location !== "undefined" ? location.hostname : "localhost"); | |
_this.port = opts.port || (typeof location !== "undefined" && location.port ? location.port : _this.secure ? "443" : "80"); | |
_this.transports = opts.transports || ["polling", "websocket"]; | |
_this.readyState = ""; | |
_this.writeBuffer = []; | |
_this.prevBufferLen = 0; | |
_this.opts = _extends({ | |
path: "/engine.io", | |
agent: false, | |
withCredentials: false, | |
upgrade: true, | |
timestampParam: "t", | |
rememberUpgrade: false, | |
rejectUnauthorized: true, | |
perMessageDeflate: { | |
threshold: 1024 | |
}, | |
transportOptions: {}, | |
closeOnBeforeunload: true | |
}, opts); | |
_this.opts.path = _this.opts.path.replace(/\/$/, "") + "/"; | |
if (typeof _this.opts.query === "string") { | |
_this.opts.query = decode(_this.opts.query); | |
} // set on handshake | |
_this.id = null; | |
_this.upgrades = null; | |
_this.pingInterval = null; | |
_this.pingTimeout = null; // set on heartbeat | |
_this.pingTimeoutTimer = null; | |
if (typeof addEventListener === "function") { | |
if (_this.opts.closeOnBeforeunload) { | |
// Firefox closes the connection when the "beforeunload" event is emitted but not Chrome. This event listener | |
// ensures every browser behaves the same (no "disconnect" event at the Socket.IO level when the page is | |
// closed/reloaded) | |
_this.beforeunloadEventListener = function() { | |
if (_this.transport) { | |
// silently close the transport | |
_this.transport.removeAllListeners(); | |
_this.transport.close(); | |
} | |
}; | |
addEventListener("beforeunload", _this.beforeunloadEventListener, false); | |
} | |
if (_this.hostname !== "localhost") { | |
_this.offlineEventListener = function() { | |
_this.onClose("transport close", { | |
description: "network connection lost" | |
}); | |
}; | |
addEventListener("offline", _this.offlineEventListener, false); | |
} | |
} | |
_this.open(); | |
return _this; | |
} | |
/** | |
* Creates transport of the given type. | |
* | |
* @param {String} transport name | |
* @return {Transport} | |
* @api private | |
*/ | |
_createClass(Socket, [{ | |
key: "createTransport", | |
value: function createTransport(name) { | |
var query = _extends({}, this.opts.query); // append engine.io protocol identifier | |
query.EIO = protocol$1; // transport name | |
query.transport = name; // session id if we already have one | |
if (this.id) query.sid = this.id; | |
var opts = _extends({}, this.opts.transportOptions[name], this.opts, { | |
query: query, | |
socket: this, | |
hostname: this.hostname, | |
secure: this.secure, | |
port: this.port | |
}); | |
return new transports[name](opts); | |
} | |
/** | |
* Initializes transport to use and starts probe. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "open", | |
value: function open() { | |
var _this2 = this; | |
var transport; | |
if (this.opts.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf("websocket") !== -1) { | |
transport = "websocket"; | |
} else if (0 === this.transports.length) { | |
// Emit error on next tick so it can be listened to | |
this.setTimeoutFn(function() { | |
_this2.emitReserved("error", "No transports available"); | |
}, 0); | |
return; | |
} else { | |
transport = this.transports[0]; | |
} | |
this.readyState = "opening"; // Retry with the next transport if the transport is disabled (jsonp: false) | |
try { | |
transport = this.createTransport(transport); | |
} catch (e) { | |
this.transports.shift(); | |
this.open(); | |
return; | |
} | |
transport.open(); | |
this.setTransport(transport); | |
} | |
/** | |
* Sets the current transport. Disables the existing one (if any). | |
* | |
* @api private | |
*/ | |
}, { | |
key: "setTransport", | |
value: function setTransport(transport) { | |
var _this3 = this; | |
if (this.transport) { | |
this.transport.removeAllListeners(); | |
} // set up transport | |
this.transport = transport; // set up transport listeners | |
transport.on("drain", this.onDrain.bind(this)).on("packet", this.onPacket.bind(this)).on("error", this.onError.bind(this)).on("close", function(reason) { | |
return _this3.onClose("transport close", reason); | |
}); | |
} | |
/** | |
* Probes a transport. | |
* | |
* @param {String} transport name | |
* @api private | |
*/ | |
}, { | |
key: "probe", | |
value: function probe(name) { | |
var _this4 = this; | |
var transport = this.createTransport(name); | |
var failed = false; | |
Socket.priorWebsocketSuccess = false; | |
var onTransportOpen = function onTransportOpen() { | |
if (failed) return; | |
transport.send([{ | |
type: "ping", | |
data: "probe" | |
}]); | |
transport.once("packet", function(msg) { | |
if (failed) return; | |
if ("pong" === msg.type && "probe" === msg.data) { | |
_this4.upgrading = true; | |
_this4.emitReserved("upgrading", transport); | |
if (!transport) return; | |
Socket.priorWebsocketSuccess = "websocket" === transport.name; | |
_this4.transport.pause(function() { | |
if (failed) return; | |
if ("closed" === _this4.readyState) return; | |
cleanup(); | |
_this4.setTransport(transport); | |
transport.send([{ | |
type: "upgrade" | |
}]); | |
_this4.emitReserved("upgrade", transport); | |
transport = null; | |
_this4.upgrading = false; | |
_this4.flush(); | |
}); | |
} else { | |
var err = new Error("probe error"); // @ts-ignore | |
err.transport = transport.name; | |
_this4.emitReserved("upgradeError", err); | |
} | |
}); | |
}; | |
function freezeTransport() { | |
if (failed) return; // Any callback called by transport should be ignored since now | |
failed = true; | |
cleanup(); | |
transport.close(); | |
transport = null; | |
} // Handle any error that happens while probing | |
var onerror = function onerror(err) { | |
var error = new Error("probe error: " + err); // @ts-ignore | |
error.transport = transport.name; | |
freezeTransport(); | |
_this4.emitReserved("upgradeError", error); | |
}; | |
function onTransportClose() { | |
onerror("transport closed"); | |
} // When the socket is closed while we're probing | |
function onclose() { | |
onerror("socket closed"); | |
} // When the socket is upgraded while we're probing | |
function onupgrade(to) { | |
if (transport && to.name !== transport.name) { | |
freezeTransport(); | |
} | |
} // Remove all listeners on the transport and on self | |
var cleanup = function cleanup() { | |
transport.removeListener("open", onTransportOpen); | |
transport.removeListener("error", onerror); | |
transport.removeListener("close", onTransportClose); | |
_this4.off("close", onclose); | |
_this4.off("upgrading", onupgrade); | |
}; | |
transport.once("open", onTransportOpen); | |
transport.once("error", onerror); | |
transport.once("close", onTransportClose); | |
this.once("close", onclose); | |
this.once("upgrading", onupgrade); | |
transport.open(); | |
} | |
/** | |
* Called when connection is deemed open. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onOpen", | |
value: function onOpen() { | |
this.readyState = "open"; | |
Socket.priorWebsocketSuccess = "websocket" === this.transport.name; | |
this.emitReserved("open"); | |
this.flush(); // we check for `readyState` in case an `open` | |
// listener already closed the socket | |
if ("open" === this.readyState && this.opts.upgrade && this.transport.pause) { | |
var i = 0; | |
var l = this.upgrades.length; | |
for (; i < l; i++) { | |
this.probe(this.upgrades[i]); | |
} | |
} | |
} | |
/** | |
* Handles a packet. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onPacket", | |
value: function onPacket(packet) { | |
if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) { | |
this.emitReserved("packet", packet); // Socket is live - any packet counts | |
this.emitReserved("heartbeat"); | |
switch (packet.type) { | |
case "open": | |
this.onHandshake(JSON.parse(packet.data)); | |
break; | |
case "ping": | |
this.resetPingTimeout(); | |
this.sendPacket("pong"); | |
this.emitReserved("ping"); | |
this.emitReserved("pong"); | |
break; | |
case "error": | |
var err = new Error("server error"); // @ts-ignore | |
err.code = packet.data; | |
this.onError(err); | |
break; | |
case "message": | |
this.emitReserved("data", packet.data); | |
this.emitReserved("message", packet.data); | |
break; | |
} | |
} | |
} | |
/** | |
* Called upon handshake completion. | |
* | |
* @param {Object} data - handshake obj | |
* @api private | |
*/ | |
}, { | |
key: "onHandshake", | |
value: function onHandshake(data) { | |
this.emitReserved("handshake", data); | |
this.id = data.sid; | |
this.transport.query.sid = data.sid; | |
this.upgrades = this.filterUpgrades(data.upgrades); | |
this.pingInterval = data.pingInterval; | |
this.pingTimeout = data.pingTimeout; | |
this.maxPayload = data.maxPayload; | |
this.onOpen(); // In case open handler closes socket | |
if ("closed" === this.readyState) return; | |
this.resetPingTimeout(); | |
} | |
/** | |
* Sets and resets ping timeout timer based on server pings. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "resetPingTimeout", | |
value: function resetPingTimeout() { | |
var _this5 = this; | |
this.clearTimeoutFn(this.pingTimeoutTimer); | |
this.pingTimeoutTimer = this.setTimeoutFn(function() { | |
_this5.onClose("ping timeout"); | |
}, this.pingInterval + this.pingTimeout); | |
if (this.opts.autoUnref) { | |
this.pingTimeoutTimer.unref(); | |
} | |
} | |
/** | |
* Called on `drain` event | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onDrain", | |
value: function onDrain() { | |
this.writeBuffer.splice(0, this.prevBufferLen); // setting prevBufferLen = 0 is very important | |
// for example, when upgrading, upgrade packet is sent over, | |
// and a nonzero prevBufferLen could cause problems on `drain` | |
this.prevBufferLen = 0; | |
if (0 === this.writeBuffer.length) { | |
this.emitReserved("drain"); | |
} else { | |
this.flush(); | |
} | |
} | |
/** | |
* Flush write buffers. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "flush", | |
value: function flush() { | |
if ("closed" !== this.readyState && this.transport.writable && !this.upgrading && this.writeBuffer.length) { | |
var packets = this.getWritablePackets(); | |
this.transport.send(packets); // keep track of current length of writeBuffer | |
// splice writeBuffer and callbackBuffer on `drain` | |
this.prevBufferLen = packets.length; | |
this.emitReserved("flush"); | |
} | |
} | |
/** | |
* Ensure the encoded size of the writeBuffer is below the maxPayload value sent by the server (only for HTTP | |
* long-polling) | |
* | |
* @private | |
*/ | |
}, { | |
key: "getWritablePackets", | |
value: function getWritablePackets() { | |
var shouldCheckPayloadSize = this.maxPayload && this.transport.name === "polling" && this.writeBuffer.length > 1; | |
if (!shouldCheckPayloadSize) { | |
return this.writeBuffer; | |
} | |
var payloadSize = 1; // first packet type | |
for (var i = 0; i < this.writeBuffer.length; i++) { | |
var data = this.writeBuffer[i].data; | |
if (data) { | |
payloadSize += byteLength(data); | |
} | |
if (i > 0 && payloadSize > this.maxPayload) { | |
return this.writeBuffer.slice(0, i); | |
} | |
payloadSize += 2; // separator + packet type | |
} | |
return this.writeBuffer; | |
} | |
/** | |
* Sends a message. | |
* | |
* @param {String} message. | |
* @param {Function} callback function. | |
* @param {Object} options. | |
* @return {Socket} for chaining. | |
* @api public | |
*/ | |
}, { | |
key: "write", | |
value: function write(msg, options, fn) { | |
this.sendPacket("message", msg, options, fn); | |
return this; | |
} | |
}, { | |
key: "send", | |
value: function send(msg, options, fn) { | |
this.sendPacket("message", msg, options, fn); | |
return this; | |
} | |
/** | |
* Sends a packet. | |
* | |
* @param {String} packet type. | |
* @param {String} data. | |
* @param {Object} options. | |
* @param {Function} callback function. | |
* @api private | |
*/ | |
}, { | |
key: "sendPacket", | |
value: function sendPacket(type, data, options, fn) { | |
if ("function" === typeof data) { | |
fn = data; | |
data = undefined; | |
} | |
if ("function" === typeof options) { | |
fn = options; | |
options = null; | |
} | |
if ("closing" === this.readyState || "closed" === this.readyState) { | |
return; | |
} | |
options = options || {}; | |
options.compress = false !== options.compress; | |
var packet = { | |
type: type, | |
data: data, | |
options: options | |
}; | |
this.emitReserved("packetCreate", packet); | |
this.writeBuffer.push(packet); | |
if (fn) this.once("flush", fn); | |
this.flush(); | |
} | |
/** | |
* Closes the connection. | |
* | |
* @api public | |
*/ | |
}, { | |
key: "close", | |
value: function close() { | |
var _this6 = this; | |
var close = function close() { | |
_this6.onClose("forced close"); | |
_this6.transport.close(); | |
}; | |
var cleanupAndClose = function cleanupAndClose() { | |
_this6.off("upgrade", cleanupAndClose); | |
_this6.off("upgradeError", cleanupAndClose); | |
close(); | |
}; | |
var waitForUpgrade = function waitForUpgrade() { | |
// wait for upgrade to finish since we can't send packets while pausing a transport | |
_this6.once("upgrade", cleanupAndClose); | |
_this6.once("upgradeError", cleanupAndClose); | |
}; | |
if ("opening" === this.readyState || "open" === this.readyState) { | |
this.readyState = "closing"; | |
if (this.writeBuffer.length) { | |
this.once("drain", function() { | |
if (_this6.upgrading) { | |
waitForUpgrade(); | |
} else { | |
close(); | |
} | |
}); | |
} else if (this.upgrading) { | |
waitForUpgrade(); | |
} else { | |
close(); | |
} | |
} | |
return this; | |
} | |
/** | |
* Called upon transport error | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onError", | |
value: function onError(err) { | |
Socket.priorWebsocketSuccess = false; | |
this.emitReserved("error", err); | |
this.onClose("transport error", err); | |
} | |
/** | |
* Called upon transport close. | |
* | |
* @api private | |
*/ | |
}, { | |
key: "onClose", | |
value: function onClose(reason, description) { | |
if ("opening" === this.readyState || "open" === this.readyState || "closing" === this.readyState) { | |
// clear timers | |
this.clearTimeoutFn(this.pingTimeoutTimer); // stop event from firing again for transport | |
this.transport.removeAllListeners("close"); // ensure transport won't stay open | |
this.transport.close(); // ignore further transport communication | |
this.transport.removeAllListeners(); | |
if (typeof removeEventListener === "function") { | |
removeEventListener("beforeunload", this.beforeunloadEventListener, false); | |
removeEventListener("offline", this.offlineEventListener, false); | |
} // set ready state | |
this.readyState = "closed"; // clear session id | |
this.id = null; // emit close event | |
this.emitReserved("close", reason, description); // clean buffers after, so users can still | |
// grab the buffers on `close` event | |
this.writeBuffer = []; | |
this.prevBufferLen = 0; | |
} | |
} | |
/** | |
* Filters upgrades, returning only those matching client transports. | |
* | |
* @param {Array} server upgrades | |
* @api private | |
* | |
*/ | |
}, { | |
key: "filterUpgrades", | |
value: function filterUpgrades(upgrades) { | |
var filteredUpgrades = []; | |
var i = 0; | |
var j = upgrades.length; | |
for (; i < j; i++) { | |
if (~this.transports.indexOf(upgrades[i])) filteredUpgrades.push(upgrades[i]); | |
} | |
return filteredUpgrades; | |
} | |
}]); | |
return Socket; | |
}(Emitter); | |
Socket$1.protocol = protocol$1; | |
Socket$1.protocol; | |
/** | |
* URL parser. | |
* | |
* @param uri - url | |
* @param path - the request path of the connection | |
* @param loc - An object meant to mimic window.location. | |
* Defaults to window.location. | |
* @public | |
*/ | |
function url(uri) { | |
var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ""; | |
var loc = arguments.length > 2 ? arguments[2] : undefined; | |
var obj = uri; // default to window.location | |
loc = loc || typeof location !== "undefined" && location; | |
if (null == uri) uri = loc.protocol + "//" + loc.host; // relative path support | |
if (typeof uri === "string") { | |
if ("/" === uri.charAt(0)) { | |
if ("/" === uri.charAt(1)) { | |
uri = loc.protocol + uri; | |
} else { | |
uri = loc.host + uri; | |
} | |
} | |
if (!/^(https?|wss?):\/\//.test(uri)) { | |
if ("undefined" !== typeof loc) { | |
uri = loc.protocol + "//" + uri; | |
} else { | |
uri = "https://" + uri; | |
} | |
} // parse | |
obj = parse(uri); | |
} // make sure we treat `localhost:80` and `localhost` equally | |
if (!obj.port) { | |
if (/^(http|ws)$/.test(obj.protocol)) { | |
obj.port = "80"; | |
} else if (/^(http|ws)s$/.test(obj.protocol)) { | |
obj.port = "443"; | |
} | |
} | |
obj.path = obj.path || "/"; | |
var ipv6 = obj.host.indexOf(":") !== -1; | |
var host = ipv6 ? "[" + obj.host + "]" : obj.host; // define unique id | |
obj.id = obj.protocol + "://" + host + ":" + obj.port + path; // define href | |
obj.href = obj.protocol + "://" + host + (loc && loc.port === obj.port ? "" : ":" + obj.port); | |
return obj; | |
} | |
var withNativeArrayBuffer = typeof ArrayBuffer === "function"; | |
var isView = function isView(obj) { | |
return typeof ArrayBuffer.isView === "function" ? ArrayBuffer.isView(obj) : obj.buffer instanceof ArrayBuffer; | |
}; | |
var toString = Object.prototype.toString; | |
var withNativeBlob = typeof Blob === "function" || typeof Blob !== "undefined" && toString.call(Blob) === "[object BlobConstructor]"; | |
var withNativeFile = typeof File === "function" || typeof File !== "undefined" && toString.call(File) === "[object FileConstructor]"; | |
/** | |
* Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File. | |
* | |
* @private | |
*/ | |
function isBinary(obj) { | |
return withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj)) || withNativeBlob && obj instanceof Blob || withNativeFile && obj instanceof File; | |
} | |
function hasBinary(obj, toJSON) { | |
if (!obj || _typeof(obj) !== "object") { | |
return false; | |
} | |
if (Array.isArray(obj)) { | |
for (var i = 0, l = obj.length; i < l; i++) { | |
if (hasBinary(obj[i])) { | |
return true; | |
} | |
} | |
return false; | |
} | |
if (isBinary(obj)) { | |
return true; | |
} | |
if (obj.toJSON && typeof obj.toJSON === "function" && arguments.length === 1) { | |
return hasBinary(obj.toJSON(), true); | |
} | |
for (var key in obj) { | |
if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder. | |
* | |
* @param {Object} packet - socket.io event packet | |
* @return {Object} with deconstructed packet and list of buffers | |
* @public | |
*/ | |
function deconstructPacket(packet) { | |
var buffers = []; | |
var packetData = packet.data; | |
var pack = packet; | |
pack.data = _deconstructPacket(packetData, buffers); | |
pack.attachments = buffers.length; // number of binary 'attachments' | |
return { | |
packet: pack, | |
buffers: buffers | |
}; | |
} | |
function _deconstructPacket(data, buffers) { | |
if (!data) return data; | |
if (isBinary(data)) { | |
var placeholder = { | |
_placeholder: true, | |
num: buffers.length | |
}; | |
buffers.push(data); | |
return placeholder; | |
} else if (Array.isArray(data)) { | |
var newData = new Array(data.length); | |
for (var i = 0; i < data.length; i++) { | |
newData[i] = _deconstructPacket(data[i], buffers); | |
} | |
return newData; | |
} else if (_typeof(data) === "object" && !(data instanceof Date)) { | |
var _newData = {}; | |
for (var key in data) { | |
if (Object.prototype.hasOwnProperty.call(data, key)) { | |
_newData[key] = _deconstructPacket(data[key], buffers); | |
} | |
} | |
return _newData; | |
} | |
return data; | |
} | |
/** | |
* Reconstructs a binary packet from its placeholder packet and buffers | |
* | |
* @param {Object} packet - event packet with placeholders | |
* @param {Array} buffers - binary buffers to put in placeholder positions | |
* @return {Object} reconstructed packet | |
* @public | |
*/ | |
function reconstructPacket(packet, buffers) { | |
packet.data = _reconstructPacket(packet.data, buffers); | |
packet.attachments = undefined; // no longer useful | |
return packet; | |
} | |
function _reconstructPacket(data, buffers) { | |
if (!data) return data; | |
if (data && data._placeholder) { | |
return buffers[data.num]; // appropriate buffer (should be natural order anyway) | |
} else if (Array.isArray(data)) { | |
for (var i = 0; i < data.length; i++) { | |
data[i] = _reconstructPacket(data[i], buffers); | |
} | |
} else if (_typeof(data) === "object") { | |
for (var key in data) { | |
if (Object.prototype.hasOwnProperty.call(data, key)) { | |
data[key] = _reconstructPacket(data[key], buffers); | |
} | |
} | |
} | |
return data; | |
} | |
/** | |
* Protocol version. | |
* | |
* @public | |
*/ | |
var protocol = 5; | |
var PacketType; | |
(function(PacketType) { | |
PacketType[PacketType["CONNECT"] = 0] = "CONNECT"; | |
PacketType[PacketType["DISCONNECT"] = 1] = "DISCONNECT"; | |
PacketType[PacketType["EVENT"] = 2] = "EVENT"; | |
PacketType[PacketType["ACK"] = 3] = "ACK"; | |
PacketType[PacketType["CONNECT_ERROR"] = 4] = "CONNECT_ERROR"; | |
PacketType[PacketType["BINARY_EVENT"] = 5] = "BINARY_EVENT"; | |
PacketType[PacketType["BINARY_ACK"] = 6] = "BINARY_ACK"; | |
})(PacketType || (PacketType = {})); | |
/** | |
* A socket.io Encoder instance | |
*/ | |
var Encoder = /*#__PURE__*/ function() { | |
/** | |
* Encoder constructor | |
* | |
* @param {function} replacer - custom replacer to pass down to JSON.parse | |
*/ | |
function Encoder(replacer) { | |
_classCallCheck(this, Encoder); | |
this.replacer = replacer; | |
} | |
/** | |
* Encode a packet as a single string if non-binary, or as a | |
* buffer sequence, depending on packet type. | |
* | |
* @param {Object} obj - packet object | |
*/ | |
_createClass(Encoder, [{ | |
key: "encode", | |
value: function encode(obj) { | |
if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) { | |
if (hasBinary(obj)) { | |
obj.type = obj.type === PacketType.EVENT ? PacketType.BINARY_EVENT : PacketType.BINARY_ACK; | |
return this.encodeAsBinary(obj); | |
} | |
} | |
return [this.encodeAsString(obj)]; | |
} | |
/** | |
* Encode packet as string. | |
*/ | |
}, { | |
key: "encodeAsString", | |
value: function encodeAsString(obj) { | |
// first is type | |
var str = "" + obj.type; // attachments if we have them | |
if (obj.type === PacketType.BINARY_EVENT || obj.type === PacketType.BINARY_ACK) { | |
str += obj.attachments + "-"; | |
} // if we have a namespace other than `/` | |
// we append it followed by a comma `,` | |
if (obj.nsp && "/" !== obj.nsp) { | |
str += obj.nsp + ","; | |
} // immediately followed by the id | |
if (null != obj.id) { | |
str += obj.id; | |
} // json data | |
if (null != obj.data) { | |
str += JSON.stringify(obj.data, this.replacer); | |
} | |
return str; | |
} | |
/** | |
* Encode packet as 'buffer sequence' by removing blobs, and | |
* deconstructing packet into object with placeholders and | |
* a list of buffers. | |
*/ | |
}, { | |
key: "encodeAsBinary", | |
value: function encodeAsBinary(obj) { | |
var deconstruction = deconstructPacket(obj); | |
var pack = this.encodeAsString(deconstruction.packet); | |
var buffers = deconstruction.buffers; | |
buffers.unshift(pack); // add packet info to beginning of data list | |
return buffers; // write all the buffers | |
} | |
}]); | |
return Encoder; | |
}(); | |
/** | |
* A socket.io Decoder instance | |
* | |
* @return {Object} decoder | |
*/ | |
var Decoder = /*#__PURE__*/ function(_Emitter) { | |
_inherits(Decoder, _Emitter); | |
var _super = _createSuper(Decoder); | |
/** | |
* Decoder constructor | |
* | |
* @param {function} reviver - custom reviver to pass down to JSON.stringify | |
*/ | |
function Decoder(reviver) { | |
var _this; | |
_classCallCheck(this, Decoder); | |
_this = _super.call(this); | |
_this.reviver = reviver; | |
return _this; | |
} | |
/** | |
* Decodes an encoded packet string into packet JSON. | |
* | |
* @param {String} obj - encoded packet | |
*/ | |
_createClass(Decoder, [{ | |
key: "add", | |
value: function add(obj) { | |
var packet; | |
if (typeof obj === "string") { | |
packet = this.decodeString(obj); | |
if (packet.type === PacketType.BINARY_EVENT || packet.type === PacketType.BINARY_ACK) { | |
// binary packet's json | |
this.reconstructor = new BinaryReconstructor(packet); // no attachments, labeled binary but no binary data to follow | |
if (packet.attachments === 0) { | |
_get(_getPrototypeOf(Decoder.prototype), "emitReserved", this).call(this, "decoded", packet); | |
} | |
} else { | |
// non-binary full packet | |
_get(_getPrototypeOf(Decoder.prototype), "emitReserved", this).call(this, "decoded", packet); | |
} | |
} else if (isBinary(obj) || obj.base64) { | |
// raw binary data | |
if (!this.reconstructor) { | |
throw new Error("got binary data when not reconstructing a packet"); | |
} else { | |
packet = this.reconstructor.takeBinaryData(obj); | |
if (packet) { | |
// received final buffer | |
this.reconstructor = null; | |
_get(_getPrototypeOf(Decoder.prototype), "emitReserved", this).call(this, "decoded", packet); | |
} | |
} | |
} else { | |
throw new Error("Unknown type: " + obj); | |
} | |
} | |
/** | |
* Decode a packet String (JSON data) | |
* | |
* @param {String} str | |
* @return {Object} packet | |
*/ | |
}, { | |
key: "decodeString", | |
value: function decodeString(str) { | |
var i = 0; // look up type | |
var p = { | |
type: Number(str.charAt(0)) | |
}; | |
if (PacketType[p.type] === undefined) { | |
throw new Error("unknown packet type " + p.type); | |
} // look up attachments if type binary | |
if (p.type === PacketType.BINARY_EVENT || p.type === PacketType.BINARY_ACK) { | |
var start = i + 1; | |
while (str.charAt(++i) !== "-" && i != str.length) {} | |
var buf = str.substring(start, i); | |
if (buf != Number(buf) || str.charAt(i) !== "-") { | |
throw new Error("Illegal attachments"); | |
} | |
p.attachments = Number(buf); | |
} // look up namespace (if any) | |
if ("/" === str.charAt(i + 1)) { | |
var _start = i + 1; | |
while (++i) { | |
var c = str.charAt(i); | |
if ("," === c) break; | |
if (i === str.length) break; | |
} | |
p.nsp = str.substring(_start, i); | |
} else { | |
p.nsp = "/"; | |
} // look up id | |
var next = str.charAt(i + 1); | |
if ("" !== next && Number(next) == next) { | |
var _start2 = i + 1; | |
while (++i) { | |
var _c = str.charAt(i); | |
if (null == _c || Number(_c) != _c) { | |
--i; | |
break; | |
} | |
if (i === str.length) break; | |
} | |
p.id = Number(str.substring(_start2, i + 1)); | |
} // look up json data | |
if (str.charAt(++i)) { | |
var payload = this.tryParse(str.substr(i)); | |
if (Decoder.isPayloadValid(p.type, payload)) { | |
p.data = payload; | |
} else { | |
throw new Error("invalid payload"); | |
} | |
} | |
return p; | |
} | |
}, { | |
key: "tryParse", | |
value: function tryParse(str) { | |
try { | |
return JSON.parse(str, this.reviver); | |
} catch (e) { | |
return false; | |
} | |
} | |
}, { | |
key: "destroy", | |
value: | |
/** | |
* Deallocates a parser's resources | |
*/ | |
function destroy() { | |
if (this.reconstructor) { | |
this.reconstructor.finishedReconstruction(); | |
} | |
} | |
}], [{ | |
key: "isPayloadValid", | |
value: function isPayloadValid(type, payload) { | |
switch (type) { | |
case PacketType.CONNECT: | |
return _typeof(payload) === "object"; | |
case PacketType.DISCONNECT: | |
return payload === undefined; | |
case PacketType.CONNECT_ERROR: | |
return typeof payload === "string" || _typeof(payload) === "object"; | |
case PacketType.EVENT: | |
case PacketType.BINARY_EVENT: | |
return Array.isArray(payload) && payload.length > 0; | |
case PacketType.ACK: | |
case PacketType.BINARY_ACK: | |
return Array.isArray(payload); | |
} | |
} | |
}]); | |
return Decoder; | |
}(Emitter); | |
/** | |
* A manager of a binary event's 'buffer sequence'. Should | |
* be constructed whenever a packet of type BINARY_EVENT is | |
* decoded. | |
* | |
* @param {Object} packet | |
* @return {BinaryReconstructor} initialized reconstructor | |
*/ | |
var BinaryReconstructor = /*#__PURE__*/ function() { | |
function BinaryReconstructor(packet) { | |
_classCallCheck(this, BinaryReconstructor); | |
this.packet = packet; | |
this.buffers = []; | |
this.reconPack = packet; | |
} | |
/** | |
* Method to be called when binary data received from connection | |
* after a BINARY_EVENT packet. | |
* | |
* @param {Buffer | ArrayBuffer} binData - the raw binary data received | |
* @return {null | Object} returns null if more binary data is expected or | |
* a reconstructed packet object if all buffers have been received. | |
*/ | |
_createClass(BinaryReconstructor, [{ | |
key: "takeBinaryData", | |
value: function takeBinaryData(binData) { | |
this.buffers.push(binData); | |
if (this.buffers.length === this.reconPack.attachments) { | |
// done with buffer list | |
var packet = reconstructPacket(this.reconPack, this.buffers); | |
this.finishedReconstruction(); | |
return packet; | |
} | |
return null; | |
} | |
/** | |
* Cleans up binary packet reconstruction variables. | |
*/ | |
}, { | |
key: "finishedReconstruction", | |
value: function finishedReconstruction() { | |
this.reconPack = null; | |
this.buffers = []; | |
} | |
}]); | |
return BinaryReconstructor; | |
}(); | |
var parser = /*#__PURE__*/ Object.freeze({ | |
__proto__: null, | |
protocol: protocol, | |
get PacketType() { | |
return PacketType; | |
}, | |
Encoder: Encoder, | |
Decoder: Decoder | |
}); | |
function on(obj, ev, fn) { | |
obj.on(ev, fn); | |
return function subDestroy() { | |
obj.off(ev, fn); | |
}; | |
} | |
/** | |
* Internal events. | |
* These events can't be emitted by the user. | |
*/ | |
var RESERVED_EVENTS = Object.freeze({ | |
connect: 1, | |
connect_error: 1, | |
disconnect: 1, | |
disconnecting: 1, | |
// EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener | |
newListener: 1, | |
removeListener: 1 | |
}); | |
/** | |
* A Socket is the fundamental class for interacting with the server. | |
* | |
* A Socket belongs to a certain Namespace (by default /) and uses an underlying {@link Manager} to communicate. | |
* | |
* @example | |
* const socket = io(); | |
* | |
* socket.on("connect", () => { | |
* console.log("connected"); | |
* }); | |
* | |
* // send an event to the server | |
* socket.emit("foo", "bar"); | |
* | |
* socket.on("foobar", () => { | |
* // an event was received from the server | |
* }); | |
* | |
* // upon disconnection | |
* socket.on("disconnect", (reason) => { | |
* console.log(`disconnected due to ${reason}`); | |
* }); | |
*/ | |
var Socket = /*#__PURE__*/ function(_Emitter) { | |
_inherits(Socket, _Emitter); | |
var _super = _createSuper(Socket); | |
/** | |
* `Socket` constructor. | |
*/ | |
function Socket(io, nsp, opts) { | |
var _this; | |
_classCallCheck(this, Socket); | |
_this = _super.call(this); | |
/** | |
* Whether the socket is currently connected to the server. | |
* | |
* @example | |
* const socket = io(); | |
* | |
* socket.on("connect", () => { | |
* console.log(socket.connected); // true | |
* }); | |
* | |
* socket.on("disconnect", () => { | |
* console.log(socket.connected); // false | |
* }); | |
*/ | |
_this.connected = false; | |
/** | |
* Buffer for packets received before the CONNECT packet | |
*/ | |
_this.receiveBuffer = []; | |
/** | |
* Buffer for packets that will be sent once the socket is connected | |
*/ | |
_this.sendBuffer = []; | |
_this.ids = 0; | |
_this.acks = {}; | |
_this.flags = {}; | |
_this.io = io; | |
_this.nsp = nsp; | |
if (opts && opts.auth) { | |
_this.auth = opts.auth; | |
} | |
if (_this.io._autoConnect) _this.open(); | |
return _this; | |
} | |
/** | |
* Whether the socket is currently disconnected | |
* | |
* @example | |
* const socket = io(); | |
* | |
* socket.on("connect", () => { | |
* console.log(socket.disconnected); // false | |
* }); | |
* | |
* socket.on("disconnect", () => { | |
* console.log(socket.disconnected); // true | |
* }); | |
*/ | |
_createClass(Socket, [{ | |
key: "disconnected", | |
get: function get() { | |
return !this.connected; | |
} | |
/** | |
* Subscribe to open, close and packet events | |
* | |
* @private | |
*/ | |
}, { | |
key: "subEvents", | |
value: function subEvents() { | |
if (this.subs) return; | |
var io = this.io; | |
this.subs = [on(io, "open", this.onopen.bind(this)), on(io, "packet", this.onpacket.bind(this)), on(io, "error", this.onerror.bind(this)), on(io, "close", this.onclose.bind(this))]; | |
} | |
/** | |
* Whether the Socket will try to reconnect when its Manager connects or reconnects. | |
* | |
* @example | |
* const socket = io(); | |
* | |
* console.log(socket.active); // true | |
* | |
* socket.on("disconnect", (reason) => { | |
* if (reason === "io server disconnect") { | |
* // the disconnection was initiated by the server, you need to manually reconnect | |
* console.log(socket.active); // false | |
* } | |
* // else the socket will automatically try to reconnect | |
* console.log(socket.active); // true | |
* }); | |
*/ | |
}, { | |
key: "active", | |
get: function get() { | |
return !!this.subs; | |
} | |
/** | |
* "Opens" the socket. | |
* | |
* @example | |
* const socket = io({ | |
* autoConnect: false | |
* }); | |
* | |
* socket.connect(); | |
*/ | |
}, { | |
key: "connect", | |
value: function connect() { | |
if (this.connected) return this; | |
this.subEvents(); | |
if (!this.io["_reconnecting"]) this.io.open(); // ensure open | |
if ("open" === this.io._readyState) this.onopen(); | |
return this; | |
} | |
/** | |
* Alias for {@link connect()}. | |
*/ | |
}, { | |
key: "open", | |
value: function open() { | |
return this.connect(); | |
} | |
/** | |
* Sends a `message` event. | |
* | |
* This method mimics the WebSocket.send() method. | |
* | |
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send | |
* | |
* @example | |
* socket.send("hello"); | |
* | |
* // this is equivalent to | |
* socket.emit("message", "hello"); | |
* | |
* @return self | |
*/ | |
}, { | |
key: "send", | |
value: function send() { | |
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
args.unshift("message"); | |
this.emit.apply(this, args); | |
return this; | |
} | |
/** | |
* Override `emit`. | |
* If the event is in `events`, it's emitted normally. | |
* | |
* @example | |
* socket.emit("hello", "world"); | |
* | |
* // all serializable datastructures are supported (no need to call JSON.stringify) | |
* socket.emit("hello", 1, "2", { 3: ["4"], 5: Uint8Array.from([6]) }); | |
* | |
* // with an acknowledgement from the server | |
* socket.emit("hello", "world", (val) => { | |
* // ... | |
* }); | |
* | |
* @return self | |
*/ | |
}, { | |
key: "emit", | |
value: function emit(ev) { | |
if (RESERVED_EVENTS.hasOwnProperty(ev)) { | |
throw new Error('"' + ev.toString() + '" is a reserved event name'); | |
} | |
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { | |
args[_key2 - 1] = arguments[_key2]; | |
} | |
args.unshift(ev); | |
var packet = { | |
type: PacketType.EVENT, | |
data: args | |
}; | |
packet.options = {}; | |
packet.options.compress = this.flags.compress !== false; // event ack callback | |
if ("function" === typeof args[args.length - 1]) { | |
var id = this.ids++; | |
var ack = args.pop(); | |
this._registerAckCallback(id, ack); | |
packet.id = id; | |
} | |
var isTransportWritable = this.io.engine && this.io.engine.transport && this.io.engine.transport.writable; | |
var discardPacket = this.flags["volatile"] && (!isTransportWritable || !this.connected); | |
if (discardPacket); | |
else if (this.connected) { | |
this.notifyOutgoingListeners(packet); | |
this.packet(packet); | |
} else { | |
this.sendBuffer.push(packet); | |
} | |
this.flags = {}; | |
return this; | |
} | |
/** | |
* @private | |
*/ | |
}, { | |
key: "_registerAckCallback", | |
value: function _registerAckCallback(id, ack) { | |
var _this2 = this; | |
var timeout = this.flags.timeout; | |
if (timeout === undefined) { | |
this.acks[id] = ack; | |
return; | |
} // @ts-ignore | |
var timer = this.io.setTimeoutFn(function() { | |
delete _this2.acks[id]; | |
for (var i = 0; i < _this2.sendBuffer.length; i++) { | |
if (_this2.sendBuffer[i].id === id) { | |
_this2.sendBuffer.splice(i, 1); | |
} | |
} | |
ack.call(_this2, new Error("operation has timed out")); | |
}, timeout); | |
this.acks[id] = function() { | |
// @ts-ignore | |
_this2.io.clearTimeoutFn(timer); | |
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | |
args[_key3] = arguments[_key3]; | |
} | |
ack.apply(_this2, [null].concat(args)); | |
}; | |
} | |
/** | |
* Sends a packet. | |
* | |
* @param packet | |
* @private | |
*/ | |
}, { | |
key: "packet", | |
value: function packet(_packet) { | |
_packet.nsp = this.nsp; | |
this.io._packet(_packet); | |
} | |
/** | |
* Called upon engine `open`. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onopen", | |
value: function onopen() { | |
var _this3 = this; | |
if (typeof this.auth == "function") { | |
this.auth(function(data) { | |
_this3.packet({ | |
type: PacketType.CONNECT, | |
data: data | |
}); | |
}); | |
} else { | |
this.packet({ | |
type: PacketType.CONNECT, | |
data: this.auth | |
}); | |
} | |
} | |
/** | |
* Called upon engine or manager `error`. | |
* | |
* @param err | |
* @private | |
*/ | |
}, { | |
key: "onerror", | |
value: function onerror(err) { | |
if (!this.connected) { | |
this.emitReserved("connect_error", err); | |
} | |
} | |
/** | |
* Called upon engine `close`. | |
* | |
* @param reason | |
* @param description | |
* @private | |
*/ | |
}, { | |
key: "onclose", | |
value: function onclose(reason, description) { | |
this.connected = false; | |
delete this.id; | |
this.emitReserved("disconnect", reason, description); | |
} | |
/** | |
* Called with socket packet. | |
* | |
* @param packet | |
* @private | |
*/ | |
}, { | |
key: "onpacket", | |
value: function onpacket(packet) { | |
var sameNamespace = packet.nsp === this.nsp; | |
if (!sameNamespace) return; | |
switch (packet.type) { | |
case PacketType.CONNECT: | |
if (packet.data && packet.data.sid) { | |
var id = packet.data.sid; | |
this.onconnect(id); | |
} else { | |
this.emitReserved("connect_error", new Error("It seems you are trying to reach a Socket.IO server in v2.x with a v3.x client, but they are not compatible (more information here: https://socket.io/docs/v3/migrating-from-2-x-to-3-0/)")); | |
} | |
break; | |
case PacketType.EVENT: | |
case PacketType.BINARY_EVENT: | |
this.onevent(packet); | |
break; | |
case PacketType.ACK: | |
case PacketType.BINARY_ACK: | |
this.onack(packet); | |
break; | |
case PacketType.DISCONNECT: | |
this.ondisconnect(); | |
break; | |
case PacketType.CONNECT_ERROR: | |
this.destroy(); | |
var err = new Error(packet.data.message); // @ts-ignore | |
err.data = packet.data.data; | |
this.emitReserved("connect_error", err); | |
break; | |
} | |
} | |
/** | |
* Called upon a server event. | |
* | |
* @param packet | |
* @private | |
*/ | |
}, { | |
key: "onevent", | |
value: function onevent(packet) { | |
var args = packet.data || []; | |
if (null != packet.id) { | |
args.push(this.ack(packet.id)); | |
} | |
if (this.connected) { | |
this.emitEvent(args); | |
} else { | |
this.receiveBuffer.push(Object.freeze(args)); | |
} | |
} | |
}, { | |
key: "emitEvent", | |
value: function emitEvent(args) { | |
if (this._anyListeners && this._anyListeners.length) { | |
var listeners = this._anyListeners.slice(); | |
var _iterator = _createForOfIteratorHelper(listeners), | |
_step; | |
try { | |
for (_iterator.s(); !(_step = _iterator.n()).done;) { | |
var listener = _step.value; | |
listener.apply(this, args); | |
} | |
} catch (err) { | |
_iterator.e(err); | |
} finally { | |
_iterator.f(); | |
} | |
} | |
_get(_getPrototypeOf(Socket.prototype), "emit", this).apply(this, args); | |
} | |
/** | |
* Produces an ack callback to emit with an event. | |
* | |
* @private | |
*/ | |
}, { | |
key: "ack", | |
value: function ack(id) { | |
var self = this; | |
var sent = false; | |
return function() { | |
// prevent double callbacks | |
if (sent) return; | |
sent = true; | |
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { | |
args[_key4] = arguments[_key4]; | |
} | |
self.packet({ | |
type: PacketType.ACK, | |
id: id, | |
data: args | |
}); | |
}; | |
} | |
/** | |
* Called upon a server acknowlegement. | |
* | |
* @param packet | |
* @private | |
*/ | |
}, { | |
key: "onack", | |
value: function onack(packet) { | |
var ack = this.acks[packet.id]; | |
if ("function" === typeof ack) { | |
ack.apply(this, packet.data); | |
delete this.acks[packet.id]; | |
} | |
} | |
/** | |
* Called upon server connect. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onconnect", | |
value: function onconnect(id) { | |
this.id = id; | |
this.connected = true; | |
this.emitBuffered(); | |
this.emitReserved("connect"); | |
} | |
/** | |
* Emit buffered events (received and emitted). | |
* | |
* @private | |
*/ | |
}, { | |
key: "emitBuffered", | |
value: function emitBuffered() { | |
var _this4 = this; | |
this.receiveBuffer.forEach(function(args) { | |
return _this4.emitEvent(args); | |
}); | |
this.receiveBuffer = []; | |
this.sendBuffer.forEach(function(packet) { | |
_this4.notifyOutgoingListeners(packet); | |
_this4.packet(packet); | |
}); | |
this.sendBuffer = []; | |
} | |
/** | |
* Called upon server disconnect. | |
* | |
* @private | |
*/ | |
}, { | |
key: "ondisconnect", | |
value: function ondisconnect() { | |
this.destroy(); | |
this.onclose("io server disconnect"); | |
} | |
/** | |
* Called upon forced client/server side disconnections, | |
* this method ensures the manager stops tracking us and | |
* that reconnections don't get triggered for this. | |
* | |
* @private | |
*/ | |
}, { | |
key: "destroy", | |
value: function destroy() { | |
if (this.subs) { | |
// clean subscriptions to avoid reconnections | |
this.subs.forEach(function(subDestroy) { | |
return subDestroy(); | |
}); | |
this.subs = undefined; | |
} | |
this.io["_destroy"](this); | |
} | |
/** | |
* Disconnects the socket manually. In that case, the socket will not try to reconnect. | |
* | |
* If this is the last active Socket instance of the {@link Manager}, the low-level connection will be closed. | |
* | |
* @example | |
* const socket = io(); | |
* | |
* socket.on("disconnect", (reason) => { | |
* // console.log(reason); prints "io client disconnect" | |
* }); | |
* | |
* socket.disconnect(); | |
* | |
* @return self | |
*/ | |
}, { | |
key: "disconnect", | |
value: function disconnect() { | |
if (this.connected) { | |
this.packet({ | |
type: PacketType.DISCONNECT | |
}); | |
} // remove socket from pool | |
this.destroy(); | |
if (this.connected) { | |
// fire events | |
this.onclose("io client disconnect"); | |
} | |
return this; | |
} | |
/** | |
* Alias for {@link disconnect()}. | |
* | |
* @return self | |
*/ | |
}, { | |
key: "close", | |
value: function close() { | |
return this.disconnect(); | |
} | |
/** | |
* Sets the compress flag. | |
* | |
* @example | |
* socket.compress(false).emit("hello"); | |
* | |
* @param compress - if `true`, compresses the sending data | |
* @return self | |
*/ | |
}, { | |
key: "compress", | |
value: function compress(_compress) { | |
this.flags.compress = _compress; | |
return this; | |
} | |
/** | |
* Sets a modifier for a subsequent event emission that the event message will be dropped when this socket is not | |
* ready to send messages. | |
* | |
* @example | |
* socket.volatile.emit("hello"); // the server may or may not receive it | |
* | |
* @returns self | |
*/ | |
}, { | |
key: "volatile", | |
get: function get() { | |
this.flags["volatile"] = true; | |
return this; | |
} | |
/** | |
* Sets a modifier for a subsequent event emission that the callback will be called with an error when the | |
* given number of milliseconds have elapsed without an acknowledgement from the server: | |
* | |
* @example | |
* socket.timeout(5000).emit("my-event", (err) => { | |
* if (err) { | |
* // the server did not acknowledge the event in the given delay | |
* } | |
* }); | |
* | |
* @returns self | |
*/ | |
}, { | |
key: "timeout", | |
value: function timeout(_timeout) { | |
this.flags.timeout = _timeout; | |
return this; | |
} | |
/** | |
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | |
* callback. | |
* | |
* @example | |
* socket.onAny((event, ...args) => { | |
* console.log(`got ${event}`); | |
* }); | |
* | |
* @param listener | |
*/ | |
}, { | |
key: "onAny", | |
value: function onAny(listener) { | |
this._anyListeners = this._anyListeners || []; | |
this._anyListeners.push(listener); | |
return this; | |
} | |
/** | |
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | |
* callback. The listener is added to the beginning of the listeners array. | |
* | |
* @example | |
* socket.prependAny((event, ...args) => { | |
* console.log(`got event ${event}`); | |
* }); | |
* | |
* @param listener | |
*/ | |
}, { | |
key: "prependAny", | |
value: function prependAny(listener) { | |
this._anyListeners = this._anyListeners || []; | |
this._anyListeners.unshift(listener); | |
return this; | |
} | |
/** | |
* Removes the listener that will be fired when any event is emitted. | |
* | |
* @example | |
* const catchAllListener = (event, ...args) => { | |
* console.log(`got event ${event}`); | |
* } | |
* | |
* socket.onAny(catchAllListener); | |
* | |
* // remove a specific listener | |
* socket.offAny(catchAllListener); | |
* | |
* // or remove all listeners | |
* socket.offAny(); | |
* | |
* @param listener | |
*/ | |
}, { | |
key: "offAny", | |
value: function offAny(listener) { | |
if (!this._anyListeners) { | |
return this; | |
} | |
if (listener) { | |
var listeners = this._anyListeners; | |
for (var i = 0; i < listeners.length; i++) { | |
if (listener === listeners[i]) { | |
listeners.splice(i, 1); | |
return this; | |
} | |
} | |
} else { | |
this._anyListeners = []; | |
} | |
return this; | |
} | |
/** | |
* Returns an array of listeners that are listening for any event that is specified. This array can be manipulated, | |
* e.g. to remove listeners. | |
*/ | |
}, { | |
key: "listenersAny", | |
value: function listenersAny() { | |
return this._anyListeners || []; | |
} | |
/** | |
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | |
* callback. | |
* | |
* Note: acknowledgements sent to the server are not included. | |
* | |
* @example | |
* socket.onAnyOutgoing((event, ...args) => { | |
* console.log(`sent event ${event}`); | |
* }); | |
* | |
* @param listener | |
*/ | |
}, { | |
key: "onAnyOutgoing", | |
value: function onAnyOutgoing(listener) { | |
this._anyOutgoingListeners = this._anyOutgoingListeners || []; | |
this._anyOutgoingListeners.push(listener); | |
return this; | |
} | |
/** | |
* Adds a listener that will be fired when any event is emitted. The event name is passed as the first argument to the | |
* callback. The listener is added to the beginning of the listeners array. | |
* | |
* Note: acknowledgements sent to the server are not included. | |
* | |
* @example | |
* socket.prependAnyOutgoing((event, ...args) => { | |
* console.log(`sent event ${event}`); | |
* }); | |
* | |
* @param listener | |
*/ | |
}, { | |
key: "prependAnyOutgoing", | |
value: function prependAnyOutgoing(listener) { | |
this._anyOutgoingListeners = this._anyOutgoingListeners || []; | |
this._anyOutgoingListeners.unshift(listener); | |
return this; | |
} | |
/** | |
* Removes the listener that will be fired when any event is emitted. | |
* | |
* @example | |
* const catchAllListener = (event, ...args) => { | |
* console.log(`sent event ${event}`); | |
* } | |
* | |
* socket.onAnyOutgoing(catchAllListener); | |
* | |
* // remove a specific listener | |
* socket.offAnyOutgoing(catchAllListener); | |
* | |
* // or remove all listeners | |
* socket.offAnyOutgoing(); | |
* | |
* @param [listener] - the catch-all listener (optional) | |
*/ | |
}, { | |
key: "offAnyOutgoing", | |
value: function offAnyOutgoing(listener) { | |
if (!this._anyOutgoingListeners) { | |
return this; | |
} | |
if (listener) { | |
var listeners = this._anyOutgoingListeners; | |
for (var i = 0; i < listeners.length; i++) { | |
if (listener === listeners[i]) { | |
listeners.splice(i, 1); | |
return this; | |
} | |
} | |
} else { | |
this._anyOutgoingListeners = []; | |
} | |
return this; | |
} | |
/** | |
* Returns an array of listeners that are listening for any event that is specified. This array can be manipulated, | |
* e.g. to remove listeners. | |
*/ | |
}, { | |
key: "listenersAnyOutgoing", | |
value: function listenersAnyOutgoing() { | |
return this._anyOutgoingListeners || []; | |
} | |
/** | |
* Notify the listeners for each packet sent | |
* | |
* @param packet | |
* | |
* @private | |
*/ | |
}, { | |
key: "notifyOutgoingListeners", | |
value: function notifyOutgoingListeners(packet) { | |
if (this._anyOutgoingListeners && this._anyOutgoingListeners.length) { | |
var listeners = this._anyOutgoingListeners.slice(); | |
var _iterator2 = _createForOfIteratorHelper(listeners), | |
_step2; | |
try { | |
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { | |
var listener = _step2.value; | |
listener.apply(this, packet.data); | |
} | |
} catch (err) { | |
_iterator2.e(err); | |
} finally { | |
_iterator2.f(); | |
} | |
} | |
} | |
}]); | |
return Socket; | |
}(Emitter); | |
/** | |
* Initialize backoff timer with `opts`. | |
* | |
* - `min` initial timeout in milliseconds [100] | |
* - `max` max timeout [10000] | |
* - `jitter` [0] | |
* - `factor` [2] | |
* | |
* @param {Object} opts | |
* @api public | |
*/ | |
function Backoff(opts) { | |
opts = opts || {}; | |
this.ms = opts.min || 100; | |
this.max = opts.max || 10000; | |
this.factor = opts.factor || 2; | |
this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0; | |
this.attempts = 0; | |
} | |
/** | |
* Return the backoff duration. | |
* | |
* @return {Number} | |
* @api public | |
*/ | |
Backoff.prototype.duration = function() { | |
var ms = this.ms * Math.pow(this.factor, this.attempts++); | |
if (this.jitter) { | |
var rand = Math.random(); | |
var deviation = Math.floor(rand * this.jitter * ms); | |
ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation; | |
} | |
return Math.min(ms, this.max) | 0; | |
}; | |
/** | |
* Reset the number of attempts. | |
* | |
* @api public | |
*/ | |
Backoff.prototype.reset = function() { | |
this.attempts = 0; | |
}; | |
/** | |
* Set the minimum duration | |
* | |
* @api public | |
*/ | |
Backoff.prototype.setMin = function(min) { | |
this.ms = min; | |
}; | |
/** | |
* Set the maximum duration | |
* | |
* @api public | |
*/ | |
Backoff.prototype.setMax = function(max) { | |
this.max = max; | |
}; | |
/** | |
* Set the jitter | |
* | |
* @api public | |
*/ | |
Backoff.prototype.setJitter = function(jitter) { | |
this.jitter = jitter; | |
}; | |
var Manager = /*#__PURE__*/ function(_Emitter) { | |
_inherits(Manager, _Emitter); | |
var _super = _createSuper(Manager); | |
function Manager(uri, opts) { | |
var _this; | |
_classCallCheck(this, Manager); | |
var _a; | |
_this = _super.call(this); | |
_this.nsps = {}; | |
_this.subs = []; | |
if (uri && "object" === _typeof(uri)) { | |
opts = uri; | |
uri = undefined; | |
} | |
opts = opts || {}; | |
opts.path = opts.path || "/socket.io"; | |
_this.opts = opts; | |
installTimerFunctions(_assertThisInitialized(_this), opts); | |
_this.reconnection(opts.reconnection !== false); | |
_this.reconnectionAttempts(opts.reconnectionAttempts || Infinity); | |
_this.reconnectionDelay(opts.reconnectionDelay || 1000); | |
_this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000); | |
_this.randomizationFactor((_a = opts.randomizationFactor) !== null && _a !== void 0 ? _a : 0.5); | |
_this.backoff = new Backoff({ | |
min: _this.reconnectionDelay(), | |
max: _this.reconnectionDelayMax(), | |
jitter: _this.randomizationFactor() | |
}); | |
_this.timeout(null == opts.timeout ? 20000 : opts.timeout); | |
_this._readyState = "closed"; | |
_this.uri = uri; | |
var _parser = opts.parser || parser; | |
_this.encoder = new _parser.Encoder(); | |
_this.decoder = new _parser.Decoder(); | |
_this._autoConnect = opts.autoConnect !== false; | |
if (_this._autoConnect) _this.open(); | |
return _this; | |
} | |
_createClass(Manager, [{ | |
key: "reconnection", | |
value: function reconnection(v) { | |
if (!arguments.length) return this._reconnection; | |
this._reconnection = !!v; | |
return this; | |
} | |
}, { | |
key: "reconnectionAttempts", | |
value: function reconnectionAttempts(v) { | |
if (v === undefined) return this._reconnectionAttempts; | |
this._reconnectionAttempts = v; | |
return this; | |
} | |
}, { | |
key: "reconnectionDelay", | |
value: function reconnectionDelay(v) { | |
var _a; | |
if (v === undefined) return this._reconnectionDelay; | |
this._reconnectionDelay = v; | |
(_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMin(v); | |
return this; | |
} | |
}, { | |
key: "randomizationFactor", | |
value: function randomizationFactor(v) { | |
var _a; | |
if (v === undefined) return this._randomizationFactor; | |
this._randomizationFactor = v; | |
(_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setJitter(v); | |
return this; | |
} | |
}, { | |
key: "reconnectionDelayMax", | |
value: function reconnectionDelayMax(v) { | |
var _a; | |
if (v === undefined) return this._reconnectionDelayMax; | |
this._reconnectionDelayMax = v; | |
(_a = this.backoff) === null || _a === void 0 ? void 0 : _a.setMax(v); | |
return this; | |
} | |
}, { | |
key: "timeout", | |
value: function timeout(v) { | |
if (!arguments.length) return this._timeout; | |
this._timeout = v; | |
return this; | |
} | |
/** | |
* Starts trying to reconnect if reconnection is enabled and we have not | |
* started reconnecting yet | |
* | |
* @private | |
*/ | |
}, { | |
key: "maybeReconnectOnOpen", | |
value: function maybeReconnectOnOpen() { | |
// Only try to reconnect if it's the first time we're connecting | |
if (!this._reconnecting && this._reconnection && this.backoff.attempts === 0) { | |
// keeps reconnection from firing twice for the same reconnection loop | |
this.reconnect(); | |
} | |
} | |
/** | |
* Sets the current transport `socket`. | |
* | |
* @param {Function} fn - optional, callback | |
* @return self | |
* @public | |
*/ | |
}, { | |
key: "open", | |
value: function open(fn) { | |
var _this2 = this; | |
if (~this._readyState.indexOf("open")) return this; | |
this.engine = new Socket$1(this.uri, this.opts); | |
var socket = this.engine; | |
var self = this; | |
this._readyState = "opening"; | |
this.skipReconnect = false; // emit `open` | |
var openSubDestroy = on(socket, "open", function() { | |
self.onopen(); | |
fn && fn(); | |
}); // emit `error` | |
var errorSub = on(socket, "error", function(err) { | |
self.cleanup(); | |
self._readyState = "closed"; | |
_this2.emitReserved("error", err); | |
if (fn) { | |
fn(err); | |
} else { | |
// Only do this if there is no fn to handle the error | |
self.maybeReconnectOnOpen(); | |
} | |
}); | |
if (false !== this._timeout) { | |
var timeout = this._timeout; | |
if (timeout === 0) { | |
openSubDestroy(); // prevents a race condition with the 'open' event | |
} // set timer | |
var timer = this.setTimeoutFn(function() { | |
openSubDestroy(); | |
socket.close(); // @ts-ignore | |
socket.emit("error", new Error("timeout")); | |
}, timeout); | |
if (this.opts.autoUnref) { | |
timer.unref(); | |
} | |
this.subs.push(function subDestroy() { | |
clearTimeout(timer); | |
}); | |
} | |
this.subs.push(openSubDestroy); | |
this.subs.push(errorSub); | |
return this; | |
} | |
/** | |
* Alias for open() | |
* | |
* @return self | |
* @public | |
*/ | |
}, { | |
key: "connect", | |
value: function connect(fn) { | |
return this.open(fn); | |
} | |
/** | |
* Called upon transport open. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onopen", | |
value: function onopen() { | |
// clear old subs | |
this.cleanup(); // mark as open | |
this._readyState = "open"; | |
this.emitReserved("open"); // add new subs | |
var socket = this.engine; | |
this.subs.push(on(socket, "ping", this.onping.bind(this)), on(socket, "data", this.ondata.bind(this)), on(socket, "error", this.onerror.bind(this)), on(socket, "close", this.onclose.bind(this)), on(this.decoder, "decoded", this.ondecoded.bind(this))); | |
} | |
/** | |
* Called upon a ping. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onping", | |
value: function onping() { | |
this.emitReserved("ping"); | |
} | |
/** | |
* Called with data. | |
* | |
* @private | |
*/ | |
}, { | |
key: "ondata", | |
value: function ondata(data) { | |
try { | |
this.decoder.add(data); | |
} catch (e) { | |
this.onclose("parse error", e); | |
} | |
} | |
/** | |
* Called when parser fully decodes a packet. | |
* | |
* @private | |
*/ | |
}, { | |
key: "ondecoded", | |
value: function ondecoded(packet) { | |
var _this3 = this; | |
// the nextTick call prevents an exception in a user-provided event listener from triggering a disconnection due to a "parse error" | |
nextTick(function() { | |
_this3.emitReserved("packet", packet); | |
}, this.setTimeoutFn); | |
} | |
/** | |
* Called upon socket error. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onerror", | |
value: function onerror(err) { | |
this.emitReserved("error", err); | |
} | |
/** | |
* Creates a new socket for the given `nsp`. | |
* | |
* @return {Socket} | |
* @public | |
*/ | |
}, { | |
key: "socket", | |
value: function socket(nsp, opts) { | |
var socket = this.nsps[nsp]; | |
if (!socket) { | |
socket = new Socket(this, nsp, opts); | |
this.nsps[nsp] = socket; | |
} | |
return socket; | |
} | |
/** | |
* Called upon a socket close. | |
* | |
* @param socket | |
* @private | |
*/ | |
}, { | |
key: "_destroy", | |
value: function _destroy(socket) { | |
var nsps = Object.keys(this.nsps); | |
for (var _i = 0, _nsps = nsps; _i < _nsps.length; _i++) { | |
var nsp = _nsps[_i]; | |
var _socket = this.nsps[nsp]; | |
if (_socket.active) { | |
return; | |
} | |
} | |
this._close(); | |
} | |
/** | |
* Writes a packet. | |
* | |
* @param packet | |
* @private | |
*/ | |
}, { | |
key: "_packet", | |
value: function _packet(packet) { | |
var encodedPackets = this.encoder.encode(packet); | |
for (var i = 0; i < encodedPackets.length; i++) { | |
this.engine.write(encodedPackets[i], packet.options); | |
} | |
} | |
/** | |
* Clean up transport subscriptions and packet buffer. | |
* | |
* @private | |
*/ | |
}, { | |
key: "cleanup", | |
value: function cleanup() { | |
this.subs.forEach(function(subDestroy) { | |
return subDestroy(); | |
}); | |
this.subs.length = 0; | |
this.decoder.destroy(); | |
} | |
/** | |
* Close the current socket. | |
* | |
* @private | |
*/ | |
}, { | |
key: "_close", | |
value: function _close() { | |
this.skipReconnect = true; | |
this._reconnecting = false; | |
this.onclose("forced close"); | |
if (this.engine) this.engine.close(); | |
} | |
/** | |
* Alias for close() | |
* | |
* @private | |
*/ | |
}, { | |
key: "disconnect", | |
value: function disconnect() { | |
return this._close(); | |
} | |
/** | |
* Called upon engine close. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onclose", | |
value: function onclose(reason, description) { | |
this.cleanup(); | |
this.backoff.reset(); | |
this._readyState = "closed"; | |
this.emitReserved("close", reason, description); | |
if (this._reconnection && !this.skipReconnect) { | |
this.reconnect(); | |
} | |
} | |
/** | |
* Attempt a reconnection. | |
* | |
* @private | |
*/ | |
}, { | |
key: "reconnect", | |
value: function reconnect() { | |
var _this4 = this; | |
if (this._reconnecting || this.skipReconnect) return this; | |
var self = this; | |
if (this.backoff.attempts >= this._reconnectionAttempts) { | |
this.backoff.reset(); | |
this.emitReserved("reconnect_failed"); | |
this._reconnecting = false; | |
} else { | |
var delay = this.backoff.duration(); | |
this._reconnecting = true; | |
var timer = this.setTimeoutFn(function() { | |
if (self.skipReconnect) return; | |
_this4.emitReserved("reconnect_attempt", self.backoff.attempts); // check again for the case socket closed in above events | |
if (self.skipReconnect) return; | |
self.open(function(err) { | |
if (err) { | |
self._reconnecting = false; | |
self.reconnect(); | |
_this4.emitReserved("reconnect_error", err); | |
} else { | |
self.onreconnect(); | |
} | |
}); | |
}, delay); | |
if (this.opts.autoUnref) { | |
timer.unref(); | |
} | |
this.subs.push(function subDestroy() { | |
clearTimeout(timer); | |
}); | |
} | |
} | |
/** | |
* Called upon successful reconnect. | |
* | |
* @private | |
*/ | |
}, { | |
key: "onreconnect", | |
value: function onreconnect() { | |
var attempt = this.backoff.attempts; | |
this._reconnecting = false; | |
this.backoff.reset(); | |
this.emitReserved("reconnect", attempt); | |
} | |
}]); | |
return Manager; | |
}(Emitter); | |
/** | |
* Managers cache. | |
*/ | |
var cache = {}; | |
function lookup(uri, opts) { | |
if (_typeof(uri) === "object") { | |
opts = uri; | |
uri = undefined; | |
} | |
opts = opts || {}; | |
var parsed = url(uri, opts.path || "/socket.io"); | |
var source = parsed.source; | |
var id = parsed.id; | |
var path = parsed.path; | |
var sameNamespace = cache[id] && path in cache[id]["nsps"]; | |
var newConnection = opts.forceNew || opts["force new connection"] || false === opts.multiplex || sameNamespace; | |
var io; | |
if (newConnection) { | |
io = new Manager(source, opts); | |
} else { | |
if (!cache[id]) { | |
cache[id] = new Manager(source, opts); | |
} | |
io = cache[id]; | |
} | |
if (parsed.query && !opts.query) { | |
opts.query = parsed.queryKey; | |
} | |
return io.socket(parsed.path, opts); | |
} // so that "lookup" can be used both as a function (e.g. `io(...)`) and as a | |
// namespace (e.g. `io.connect(...)`), for backward compatibility | |
_extends(lookup, { | |
Manager: Manager, | |
Socket: Socket, | |
io: lookup, | |
connect: lookup | |
}); | |
return lookup; | |
})); | |
//# sourceMappingURL=socket.io.js.map |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment