@october/reconnecting-websocket
Advanced tools
Comparing version 1.0.1 to 1.0.2
define(function () { 'use strict'; | ||
class Event { | ||
constructor(type, target) { | ||
this.target = target; | ||
this.type = type; | ||
} | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
class ErrorEvent extends Event { | ||
constructor(error, target) { | ||
super('error', target); | ||
this.message = error.message; | ||
this.error = error; | ||
} | ||
}; | ||
var createClass = 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); | ||
} | ||
} | ||
class CloseEvent extends Event { | ||
constructor(code = 1000, reason = '', target) { | ||
super('close', target); | ||
this.wasClean = true; | ||
this.code = code; | ||
this.reason = reason; | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
const getGlobalWebSocket = () => { | ||
if (typeof WebSocket !== 'undefined') { | ||
// @ts-ignore | ||
return WebSocket; | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
}; | ||
/** | ||
* Returns true if given argument looks like a WebSocket class | ||
*/ | ||
const isWebSocket = (w) => typeof w === 'function' && w.CLOSING === 2; | ||
const DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
minReconnectionDelay: 1000 + Math.random() * 4000, | ||
minUptime: 5000, | ||
reconnectionDelayGrowFactor: 1.3, | ||
connectionTimeout: 4000, | ||
maxRetries: Infinity, | ||
debug: false, | ||
}; | ||
class ReconnectingWebSocket { | ||
constructor(url, protocols, options = {}) { | ||
this._listeners = { | ||
error: [], | ||
message: [], | ||
open: [], | ||
close: [], | ||
}; | ||
this._retryCount = -1; | ||
this._shouldReconnect = true; | ||
this._connectLock = false; | ||
this._binaryType = 'blob'; | ||
this.eventToHandler = new Map([ | ||
['open', this._handleOpen.bind(this)], | ||
['close', this._handleClose.bind(this)], | ||
['error', this._handleError.bind(this)], | ||
['message', this._handleMessage.bind(this)], | ||
]); | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to CLOSED | ||
*/ | ||
this.onclose = undefined; | ||
/** | ||
* An event listener to be called when an error occurs | ||
*/ | ||
this.onerror = undefined; | ||
/** | ||
* An event listener to be called when a message is received from the server | ||
*/ | ||
this.onmessage = undefined; | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to OPEN; | ||
* this indicates that the connection is ready to send and receive data | ||
*/ | ||
this.onopen = undefined; | ||
this._url = url; | ||
this._protocols = protocols; | ||
this._options = options; | ||
this._connect(); | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
static get CONNECTING() { | ||
return 0; | ||
} | ||
static get OPEN() { | ||
return 1; | ||
} | ||
static get CLOSING() { | ||
return 2; | ||
} | ||
static get CLOSED() { | ||
return 3; | ||
} | ||
get CONNECTING() { | ||
return ReconnectingWebSocket.CONNECTING; | ||
} | ||
get OPEN() { | ||
return ReconnectingWebSocket.OPEN; | ||
} | ||
get CLOSING() { | ||
return ReconnectingWebSocket.CLOSING; | ||
} | ||
get CLOSED() { | ||
return ReconnectingWebSocket.CLOSED; | ||
} | ||
get binaryType() { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
} | ||
set binaryType(value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
} | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
get retryCount() { | ||
return Math.max(this._retryCount, 0); | ||
} | ||
/** | ||
* The number of bytes of data that have been queued using calls to send() but not yet | ||
* transmitted to the network. This value resets to zero once all queued data has been sent. | ||
* This value does not reset to zero when the connection is closed; if you keep calling send(), | ||
* this will continue to climb. Read only | ||
*/ | ||
get bufferedAmount() { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
} | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
get extensions() { | ||
return this._ws ? this._ws.extensions : ''; | ||
} | ||
/** | ||
* A string indicating the name of the sub-protocol the server selected; | ||
* this will be one of the strings specified in the protocols parameter when creating the | ||
* WebSocket object | ||
*/ | ||
get protocol() { | ||
return this._ws ? this._ws.protocol : ''; | ||
} | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
get readyState() { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
} | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
get url() { | ||
return this._ws ? this._ws.url : ''; | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt, if any. If the connection is already | ||
* CLOSED, this method does nothing | ||
*/ | ||
close(code, reason) { | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt and connects again. | ||
* Resets retry counter; | ||
*/ | ||
reconnect(code, reason) { | ||
this._shouldReconnect = true; | ||
this._retryCount = -1; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
this._connect(); | ||
} | ||
this._disconnect(code, reason); | ||
this._connect(); | ||
} | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data) { | ||
if (this._ws) { | ||
this._ws.send(data); | ||
} | ||
} | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
} | ||
} | ||
_debug(...params) { | ||
if (this._options.debug) { | ||
// tslint:disable-next-line | ||
console.log('RWS>', ...params); | ||
} | ||
} | ||
_getNextDelay() { | ||
let delay = 0; | ||
if (this._retryCount > 0) { | ||
const { reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor, minReconnectionDelay = DEFAULT.minReconnectionDelay, maxReconnectionDelay = DEFAULT.maxReconnectionDelay, } = this._options; | ||
delay = | ||
minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
if (delay > maxReconnectionDelay) { | ||
delay = maxReconnectionDelay; | ||
} | ||
} | ||
this._debug('next delay', delay); | ||
return delay; | ||
} | ||
_wait() { | ||
return new Promise(resolve => { | ||
setTimeout(resolve, this._getNextDelay()); | ||
}); | ||
} | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
_getNextUrl(urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
return Promise.resolve(urlProvider); | ||
} | ||
if (typeof urlProvider === 'function') { | ||
const url = urlProvider(); | ||
if (typeof url === 'string') { | ||
return Promise.resolve(url); | ||
} | ||
if (url.then) { | ||
return url; | ||
} | ||
} | ||
throw Error('Invalid URL'); | ||
} | ||
_connect() { | ||
if (this._connectLock) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
const { maxRetries = DEFAULT.maxRetries, connectionTimeout = DEFAULT.connectionTimeout, WebSocket = getGlobalWebSocket(), } = this._options; | ||
if (this._retryCount >= maxRetries) { | ||
this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
return; | ||
} | ||
this._retryCount++; | ||
this._debug('connect', this._retryCount); | ||
this._removeListeners(); | ||
if (!isWebSocket(WebSocket)) { | ||
throw Error('No valid WebSocket class provided'); | ||
} | ||
this._wait() | ||
.then(() => this._getNextUrl(this._url)) | ||
.then(url => { | ||
this._debug('connect', { url, protocols: this._protocols }); | ||
this._ws = new WebSocket(url, this._protocols); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
this._connectLock = false; | ||
this._addListeners(); | ||
this._connectTimeout = setTimeout(() => this._handleTimeout(), connectionTimeout); | ||
}); | ||
} | ||
_handleTimeout() { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
_disconnect(code, reason) { | ||
clearTimeout(this._connectTimeout); | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._removeListeners(); | ||
try { | ||
this._ws.close(code, reason); | ||
this._handleClose(new CloseEvent(code, reason, this)); | ||
} | ||
catch (error) { | ||
// ignore | ||
} | ||
} | ||
_acceptOpen() { | ||
this._retryCount = 0; | ||
} | ||
_handleOpen(event) { | ||
this._debug('open event'); | ||
const { minUptime = DEFAULT.minUptime } = this._options; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
} | ||
_handleMessage(event) { | ||
this._debug('message event'); | ||
if (this.onmessage) { | ||
this.onmessage(event); | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
} | ||
_handleError(event) { | ||
this._debug('error event', event.message); | ||
this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
if (this.onerror) { | ||
this.onerror(event); | ||
} | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._connect(); | ||
} | ||
_handleClose(event) { | ||
this._debug('close event'); | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
} | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
_removeListeners() { | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._debug('removeListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
_addListeners() { | ||
this._debug('addListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} | ||
} | ||
return _arr; | ||
} | ||
return ReconnectingWebSocket; | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
var Event = function Event(type, target) { | ||
classCallCheck(this, Event); | ||
this.target = target; | ||
this.type = type; | ||
}; | ||
var ErrorEvent = function (_Event) { | ||
inherits(ErrorEvent, _Event); | ||
function ErrorEvent(error, target) { | ||
classCallCheck(this, ErrorEvent); | ||
var _this = possibleConstructorReturn(this, (ErrorEvent.__proto__ || Object.getPrototypeOf(ErrorEvent)).call(this, 'error', target)); | ||
_this.message = error.message; | ||
_this.error = error; | ||
return _this; | ||
} | ||
return ErrorEvent; | ||
}(Event); | ||
var CloseEvent = function (_Event2) { | ||
inherits(CloseEvent, _Event2); | ||
function CloseEvent() { | ||
var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000; | ||
var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
var target = arguments[2]; | ||
classCallCheck(this, CloseEvent); | ||
var _this2 = possibleConstructorReturn(this, (CloseEvent.__proto__ || Object.getPrototypeOf(CloseEvent)).call(this, 'close', target)); | ||
_this2.wasClean = true; | ||
_this2.code = code; | ||
_this2.reason = reason; | ||
return _this2; | ||
} | ||
return CloseEvent; | ||
}(Event); | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
var getGlobalWebSocket = function getGlobalWebSocket() { | ||
if (typeof WebSocket !== 'undefined') { | ||
// @ts-ignore | ||
return WebSocket; | ||
} | ||
}; | ||
/** | ||
* Returns true if given argument looks like a WebSocket class | ||
*/ | ||
var isWebSocket = function isWebSocket(w) { | ||
return typeof w === 'function' && w.CLOSING === 2; | ||
}; | ||
var DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
minReconnectionDelay: 1000 + Math.random() * 4000, | ||
minUptime: 5000, | ||
reconnectionDelayGrowFactor: 1.3, | ||
connectionTimeout: 4000, | ||
maxRetries: Infinity, | ||
debug: false | ||
}; | ||
var ReconnectingWebSocket = function () { | ||
function ReconnectingWebSocket(url, protocols) { | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
classCallCheck(this, ReconnectingWebSocket); | ||
this._listeners = { | ||
error: [], | ||
message: [], | ||
open: [], | ||
close: [] | ||
}; | ||
this._retryCount = -1; | ||
this._shouldReconnect = true; | ||
this._connectLock = false; | ||
this._binaryType = 'blob'; | ||
this.eventToHandler = new Map([['open', this._handleOpen.bind(this)], ['close', this._handleClose.bind(this)], ['error', this._handleError.bind(this)], ['message', this._handleMessage.bind(this)]]); | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to CLOSED | ||
*/ | ||
this.onclose = undefined; | ||
/** | ||
* An event listener to be called when an error occurs | ||
*/ | ||
this.onerror = undefined; | ||
/** | ||
* An event listener to be called when a message is received from the server | ||
*/ | ||
this.onmessage = undefined; | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to OPEN; | ||
* this indicates that the connection is ready to send and receive data | ||
*/ | ||
this.onopen = undefined; | ||
this._url = url; | ||
this._protocols = protocols; | ||
this._options = options; | ||
this._connect(); | ||
} | ||
createClass(ReconnectingWebSocket, [{ | ||
key: 'close', | ||
/** | ||
* Closes the WebSocket connection or connection attempt, if any. If the connection is already | ||
* CLOSED, this method does nothing | ||
*/ | ||
value: function close(code, reason) { | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt and connects again. | ||
* Resets retry counter; | ||
*/ | ||
}, { | ||
key: 'reconnect', | ||
value: function reconnect(code, reason) { | ||
this._shouldReconnect = true; | ||
this._retryCount = -1; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
this._connect(); | ||
} | ||
this._disconnect(code, reason); | ||
this._connect(); | ||
} | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
}, { | ||
key: 'send', | ||
value: function send(data) { | ||
if (this._ws) { | ||
this._ws.send(data); | ||
} | ||
} | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
}, { | ||
key: 'addEventListener', | ||
value: function addEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
/** | ||
* Removes an event listener | ||
*/ | ||
}, { | ||
key: 'removeEventListener', | ||
value: function removeEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(function (l) { | ||
return l !== listener; | ||
}); | ||
} | ||
} | ||
}, { | ||
key: '_debug', | ||
value: function _debug() { | ||
if (this._options.debug) { | ||
var _console; | ||
for (var _len = arguments.length, params = Array(_len), _key = 0; _key < _len; _key++) { | ||
params[_key] = arguments[_key]; | ||
} | ||
// tslint:disable-next-line | ||
(_console = console).log.apply(_console, ['RWS>'].concat(params)); | ||
} | ||
} | ||
}, { | ||
key: '_getNextDelay', | ||
value: function _getNextDelay() { | ||
var delay = 0; | ||
if (this._retryCount > 0) { | ||
var _options = this._options, | ||
_options$reconnection = _options.reconnectionDelayGrowFactor, | ||
reconnectionDelayGrowFactor = _options$reconnection === undefined ? DEFAULT.reconnectionDelayGrowFactor : _options$reconnection, | ||
_options$minReconnect = _options.minReconnectionDelay, | ||
minReconnectionDelay = _options$minReconnect === undefined ? DEFAULT.minReconnectionDelay : _options$minReconnect, | ||
_options$maxReconnect = _options.maxReconnectionDelay, | ||
maxReconnectionDelay = _options$maxReconnect === undefined ? DEFAULT.maxReconnectionDelay : _options$maxReconnect; | ||
delay = minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
if (delay > maxReconnectionDelay) { | ||
delay = maxReconnectionDelay; | ||
} | ||
} | ||
this._debug('next delay', delay); | ||
return delay; | ||
} | ||
}, { | ||
key: '_wait', | ||
value: function _wait() { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, _this._getNextDelay()); | ||
}); | ||
} | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
}, { | ||
key: '_getNextUrl', | ||
value: function _getNextUrl(urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
return Promise.resolve(urlProvider); | ||
} | ||
if (typeof urlProvider === 'function') { | ||
var url = urlProvider(); | ||
if (typeof url === 'string') { | ||
return Promise.resolve(url); | ||
} | ||
if (url.then) { | ||
return url; | ||
} | ||
} | ||
throw Error('Invalid URL'); | ||
} | ||
}, { | ||
key: '_connect', | ||
value: function _connect() { | ||
var _this2 = this; | ||
if (this._connectLock) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
var _options2 = this._options, | ||
_options2$maxRetries = _options2.maxRetries, | ||
maxRetries = _options2$maxRetries === undefined ? DEFAULT.maxRetries : _options2$maxRetries, | ||
_options2$connectionT = _options2.connectionTimeout, | ||
connectionTimeout = _options2$connectionT === undefined ? DEFAULT.connectionTimeout : _options2$connectionT, | ||
_options2$WebSocket = _options2.WebSocket, | ||
WebSocket = _options2$WebSocket === undefined ? getGlobalWebSocket() : _options2$WebSocket; | ||
if (this._retryCount >= maxRetries) { | ||
this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
return; | ||
} | ||
this._retryCount++; | ||
this._debug('connect', this._retryCount); | ||
this._removeListeners(); | ||
if (!isWebSocket(WebSocket)) { | ||
throw Error('No valid WebSocket class provided'); | ||
} | ||
this._wait().then(function () { | ||
return _this2._getNextUrl(_this2._url); | ||
}).then(function (url) { | ||
_this2._debug('connect', { url: url, protocols: _this2._protocols }); | ||
_this2._ws = new WebSocket(url, _this2._protocols); | ||
// @ts-ignore | ||
_this2._ws.binaryType = _this2._binaryType; | ||
_this2._connectLock = false; | ||
_this2._addListeners(); | ||
_this2._connectTimeout = setTimeout(function () { | ||
return _this2._handleTimeout(); | ||
}, connectionTimeout); | ||
}); | ||
} | ||
}, { | ||
key: '_handleTimeout', | ||
value: function _handleTimeout() { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
}, { | ||
key: '_disconnect', | ||
value: function _disconnect(code, reason) { | ||
clearTimeout(this._connectTimeout); | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._removeListeners(); | ||
try { | ||
this._ws.close(code, reason); | ||
this._handleClose(new CloseEvent(code, reason, this)); | ||
} catch (error) { | ||
// ignore | ||
} | ||
} | ||
}, { | ||
key: '_acceptOpen', | ||
value: function _acceptOpen() { | ||
this._retryCount = 0; | ||
} | ||
}, { | ||
key: '_handleOpen', | ||
value: function _handleOpen(event) { | ||
var _this3 = this; | ||
this._debug('open event'); | ||
var _options$minUptime = this._options.minUptime, | ||
minUptime = _options$minUptime === undefined ? DEFAULT.minUptime : _options$minUptime; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(function () { | ||
return _this3._acceptOpen(); | ||
}, minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
}, { | ||
key: '_handleMessage', | ||
value: function _handleMessage(event) { | ||
this._debug('message event'); | ||
if (this.onmessage) { | ||
this.onmessage(event); | ||
} | ||
this._listeners.message.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
}, { | ||
key: '_handleError', | ||
value: function _handleError(event) { | ||
this._debug('error event', event.message); | ||
// https://github.com/pladaria/reconnecting-websocket/pull/69 | ||
this._disconnect(4008, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
if (this.onerror) { | ||
this.onerror(event); | ||
} | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
this._connect(); | ||
} | ||
}, { | ||
key: '_handleClose', | ||
value: function _handleClose(event) { | ||
this._debug('close event'); | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
}, { | ||
key: '_removeListeners', | ||
value: function _removeListeners() { | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._debug('removeListeners'); | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = this.eventToHandler[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _ref = _step.value; | ||
var _ref2 = slicedToArray(_ref, 2); | ||
var type = _ref2[0]; | ||
var handler = _ref2[1]; | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
}, { | ||
key: '_addListeners', | ||
value: function _addListeners() { | ||
this._debug('addListeners'); | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = this.eventToHandler[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var _ref3 = _step2.value; | ||
var _ref4 = slicedToArray(_ref3, 2); | ||
var type = _ref4[0]; | ||
var handler = _ref4[1]; | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'CONNECTING', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CONNECTING; | ||
} | ||
}, { | ||
key: 'OPEN', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.OPEN; | ||
} | ||
}, { | ||
key: 'CLOSING', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CLOSING; | ||
} | ||
}, { | ||
key: 'CLOSED', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CLOSED; | ||
} | ||
}, { | ||
key: 'binaryType', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
}, | ||
set: function set$$1(value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
} | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
}, { | ||
key: 'retryCount', | ||
get: function get$$1() { | ||
return Math.max(this._retryCount, 0); | ||
} | ||
/** | ||
* The number of bytes of data that have been queued using calls to send() but not yet | ||
* transmitted to the network. This value resets to zero once all queued data has been sent. | ||
* This value does not reset to zero when the connection is closed; if you keep calling send(), | ||
* this will continue to climb. Read only | ||
*/ | ||
}, { | ||
key: 'bufferedAmount', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
} | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
}, { | ||
key: 'extensions', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.extensions : ''; | ||
} | ||
/** | ||
* A string indicating the name of the sub-protocol the server selected; | ||
* this will be one of the strings specified in the protocols parameter when creating the | ||
* WebSocket object | ||
*/ | ||
}, { | ||
key: 'protocol', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.protocol : ''; | ||
} | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
}, { | ||
key: 'readyState', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
} | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
}, { | ||
key: 'url', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.url : ''; | ||
} | ||
}], [{ | ||
key: 'CONNECTING', | ||
get: function get$$1() { | ||
return 0; | ||
} | ||
}, { | ||
key: 'OPEN', | ||
get: function get$$1() { | ||
return 1; | ||
} | ||
}, { | ||
key: 'CLOSING', | ||
get: function get$$1() { | ||
return 2; | ||
} | ||
}, { | ||
key: 'CLOSED', | ||
get: function get$$1() { | ||
return 3; | ||
} | ||
}]); | ||
return ReconnectingWebSocket; | ||
}(); | ||
return ReconnectingWebSocket; | ||
}); |
'use strict'; | ||
class Event { | ||
constructor(type, target) { | ||
this.target = target; | ||
this.type = type; | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
}; | ||
var createClass = 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); | ||
} | ||
} | ||
class ErrorEvent extends Event { | ||
constructor(error, target) { | ||
super('error', target); | ||
this.message = error.message; | ||
this.error = error; | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
} | ||
class CloseEvent extends Event { | ||
constructor(code = 1000, reason = '', target) { | ||
super('close', target); | ||
this.wasClean = true; | ||
this.code = code; | ||
this.reason = reason; | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
} | ||
} | ||
return _arr; | ||
} | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
var Event = function Event(type, target) { | ||
classCallCheck(this, Event); | ||
this.target = target; | ||
this.type = type; | ||
}; | ||
var ErrorEvent = function (_Event) { | ||
inherits(ErrorEvent, _Event); | ||
function ErrorEvent(error, target) { | ||
classCallCheck(this, ErrorEvent); | ||
var _this = possibleConstructorReturn(this, (ErrorEvent.__proto__ || Object.getPrototypeOf(ErrorEvent)).call(this, 'error', target)); | ||
_this.message = error.message; | ||
_this.error = error; | ||
return _this; | ||
} | ||
return ErrorEvent; | ||
}(Event); | ||
var CloseEvent = function (_Event2) { | ||
inherits(CloseEvent, _Event2); | ||
function CloseEvent() { | ||
var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000; | ||
var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
var target = arguments[2]; | ||
classCallCheck(this, CloseEvent); | ||
var _this2 = possibleConstructorReturn(this, (CloseEvent.__proto__ || Object.getPrototypeOf(CloseEvent)).call(this, 'close', target)); | ||
_this2.wasClean = true; | ||
_this2.code = code; | ||
_this2.reason = reason; | ||
return _this2; | ||
} | ||
return CloseEvent; | ||
}(Event); | ||
/*! | ||
@@ -31,3 +136,3 @@ * Reconnecting WebSocket | ||
*/ | ||
const getGlobalWebSocket = () => { | ||
var getGlobalWebSocket = function getGlobalWebSocket() { | ||
if (typeof WebSocket !== 'undefined') { | ||
@@ -41,4 +146,6 @@ // @ts-ignore | ||
*/ | ||
const isWebSocket = (w) => typeof w === 'function' && w.CLOSING === 2; | ||
const DEFAULT = { | ||
var isWebSocket = function isWebSocket(w) { | ||
return typeof w === 'function' && w.CLOSING === 2; | ||
}; | ||
var DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
@@ -50,6 +157,10 @@ minReconnectionDelay: 1000 + Math.random() * 4000, | ||
maxRetries: Infinity, | ||
debug: false, | ||
debug: false | ||
}; | ||
class ReconnectingWebSocket { | ||
constructor(url, protocols, options = {}) { | ||
var ReconnectingWebSocket = function () { | ||
function ReconnectingWebSocket(url, protocols) { | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
classCallCheck(this, ReconnectingWebSocket); | ||
this._listeners = { | ||
@@ -59,3 +170,3 @@ error: [], | ||
open: [], | ||
close: [], | ||
close: [] | ||
}; | ||
@@ -66,8 +177,3 @@ this._retryCount = -1; | ||
this._binaryType = 'blob'; | ||
this.eventToHandler = new Map([ | ||
['open', this._handleOpen.bind(this)], | ||
['close', this._handleClose.bind(this)], | ||
['error', this._handleError.bind(this)], | ||
['message', this._handleMessage.bind(this)], | ||
]); | ||
this.eventToHandler = new Map([['open', this._handleOpen.bind(this)], ['close', this._handleClose.bind(this)], ['error', this._handleError.bind(this)], ['message', this._handleMessage.bind(this)]]); | ||
/** | ||
@@ -95,279 +201,457 @@ * An event listener to be called when the WebSocket connection's readyState changes to CLOSED | ||
} | ||
static get CONNECTING() { | ||
return 0; | ||
} | ||
static get OPEN() { | ||
return 1; | ||
} | ||
static get CLOSING() { | ||
return 2; | ||
} | ||
static get CLOSED() { | ||
return 3; | ||
} | ||
get CONNECTING() { | ||
return ReconnectingWebSocket.CONNECTING; | ||
} | ||
get OPEN() { | ||
return ReconnectingWebSocket.OPEN; | ||
} | ||
get CLOSING() { | ||
return ReconnectingWebSocket.CLOSING; | ||
} | ||
get CLOSED() { | ||
return ReconnectingWebSocket.CLOSED; | ||
} | ||
get binaryType() { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
} | ||
set binaryType(value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
createClass(ReconnectingWebSocket, [{ | ||
key: 'close', | ||
/** | ||
* Closes the WebSocket connection or connection attempt, if any. If the connection is already | ||
* CLOSED, this method does nothing | ||
*/ | ||
value: function close(code, reason) { | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
} | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
get retryCount() { | ||
return Math.max(this._retryCount, 0); | ||
} | ||
/** | ||
* The number of bytes of data that have been queued using calls to send() but not yet | ||
* transmitted to the network. This value resets to zero once all queued data has been sent. | ||
* This value does not reset to zero when the connection is closed; if you keep calling send(), | ||
* this will continue to climb. Read only | ||
*/ | ||
get bufferedAmount() { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
} | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
get extensions() { | ||
return this._ws ? this._ws.extensions : ''; | ||
} | ||
/** | ||
* A string indicating the name of the sub-protocol the server selected; | ||
* this will be one of the strings specified in the protocols parameter when creating the | ||
* WebSocket object | ||
*/ | ||
get protocol() { | ||
return this._ws ? this._ws.protocol : ''; | ||
} | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
get readyState() { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
} | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
get url() { | ||
return this._ws ? this._ws.url : ''; | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt, if any. If the connection is already | ||
* CLOSED, this method does nothing | ||
*/ | ||
close(code, reason) { | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt and connects again. | ||
* Resets retry counter; | ||
*/ | ||
reconnect(code, reason) { | ||
this._shouldReconnect = true; | ||
this._retryCount = -1; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
/** | ||
* Closes the WebSocket connection or connection attempt and connects again. | ||
* Resets retry counter; | ||
*/ | ||
}, { | ||
key: 'reconnect', | ||
value: function reconnect(code, reason) { | ||
this._shouldReconnect = true; | ||
this._retryCount = -1; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
this._connect(); | ||
} | ||
this._disconnect(code, reason); | ||
this._connect(); | ||
} | ||
this._disconnect(code, reason); | ||
this._connect(); | ||
} | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data) { | ||
if (this._ws) { | ||
this._ws.send(data); | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
}, { | ||
key: 'send', | ||
value: function send(data) { | ||
if (this._ws) { | ||
this._ws.send(data); | ||
} | ||
} | ||
} | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
}, { | ||
key: 'addEventListener', | ||
value: function addEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
} | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
/** | ||
* Removes an event listener | ||
*/ | ||
}, { | ||
key: 'removeEventListener', | ||
value: function removeEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(function (l) { | ||
return l !== listener; | ||
}); | ||
} | ||
} | ||
} | ||
_debug(...params) { | ||
if (this._options.debug) { | ||
// tslint:disable-next-line | ||
console.log('RWS>', ...params); | ||
}, { | ||
key: '_debug', | ||
value: function _debug() { | ||
if (this._options.debug) { | ||
var _console; | ||
for (var _len = arguments.length, params = Array(_len), _key = 0; _key < _len; _key++) { | ||
params[_key] = arguments[_key]; | ||
} | ||
// tslint:disable-next-line | ||
(_console = console).log.apply(_console, ['RWS>'].concat(params)); | ||
} | ||
} | ||
} | ||
_getNextDelay() { | ||
let delay = 0; | ||
if (this._retryCount > 0) { | ||
const { reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor, minReconnectionDelay = DEFAULT.minReconnectionDelay, maxReconnectionDelay = DEFAULT.maxReconnectionDelay, } = this._options; | ||
delay = | ||
minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
if (delay > maxReconnectionDelay) { | ||
delay = maxReconnectionDelay; | ||
}, { | ||
key: '_getNextDelay', | ||
value: function _getNextDelay() { | ||
var delay = 0; | ||
if (this._retryCount > 0) { | ||
var _options = this._options, | ||
_options$reconnection = _options.reconnectionDelayGrowFactor, | ||
reconnectionDelayGrowFactor = _options$reconnection === undefined ? DEFAULT.reconnectionDelayGrowFactor : _options$reconnection, | ||
_options$minReconnect = _options.minReconnectionDelay, | ||
minReconnectionDelay = _options$minReconnect === undefined ? DEFAULT.minReconnectionDelay : _options$minReconnect, | ||
_options$maxReconnect = _options.maxReconnectionDelay, | ||
maxReconnectionDelay = _options$maxReconnect === undefined ? DEFAULT.maxReconnectionDelay : _options$maxReconnect; | ||
delay = minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
if (delay > maxReconnectionDelay) { | ||
delay = maxReconnectionDelay; | ||
} | ||
} | ||
this._debug('next delay', delay); | ||
return delay; | ||
} | ||
this._debug('next delay', delay); | ||
return delay; | ||
} | ||
_wait() { | ||
return new Promise(resolve => { | ||
setTimeout(resolve, this._getNextDelay()); | ||
}); | ||
} | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
_getNextUrl(urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
return Promise.resolve(urlProvider); | ||
}, { | ||
key: '_wait', | ||
value: function _wait() { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, _this._getNextDelay()); | ||
}); | ||
} | ||
if (typeof urlProvider === 'function') { | ||
const url = urlProvider(); | ||
if (typeof url === 'string') { | ||
return Promise.resolve(url); | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
}, { | ||
key: '_getNextUrl', | ||
value: function _getNextUrl(urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
return Promise.resolve(urlProvider); | ||
} | ||
if (url.then) { | ||
return url; | ||
if (typeof urlProvider === 'function') { | ||
var url = urlProvider(); | ||
if (typeof url === 'string') { | ||
return Promise.resolve(url); | ||
} | ||
if (url.then) { | ||
return url; | ||
} | ||
} | ||
throw Error('Invalid URL'); | ||
} | ||
throw Error('Invalid URL'); | ||
} | ||
_connect() { | ||
if (this._connectLock) { | ||
return; | ||
}, { | ||
key: '_connect', | ||
value: function _connect() { | ||
var _this2 = this; | ||
if (this._connectLock) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
var _options2 = this._options, | ||
_options2$maxRetries = _options2.maxRetries, | ||
maxRetries = _options2$maxRetries === undefined ? DEFAULT.maxRetries : _options2$maxRetries, | ||
_options2$connectionT = _options2.connectionTimeout, | ||
connectionTimeout = _options2$connectionT === undefined ? DEFAULT.connectionTimeout : _options2$connectionT, | ||
_options2$WebSocket = _options2.WebSocket, | ||
WebSocket = _options2$WebSocket === undefined ? getGlobalWebSocket() : _options2$WebSocket; | ||
if (this._retryCount >= maxRetries) { | ||
this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
return; | ||
} | ||
this._retryCount++; | ||
this._debug('connect', this._retryCount); | ||
this._removeListeners(); | ||
if (!isWebSocket(WebSocket)) { | ||
throw Error('No valid WebSocket class provided'); | ||
} | ||
this._wait().then(function () { | ||
return _this2._getNextUrl(_this2._url); | ||
}).then(function (url) { | ||
_this2._debug('connect', { url: url, protocols: _this2._protocols }); | ||
_this2._ws = new WebSocket(url, _this2._protocols); | ||
// @ts-ignore | ||
_this2._ws.binaryType = _this2._binaryType; | ||
_this2._connectLock = false; | ||
_this2._addListeners(); | ||
_this2._connectTimeout = setTimeout(function () { | ||
return _this2._handleTimeout(); | ||
}, connectionTimeout); | ||
}); | ||
} | ||
this._connectLock = true; | ||
const { maxRetries = DEFAULT.maxRetries, connectionTimeout = DEFAULT.connectionTimeout, WebSocket = getGlobalWebSocket(), } = this._options; | ||
if (this._retryCount >= maxRetries) { | ||
this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
return; | ||
}, { | ||
key: '_handleTimeout', | ||
value: function _handleTimeout() { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
this._retryCount++; | ||
this._debug('connect', this._retryCount); | ||
this._removeListeners(); | ||
if (!isWebSocket(WebSocket)) { | ||
throw Error('No valid WebSocket class provided'); | ||
}, { | ||
key: '_disconnect', | ||
value: function _disconnect(code, reason) { | ||
clearTimeout(this._connectTimeout); | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._removeListeners(); | ||
try { | ||
this._ws.close(code, reason); | ||
this._handleClose(new CloseEvent(code, reason, this)); | ||
} catch (error) { | ||
// ignore | ||
} | ||
} | ||
this._wait() | ||
.then(() => this._getNextUrl(this._url)) | ||
.then(url => { | ||
this._debug('connect', { url, protocols: this._protocols }); | ||
this._ws = new WebSocket(url, this._protocols); | ||
}, { | ||
key: '_acceptOpen', | ||
value: function _acceptOpen() { | ||
this._retryCount = 0; | ||
} | ||
}, { | ||
key: '_handleOpen', | ||
value: function _handleOpen(event) { | ||
var _this3 = this; | ||
this._debug('open event'); | ||
var _options$minUptime = this._options.minUptime, | ||
minUptime = _options$minUptime === undefined ? DEFAULT.minUptime : _options$minUptime; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(function () { | ||
return _this3._acceptOpen(); | ||
}, minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
this._connectLock = false; | ||
this._addListeners(); | ||
this._connectTimeout = setTimeout(() => this._handleTimeout(), connectionTimeout); | ||
}); | ||
} | ||
_handleTimeout() { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
_disconnect(code, reason) { | ||
clearTimeout(this._connectTimeout); | ||
if (!this._ws) { | ||
return; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
this._removeListeners(); | ||
try { | ||
this._ws.close(code, reason); | ||
this._handleClose(new CloseEvent(code, reason, this)); | ||
}, { | ||
key: '_handleMessage', | ||
value: function _handleMessage(event) { | ||
this._debug('message event'); | ||
if (this.onmessage) { | ||
this.onmessage(event); | ||
} | ||
this._listeners.message.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
catch (error) { | ||
// ignore | ||
}, { | ||
key: '_handleError', | ||
value: function _handleError(event) { | ||
this._debug('error event', event.message); | ||
// https://github.com/pladaria/reconnecting-websocket/pull/69 | ||
this._disconnect(4008, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
if (this.onerror) { | ||
this.onerror(event); | ||
} | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
this._connect(); | ||
} | ||
} | ||
_acceptOpen() { | ||
this._retryCount = 0; | ||
} | ||
_handleOpen(event) { | ||
this._debug('open event'); | ||
const { minUptime = DEFAULT.minUptime } = this._options; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
}, { | ||
key: '_handleClose', | ||
value: function _handleClose(event) { | ||
this._debug('close event'); | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
} | ||
_handleMessage(event) { | ||
this._debug('message event'); | ||
if (this.onmessage) { | ||
this.onmessage(event); | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
}, { | ||
key: '_removeListeners', | ||
value: function _removeListeners() { | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._debug('removeListeners'); | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = this.eventToHandler[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _ref = _step.value; | ||
var _ref2 = slicedToArray(_ref, 2); | ||
var type = _ref2[0]; | ||
var handler = _ref2[1]; | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
} | ||
_handleError(event) { | ||
this._debug('error event', event.message); | ||
this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
if (this.onerror) { | ||
this.onerror(event); | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
}, { | ||
key: '_addListeners', | ||
value: function _addListeners() { | ||
this._debug('addListeners'); | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = this.eventToHandler[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var _ref3 = _step2.value; | ||
var _ref4 = slicedToArray(_ref3, 2); | ||
var type = _ref4[0]; | ||
var handler = _ref4[1]; | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
} | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._connect(); | ||
} | ||
_handleClose(event) { | ||
this._debug('close event'); | ||
if (this.onclose) { | ||
this.onclose(event); | ||
}, { | ||
key: 'CONNECTING', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CONNECTING; | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
} | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
_removeListeners() { | ||
if (!this._ws) { | ||
return; | ||
}, { | ||
key: 'OPEN', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.OPEN; | ||
} | ||
this._debug('removeListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.removeEventListener(type, handler); | ||
}, { | ||
key: 'CLOSING', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CLOSING; | ||
} | ||
} | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
_addListeners() { | ||
this._debug('addListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.addEventListener(type, handler); | ||
}, { | ||
key: 'CLOSED', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CLOSED; | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'binaryType', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
}, | ||
set: function set$$1(value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
} | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
}, { | ||
key: 'retryCount', | ||
get: function get$$1() { | ||
return Math.max(this._retryCount, 0); | ||
} | ||
/** | ||
* The number of bytes of data that have been queued using calls to send() but not yet | ||
* transmitted to the network. This value resets to zero once all queued data has been sent. | ||
* This value does not reset to zero when the connection is closed; if you keep calling send(), | ||
* this will continue to climb. Read only | ||
*/ | ||
}, { | ||
key: 'bufferedAmount', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
} | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
}, { | ||
key: 'extensions', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.extensions : ''; | ||
} | ||
/** | ||
* A string indicating the name of the sub-protocol the server selected; | ||
* this will be one of the strings specified in the protocols parameter when creating the | ||
* WebSocket object | ||
*/ | ||
}, { | ||
key: 'protocol', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.protocol : ''; | ||
} | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
}, { | ||
key: 'readyState', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
} | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
}, { | ||
key: 'url', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.url : ''; | ||
} | ||
}], [{ | ||
key: 'CONNECTING', | ||
get: function get$$1() { | ||
return 0; | ||
} | ||
}, { | ||
key: 'OPEN', | ||
get: function get$$1() { | ||
return 1; | ||
} | ||
}, { | ||
key: 'CLOSING', | ||
get: function get$$1() { | ||
return 2; | ||
} | ||
}, { | ||
key: 'CLOSED', | ||
get: function get$$1() { | ||
return 3; | ||
} | ||
}]); | ||
return ReconnectingWebSocket; | ||
}(); | ||
module.exports = ReconnectingWebSocket; |
var ReconnectingWebSocket = (function () { | ||
'use strict'; | ||
'use strict'; | ||
class Event { | ||
constructor(type, target) { | ||
this.target = target; | ||
this.type = type; | ||
} | ||
var classCallCheck = function (instance, Constructor) { | ||
if (!(instance instanceof Constructor)) { | ||
throw new TypeError("Cannot call a class as a function"); | ||
} | ||
class ErrorEvent extends Event { | ||
constructor(error, target) { | ||
super('error', target); | ||
this.message = error.message; | ||
this.error = error; | ||
} | ||
}; | ||
var createClass = 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); | ||
} | ||
} | ||
class CloseEvent extends Event { | ||
constructor(code = 1000, reason = '', target) { | ||
super('close', target); | ||
this.wasClean = true; | ||
this.code = code; | ||
this.reason = reason; | ||
} | ||
return function (Constructor, protoProps, staticProps) { | ||
if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||
if (staticProps) defineProperties(Constructor, staticProps); | ||
return Constructor; | ||
}; | ||
}(); | ||
var inherits = function (subClass, superClass) { | ||
if (typeof superClass !== "function" && superClass !== null) { | ||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); | ||
} | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
const getGlobalWebSocket = () => { | ||
if (typeof WebSocket !== 'undefined') { | ||
// @ts-ignore | ||
return WebSocket; | ||
subClass.prototype = Object.create(superClass && superClass.prototype, { | ||
constructor: { | ||
value: subClass, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; | ||
}; | ||
var possibleConstructorReturn = function (self, call) { | ||
if (!self) { | ||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); | ||
} | ||
return call && (typeof call === "object" || typeof call === "function") ? call : self; | ||
}; | ||
var slicedToArray = function () { | ||
function sliceIterator(arr, i) { | ||
var _arr = []; | ||
var _n = true; | ||
var _d = false; | ||
var _e = undefined; | ||
try { | ||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { | ||
_arr.push(_s.value); | ||
if (i && _arr.length === i) break; | ||
} | ||
}; | ||
/** | ||
* Returns true if given argument looks like a WebSocket class | ||
*/ | ||
const isWebSocket = (w) => typeof w === 'function' && w.CLOSING === 2; | ||
const DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
minReconnectionDelay: 1000 + Math.random() * 4000, | ||
minUptime: 5000, | ||
reconnectionDelayGrowFactor: 1.3, | ||
connectionTimeout: 4000, | ||
maxRetries: Infinity, | ||
debug: false, | ||
}; | ||
class ReconnectingWebSocket { | ||
constructor(url, protocols, options = {}) { | ||
this._listeners = { | ||
error: [], | ||
message: [], | ||
open: [], | ||
close: [], | ||
}; | ||
this._retryCount = -1; | ||
this._shouldReconnect = true; | ||
this._connectLock = false; | ||
this._binaryType = 'blob'; | ||
this.eventToHandler = new Map([ | ||
['open', this._handleOpen.bind(this)], | ||
['close', this._handleClose.bind(this)], | ||
['error', this._handleError.bind(this)], | ||
['message', this._handleMessage.bind(this)], | ||
]); | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to CLOSED | ||
*/ | ||
this.onclose = undefined; | ||
/** | ||
* An event listener to be called when an error occurs | ||
*/ | ||
this.onerror = undefined; | ||
/** | ||
* An event listener to be called when a message is received from the server | ||
*/ | ||
this.onmessage = undefined; | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to OPEN; | ||
* this indicates that the connection is ready to send and receive data | ||
*/ | ||
this.onopen = undefined; | ||
this._url = url; | ||
this._protocols = protocols; | ||
this._options = options; | ||
this._connect(); | ||
} catch (err) { | ||
_d = true; | ||
_e = err; | ||
} finally { | ||
try { | ||
if (!_n && _i["return"]) _i["return"](); | ||
} finally { | ||
if (_d) throw _e; | ||
} | ||
static get CONNECTING() { | ||
return 0; | ||
} | ||
static get OPEN() { | ||
return 1; | ||
} | ||
static get CLOSING() { | ||
return 2; | ||
} | ||
static get CLOSED() { | ||
return 3; | ||
} | ||
get CONNECTING() { | ||
return ReconnectingWebSocket.CONNECTING; | ||
} | ||
get OPEN() { | ||
return ReconnectingWebSocket.OPEN; | ||
} | ||
get CLOSING() { | ||
return ReconnectingWebSocket.CLOSING; | ||
} | ||
get CLOSED() { | ||
return ReconnectingWebSocket.CLOSED; | ||
} | ||
get binaryType() { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
} | ||
set binaryType(value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
} | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
get retryCount() { | ||
return Math.max(this._retryCount, 0); | ||
} | ||
/** | ||
* The number of bytes of data that have been queued using calls to send() but not yet | ||
* transmitted to the network. This value resets to zero once all queued data has been sent. | ||
* This value does not reset to zero when the connection is closed; if you keep calling send(), | ||
* this will continue to climb. Read only | ||
*/ | ||
get bufferedAmount() { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
} | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
get extensions() { | ||
return this._ws ? this._ws.extensions : ''; | ||
} | ||
/** | ||
* A string indicating the name of the sub-protocol the server selected; | ||
* this will be one of the strings specified in the protocols parameter when creating the | ||
* WebSocket object | ||
*/ | ||
get protocol() { | ||
return this._ws ? this._ws.protocol : ''; | ||
} | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
get readyState() { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
} | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
get url() { | ||
return this._ws ? this._ws.url : ''; | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt, if any. If the connection is already | ||
* CLOSED, this method does nothing | ||
*/ | ||
close(code, reason) { | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt and connects again. | ||
* Resets retry counter; | ||
*/ | ||
reconnect(code, reason) { | ||
this._shouldReconnect = true; | ||
this._retryCount = -1; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
this._connect(); | ||
} | ||
this._disconnect(code, reason); | ||
this._connect(); | ||
} | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data) { | ||
if (this._ws) { | ||
this._ws.send(data); | ||
} | ||
} | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
} | ||
} | ||
_debug(...params) { | ||
if (this._options.debug) { | ||
// tslint:disable-next-line | ||
console.log('RWS>', ...params); | ||
} | ||
} | ||
_getNextDelay() { | ||
let delay = 0; | ||
if (this._retryCount > 0) { | ||
const { reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor, minReconnectionDelay = DEFAULT.minReconnectionDelay, maxReconnectionDelay = DEFAULT.maxReconnectionDelay, } = this._options; | ||
delay = | ||
minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
if (delay > maxReconnectionDelay) { | ||
delay = maxReconnectionDelay; | ||
} | ||
} | ||
this._debug('next delay', delay); | ||
return delay; | ||
} | ||
_wait() { | ||
return new Promise(resolve => { | ||
setTimeout(resolve, this._getNextDelay()); | ||
}); | ||
} | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
_getNextUrl(urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
return Promise.resolve(urlProvider); | ||
} | ||
if (typeof urlProvider === 'function') { | ||
const url = urlProvider(); | ||
if (typeof url === 'string') { | ||
return Promise.resolve(url); | ||
} | ||
if (url.then) { | ||
return url; | ||
} | ||
} | ||
throw Error('Invalid URL'); | ||
} | ||
_connect() { | ||
if (this._connectLock) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
const { maxRetries = DEFAULT.maxRetries, connectionTimeout = DEFAULT.connectionTimeout, WebSocket = getGlobalWebSocket(), } = this._options; | ||
if (this._retryCount >= maxRetries) { | ||
this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
return; | ||
} | ||
this._retryCount++; | ||
this._debug('connect', this._retryCount); | ||
this._removeListeners(); | ||
if (!isWebSocket(WebSocket)) { | ||
throw Error('No valid WebSocket class provided'); | ||
} | ||
this._wait() | ||
.then(() => this._getNextUrl(this._url)) | ||
.then(url => { | ||
this._debug('connect', { url, protocols: this._protocols }); | ||
this._ws = new WebSocket(url, this._protocols); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
this._connectLock = false; | ||
this._addListeners(); | ||
this._connectTimeout = setTimeout(() => this._handleTimeout(), connectionTimeout); | ||
}); | ||
} | ||
_handleTimeout() { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
_disconnect(code, reason) { | ||
clearTimeout(this._connectTimeout); | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._removeListeners(); | ||
try { | ||
this._ws.close(code, reason); | ||
this._handleClose(new CloseEvent(code, reason, this)); | ||
} | ||
catch (error) { | ||
// ignore | ||
} | ||
} | ||
_acceptOpen() { | ||
this._retryCount = 0; | ||
} | ||
_handleOpen(event) { | ||
this._debug('open event'); | ||
const { minUptime = DEFAULT.minUptime } = this._options; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
} | ||
_handleMessage(event) { | ||
this._debug('message event'); | ||
if (this.onmessage) { | ||
this.onmessage(event); | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
} | ||
_handleError(event) { | ||
this._debug('error event', event.message); | ||
this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
if (this.onerror) { | ||
this.onerror(event); | ||
} | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._connect(); | ||
} | ||
_handleClose(event) { | ||
this._debug('close event'); | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
} | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
_removeListeners() { | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._debug('removeListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
_addListeners() { | ||
this._debug('addListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} | ||
} | ||
return _arr; | ||
} | ||
return ReconnectingWebSocket; | ||
return function (arr, i) { | ||
if (Array.isArray(arr)) { | ||
return arr; | ||
} else if (Symbol.iterator in Object(arr)) { | ||
return sliceIterator(arr, i); | ||
} else { | ||
throw new TypeError("Invalid attempt to destructure non-iterable instance"); | ||
} | ||
}; | ||
}(); | ||
var Event = function Event(type, target) { | ||
classCallCheck(this, Event); | ||
this.target = target; | ||
this.type = type; | ||
}; | ||
var ErrorEvent = function (_Event) { | ||
inherits(ErrorEvent, _Event); | ||
function ErrorEvent(error, target) { | ||
classCallCheck(this, ErrorEvent); | ||
var _this = possibleConstructorReturn(this, (ErrorEvent.__proto__ || Object.getPrototypeOf(ErrorEvent)).call(this, 'error', target)); | ||
_this.message = error.message; | ||
_this.error = error; | ||
return _this; | ||
} | ||
return ErrorEvent; | ||
}(Event); | ||
var CloseEvent = function (_Event2) { | ||
inherits(CloseEvent, _Event2); | ||
function CloseEvent() { | ||
var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1000; | ||
var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; | ||
var target = arguments[2]; | ||
classCallCheck(this, CloseEvent); | ||
var _this2 = possibleConstructorReturn(this, (CloseEvent.__proto__ || Object.getPrototypeOf(CloseEvent)).call(this, 'close', target)); | ||
_this2.wasClean = true; | ||
_this2.code = code; | ||
_this2.reason = reason; | ||
return _this2; | ||
} | ||
return CloseEvent; | ||
}(Event); | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
var getGlobalWebSocket = function getGlobalWebSocket() { | ||
if (typeof WebSocket !== 'undefined') { | ||
// @ts-ignore | ||
return WebSocket; | ||
} | ||
}; | ||
/** | ||
* Returns true if given argument looks like a WebSocket class | ||
*/ | ||
var isWebSocket = function isWebSocket(w) { | ||
return typeof w === 'function' && w.CLOSING === 2; | ||
}; | ||
var DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
minReconnectionDelay: 1000 + Math.random() * 4000, | ||
minUptime: 5000, | ||
reconnectionDelayGrowFactor: 1.3, | ||
connectionTimeout: 4000, | ||
maxRetries: Infinity, | ||
debug: false | ||
}; | ||
var ReconnectingWebSocket = function () { | ||
function ReconnectingWebSocket(url, protocols) { | ||
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
classCallCheck(this, ReconnectingWebSocket); | ||
this._listeners = { | ||
error: [], | ||
message: [], | ||
open: [], | ||
close: [] | ||
}; | ||
this._retryCount = -1; | ||
this._shouldReconnect = true; | ||
this._connectLock = false; | ||
this._binaryType = 'blob'; | ||
this.eventToHandler = new Map([['open', this._handleOpen.bind(this)], ['close', this._handleClose.bind(this)], ['error', this._handleError.bind(this)], ['message', this._handleMessage.bind(this)]]); | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to CLOSED | ||
*/ | ||
this.onclose = undefined; | ||
/** | ||
* An event listener to be called when an error occurs | ||
*/ | ||
this.onerror = undefined; | ||
/** | ||
* An event listener to be called when a message is received from the server | ||
*/ | ||
this.onmessage = undefined; | ||
/** | ||
* An event listener to be called when the WebSocket connection's readyState changes to OPEN; | ||
* this indicates that the connection is ready to send and receive data | ||
*/ | ||
this.onopen = undefined; | ||
this._url = url; | ||
this._protocols = protocols; | ||
this._options = options; | ||
this._connect(); | ||
} | ||
createClass(ReconnectingWebSocket, [{ | ||
key: 'close', | ||
/** | ||
* Closes the WebSocket connection or connection attempt, if any. If the connection is already | ||
* CLOSED, this method does nothing | ||
*/ | ||
value: function close(code, reason) { | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
/** | ||
* Closes the WebSocket connection or connection attempt and connects again. | ||
* Resets retry counter; | ||
*/ | ||
}, { | ||
key: 'reconnect', | ||
value: function reconnect(code, reason) { | ||
this._shouldReconnect = true; | ||
this._retryCount = -1; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
this._connect(); | ||
} | ||
this._disconnect(code, reason); | ||
this._connect(); | ||
} | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
}, { | ||
key: 'send', | ||
value: function send(data) { | ||
if (this._ws) { | ||
this._ws.send(data); | ||
} | ||
} | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
}, { | ||
key: 'addEventListener', | ||
value: function addEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
/** | ||
* Removes an event listener | ||
*/ | ||
}, { | ||
key: 'removeEventListener', | ||
value: function removeEventListener(type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(function (l) { | ||
return l !== listener; | ||
}); | ||
} | ||
} | ||
}, { | ||
key: '_debug', | ||
value: function _debug() { | ||
if (this._options.debug) { | ||
var _console; | ||
for (var _len = arguments.length, params = Array(_len), _key = 0; _key < _len; _key++) { | ||
params[_key] = arguments[_key]; | ||
} | ||
// tslint:disable-next-line | ||
(_console = console).log.apply(_console, ['RWS>'].concat(params)); | ||
} | ||
} | ||
}, { | ||
key: '_getNextDelay', | ||
value: function _getNextDelay() { | ||
var delay = 0; | ||
if (this._retryCount > 0) { | ||
var _options = this._options, | ||
_options$reconnection = _options.reconnectionDelayGrowFactor, | ||
reconnectionDelayGrowFactor = _options$reconnection === undefined ? DEFAULT.reconnectionDelayGrowFactor : _options$reconnection, | ||
_options$minReconnect = _options.minReconnectionDelay, | ||
minReconnectionDelay = _options$minReconnect === undefined ? DEFAULT.minReconnectionDelay : _options$minReconnect, | ||
_options$maxReconnect = _options.maxReconnectionDelay, | ||
maxReconnectionDelay = _options$maxReconnect === undefined ? DEFAULT.maxReconnectionDelay : _options$maxReconnect; | ||
delay = minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
if (delay > maxReconnectionDelay) { | ||
delay = maxReconnectionDelay; | ||
} | ||
} | ||
this._debug('next delay', delay); | ||
return delay; | ||
} | ||
}, { | ||
key: '_wait', | ||
value: function _wait() { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, _this._getNextDelay()); | ||
}); | ||
} | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
}, { | ||
key: '_getNextUrl', | ||
value: function _getNextUrl(urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
return Promise.resolve(urlProvider); | ||
} | ||
if (typeof urlProvider === 'function') { | ||
var url = urlProvider(); | ||
if (typeof url === 'string') { | ||
return Promise.resolve(url); | ||
} | ||
if (url.then) { | ||
return url; | ||
} | ||
} | ||
throw Error('Invalid URL'); | ||
} | ||
}, { | ||
key: '_connect', | ||
value: function _connect() { | ||
var _this2 = this; | ||
if (this._connectLock) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
var _options2 = this._options, | ||
_options2$maxRetries = _options2.maxRetries, | ||
maxRetries = _options2$maxRetries === undefined ? DEFAULT.maxRetries : _options2$maxRetries, | ||
_options2$connectionT = _options2.connectionTimeout, | ||
connectionTimeout = _options2$connectionT === undefined ? DEFAULT.connectionTimeout : _options2$connectionT, | ||
_options2$WebSocket = _options2.WebSocket, | ||
WebSocket = _options2$WebSocket === undefined ? getGlobalWebSocket() : _options2$WebSocket; | ||
if (this._retryCount >= maxRetries) { | ||
this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
return; | ||
} | ||
this._retryCount++; | ||
this._debug('connect', this._retryCount); | ||
this._removeListeners(); | ||
if (!isWebSocket(WebSocket)) { | ||
throw Error('No valid WebSocket class provided'); | ||
} | ||
this._wait().then(function () { | ||
return _this2._getNextUrl(_this2._url); | ||
}).then(function (url) { | ||
_this2._debug('connect', { url: url, protocols: _this2._protocols }); | ||
_this2._ws = new WebSocket(url, _this2._protocols); | ||
// @ts-ignore | ||
_this2._ws.binaryType = _this2._binaryType; | ||
_this2._connectLock = false; | ||
_this2._addListeners(); | ||
_this2._connectTimeout = setTimeout(function () { | ||
return _this2._handleTimeout(); | ||
}, connectionTimeout); | ||
}); | ||
} | ||
}, { | ||
key: '_handleTimeout', | ||
value: function _handleTimeout() { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
}, { | ||
key: '_disconnect', | ||
value: function _disconnect(code, reason) { | ||
clearTimeout(this._connectTimeout); | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._removeListeners(); | ||
try { | ||
this._ws.close(code, reason); | ||
this._handleClose(new CloseEvent(code, reason, this)); | ||
} catch (error) { | ||
// ignore | ||
} | ||
} | ||
}, { | ||
key: '_acceptOpen', | ||
value: function _acceptOpen() { | ||
this._retryCount = 0; | ||
} | ||
}, { | ||
key: '_handleOpen', | ||
value: function _handleOpen(event) { | ||
var _this3 = this; | ||
this._debug('open event'); | ||
var _options$minUptime = this._options.minUptime, | ||
minUptime = _options$minUptime === undefined ? DEFAULT.minUptime : _options$minUptime; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(function () { | ||
return _this3._acceptOpen(); | ||
}, minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
}, { | ||
key: '_handleMessage', | ||
value: function _handleMessage(event) { | ||
this._debug('message event'); | ||
if (this.onmessage) { | ||
this.onmessage(event); | ||
} | ||
this._listeners.message.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
}, { | ||
key: '_handleError', | ||
value: function _handleError(event) { | ||
this._debug('error event', event.message); | ||
// https://github.com/pladaria/reconnecting-websocket/pull/69 | ||
this._disconnect(4008, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
if (this.onerror) { | ||
this.onerror(event); | ||
} | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
this._connect(); | ||
} | ||
}, { | ||
key: '_handleClose', | ||
value: function _handleClose(event) { | ||
this._debug('close event'); | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(function (listener) { | ||
return listener(event); | ||
}); | ||
} | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
}, { | ||
key: '_removeListeners', | ||
value: function _removeListeners() { | ||
if (!this._ws) { | ||
return; | ||
} | ||
this._debug('removeListeners'); | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = this.eventToHandler[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _ref = _step.value; | ||
var _ref2 = slicedToArray(_ref, 2); | ||
var type = _ref2[0]; | ||
var handler = _ref2[1]; | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
}, { | ||
key: '_addListeners', | ||
value: function _addListeners() { | ||
this._debug('addListeners'); | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = this.eventToHandler[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var _ref3 = _step2.value; | ||
var _ref4 = slicedToArray(_ref3, 2); | ||
var type = _ref4[0]; | ||
var handler = _ref4[1]; | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
} | ||
}, { | ||
key: 'CONNECTING', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CONNECTING; | ||
} | ||
}, { | ||
key: 'OPEN', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.OPEN; | ||
} | ||
}, { | ||
key: 'CLOSING', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CLOSING; | ||
} | ||
}, { | ||
key: 'CLOSED', | ||
get: function get$$1() { | ||
return ReconnectingWebSocket.CLOSED; | ||
} | ||
}, { | ||
key: 'binaryType', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
}, | ||
set: function set$$1(value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
} | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
}, { | ||
key: 'retryCount', | ||
get: function get$$1() { | ||
return Math.max(this._retryCount, 0); | ||
} | ||
/** | ||
* The number of bytes of data that have been queued using calls to send() but not yet | ||
* transmitted to the network. This value resets to zero once all queued data has been sent. | ||
* This value does not reset to zero when the connection is closed; if you keep calling send(), | ||
* this will continue to climb. Read only | ||
*/ | ||
}, { | ||
key: 'bufferedAmount', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
} | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
}, { | ||
key: 'extensions', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.extensions : ''; | ||
} | ||
/** | ||
* A string indicating the name of the sub-protocol the server selected; | ||
* this will be one of the strings specified in the protocols parameter when creating the | ||
* WebSocket object | ||
*/ | ||
}, { | ||
key: 'protocol', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.protocol : ''; | ||
} | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
}, { | ||
key: 'readyState', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
} | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
}, { | ||
key: 'url', | ||
get: function get$$1() { | ||
return this._ws ? this._ws.url : ''; | ||
} | ||
}], [{ | ||
key: 'CONNECTING', | ||
get: function get$$1() { | ||
return 0; | ||
} | ||
}, { | ||
key: 'OPEN', | ||
get: function get$$1() { | ||
return 1; | ||
} | ||
}, { | ||
key: 'CLOSING', | ||
get: function get$$1() { | ||
return 2; | ||
} | ||
}, { | ||
key: 'CLOSED', | ||
get: function get$$1() { | ||
return 3; | ||
} | ||
}]); | ||
return ReconnectingWebSocket; | ||
}(); | ||
return ReconnectingWebSocket; | ||
}()); |
@@ -1,1 +0,1 @@ | ||
var ReconnectingWebSocket=function(){"use strict";class e{constructor(e,t){this.target=t,this.type=e}}class t extends e{constructor(e,t){super("error",t),this.message=e.message,this.error=e}}class s extends e{constructor(e=1e3,t="",s){super("close",s),this.wasClean=!0,this.code=e,this.reason=t}}const i=()=>{if("undefined"!=typeof WebSocket)return WebSocket},n=e=>"function"==typeof e&&2===e.CLOSING,o={maxReconnectionDelay:1e4,minReconnectionDelay:1e3+4e3*Math.random(),minUptime:5e3,reconnectionDelayGrowFactor:1.3,connectionTimeout:4e3,maxRetries:1/0,debug:!1};class r{constructor(e,t,s={}){this._listeners={error:[],message:[],open:[],close:[]},this._retryCount=-1,this._shouldReconnect=!0,this._connectLock=!1,this._binaryType="blob",this.eventToHandler=new Map([["open",this._handleOpen.bind(this)],["close",this._handleClose.bind(this)],["error",this._handleError.bind(this)],["message",this._handleMessage.bind(this)]]),this.onclose=void 0,this.onerror=void 0,this.onmessage=void 0,this.onopen=void 0,this._url=e,this._protocols=t,this._options=s,this._connect()}static get CONNECTING(){return 0}static get OPEN(){return 1}static get CLOSING(){return 2}static get CLOSED(){return 3}get CONNECTING(){return r.CONNECTING}get OPEN(){return r.OPEN}get CLOSING(){return r.CLOSING}get CLOSED(){return r.CLOSED}get binaryType(){return this._ws?this._ws.binaryType:this._binaryType}set binaryType(e){this._binaryType=e,this._ws&&(this._ws.binaryType=e)}get retryCount(){return Math.max(this._retryCount,0)}get bufferedAmount(){return this._ws?this._ws.bufferedAmount:0}get extensions(){return this._ws?this._ws.extensions:""}get protocol(){return this._ws?this._ws.protocol:""}get readyState(){return this._ws?this._ws.readyState:r.CONNECTING}get url(){return this._ws?this._ws.url:""}close(e,t){this._shouldReconnect=!1,this._ws&&this._ws.readyState!==this.CLOSED&&this._ws.close(e,t)}reconnect(e,t){this._shouldReconnect=!0,this._retryCount=-1,this._ws&&this._ws.readyState!==this.CLOSED||this._connect(),this._disconnect(e,t),this._connect()}send(e){this._ws&&this._ws.send(e)}addEventListener(e,t){this._listeners[e]&&this._listeners[e].push(t)}removeEventListener(e,t){this._listeners[e]&&(this._listeners[e]=this._listeners[e].filter(e=>e!==t))}_debug(...e){this._options.debug&&console.log("RWS>",...e)}_getNextDelay(){let e=0;if(this._retryCount>0){const{reconnectionDelayGrowFactor:t=o.reconnectionDelayGrowFactor,minReconnectionDelay:s=o.minReconnectionDelay,maxReconnectionDelay:i=o.maxReconnectionDelay}=this._options;(e=s+Math.pow(this._retryCount-1,t))>i&&(e=i)}return this._debug("next delay",e),e}_wait(){return new Promise(e=>{setTimeout(e,this._getNextDelay())})}_getNextUrl(e){if("string"==typeof e)return Promise.resolve(e);if("function"==typeof e){const t=e();if("string"==typeof t)return Promise.resolve(t);if(t.then)return t}throw Error("Invalid URL")}_connect(){if(this._connectLock)return;this._connectLock=!0;const{maxRetries:e=o.maxRetries,connectionTimeout:t=o.connectionTimeout,WebSocket:s=i()}=this._options;if(this._retryCount>=e)this._debug("max retries reached",this._retryCount,">=",e);else{if(this._retryCount++,this._debug("connect",this._retryCount),this._removeListeners(),!n(s))throw Error("No valid WebSocket class provided");this._wait().then(()=>this._getNextUrl(this._url)).then(e=>{this._debug("connect",{url:e,protocols:this._protocols}),this._ws=new s(e,this._protocols),this._ws.binaryType=this._binaryType,this._connectLock=!1,this._addListeners(),this._connectTimeout=setTimeout(()=>this._handleTimeout(),t)})}}_handleTimeout(){this._debug("timeout event"),this._handleError(new t(Error("TIMEOUT"),this))}_disconnect(e,t){if(clearTimeout(this._connectTimeout),this._ws){this._removeListeners();try{this._ws.close(e,t),this._handleClose(new s(e,t,this))}catch(e){}}}_acceptOpen(){this._retryCount=0}_handleOpen(e){this._debug("open event");const{minUptime:t=o.minUptime}=this._options;clearTimeout(this._connectTimeout),this._uptimeTimeout=setTimeout(()=>this._acceptOpen(),t),this._debug("assign binary type"),this._ws.binaryType=this._binaryType,this.onopen&&this.onopen(e),this._listeners.open.forEach(t=>t(e))}_handleMessage(e){this._debug("message event"),this.onmessage&&this.onmessage(e),this._listeners.message.forEach(t=>t(e))}_handleError(e){this._debug("error event",e.message),this._disconnect(void 0,"TIMEOUT"===e.message?"timeout":void 0),this.onerror&&this.onerror(e),this._debug("exec error listeners"),this._listeners.error.forEach(t=>t(e)),this._connect()}_handleClose(e){this._debug("close event"),this.onclose&&this.onclose(e),this._listeners.close.forEach(t=>t(e))}_removeListeners(){if(this._ws){this._debug("removeListeners");for(const[e,t]of this.eventToHandler)this._ws.removeEventListener(e,t)}}_addListeners(){this._debug("addListeners");for(const[e,t]of this.eventToHandler)this._ws.addEventListener(e,t)}}return r}(); | ||
var ReconnectingWebSocket=function(){"use strict";var e=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},t=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),n=function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)},i=function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t},r=function(){function e(e,t){var n=[],i=!0,r=!1,o=void 0;try{for(var s,u=e[Symbol.iterator]();!(i=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);i=!0);}catch(e){r=!0,o=e}finally{try{!i&&u.return&&u.return()}finally{if(r)throw o}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),o=function t(n,i){e(this,t),this.target=i,this.type=n},s=function(t){function r(t,n){e(this,r);var o=i(this,(r.__proto__||Object.getPrototypeOf(r)).call(this,"error",n));return o.message=t.message,o.error=t,o}return n(r,t),r}(o),u=function(t){function r(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1e3,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",o=arguments[2];e(this,r);var s=i(this,(r.__proto__||Object.getPrototypeOf(r)).call(this,"close",o));return s.wasClean=!0,s.code=t,s.reason=n,s}return n(r,t),r}(o),c=function(){if("undefined"!=typeof WebSocket)return WebSocket},a=function(e){return"function"==typeof e&&2===e.CLOSING},h={maxReconnectionDelay:1e4,minReconnectionDelay:1e3+4e3*Math.random(),minUptime:5e3,reconnectionDelayGrowFactor:1.3,connectionTimeout:4e3,maxRetries:1/0,debug:!1};return function(){function n(t,i){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};e(this,n),this._listeners={error:[],message:[],open:[],close:[]},this._retryCount=-1,this._shouldReconnect=!0,this._connectLock=!1,this._binaryType="blob",this.eventToHandler=new Map([["open",this._handleOpen.bind(this)],["close",this._handleClose.bind(this)],["error",this._handleError.bind(this)],["message",this._handleMessage.bind(this)]]),this.onclose=void 0,this.onerror=void 0,this.onmessage=void 0,this.onopen=void 0,this._url=t,this._protocols=i,this._options=r,this._connect()}return t(n,[{key:"close",value:function(e,t){this._shouldReconnect=!1,this._ws&&this._ws.readyState!==this.CLOSED&&this._ws.close(e,t)}},{key:"reconnect",value:function(e,t){this._shouldReconnect=!0,this._retryCount=-1,this._ws&&this._ws.readyState!==this.CLOSED||this._connect(),this._disconnect(e,t),this._connect()}},{key:"send",value:function(e){this._ws&&this._ws.send(e)}},{key:"addEventListener",value:function(e,t){this._listeners[e]&&this._listeners[e].push(t)}},{key:"removeEventListener",value:function(e,t){this._listeners[e]&&(this._listeners[e]=this._listeners[e].filter(function(e){return e!==t}))}},{key:"_debug",value:function(){if(this._options.debug){for(var e,t=arguments.length,n=Array(t),i=0;i<t;i++)n[i]=arguments[i];(e=console).log.apply(e,["RWS>"].concat(n))}}},{key:"_getNextDelay",value:function(){var e=0;if(this._retryCount>0){var t=this._options,n=t.reconnectionDelayGrowFactor,i=void 0===n?h.reconnectionDelayGrowFactor:n,r=t.minReconnectionDelay,o=void 0===r?h.minReconnectionDelay:r,s=t.maxReconnectionDelay,u=void 0===s?h.maxReconnectionDelay:s;e=o+Math.pow(this._retryCount-1,i),e>u&&(e=u)}return this._debug("next delay",e),e}},{key:"_wait",value:function(){var e=this;return new Promise(function(t){setTimeout(t,e._getNextDelay())})}},{key:"_getNextUrl",value:function(e){if("string"==typeof e)return Promise.resolve(e);if("function"==typeof e){var t=e();if("string"==typeof t)return Promise.resolve(t);if(t.then)return t}throw Error("Invalid URL")}},{key:"_connect",value:function(){var e=this;if(!this._connectLock){this._connectLock=!0;var t=this._options,n=t.maxRetries,i=void 0===n?h.maxRetries:n,r=t.connectionTimeout,o=void 0===r?h.connectionTimeout:r,s=t.WebSocket,u=void 0===s?c():s;if(this._retryCount>=i)return void this._debug("max retries reached",this._retryCount,">=",i);if(this._retryCount++,this._debug("connect",this._retryCount),this._removeListeners(),!a(u))throw Error("No valid WebSocket class provided");this._wait().then(function(){return e._getNextUrl(e._url)}).then(function(t){e._debug("connect",{url:t,protocols:e._protocols}),e._ws=new u(t,e._protocols),e._ws.binaryType=e._binaryType,e._connectLock=!1,e._addListeners(),e._connectTimeout=setTimeout(function(){return e._handleTimeout()},o)})}}},{key:"_handleTimeout",value:function(){this._debug("timeout event"),this._handleError(new s(Error("TIMEOUT"),this))}},{key:"_disconnect",value:function(e,t){if(clearTimeout(this._connectTimeout),this._ws){this._removeListeners();try{this._ws.close(e,t),this._handleClose(new u(e,t,this))}catch(e){}}}},{key:"_acceptOpen",value:function(){this._retryCount=0}},{key:"_handleOpen",value:function(e){var t=this;this._debug("open event");var n=this._options.minUptime,i=void 0===n?h.minUptime:n;clearTimeout(this._connectTimeout),this._uptimeTimeout=setTimeout(function(){return t._acceptOpen()},i),this._debug("assign binary type"),this._ws.binaryType=this._binaryType,this.onopen&&this.onopen(e),this._listeners.open.forEach(function(t){return t(e)})}},{key:"_handleMessage",value:function(e){this._debug("message event"),this.onmessage&&this.onmessage(e),this._listeners.message.forEach(function(t){return t(e)})}},{key:"_handleError",value:function(e){this._debug("error event",e.message),this._disconnect(4008,"TIMEOUT"===e.message?"timeout":void 0),this.onerror&&this.onerror(e),this._debug("exec error listeners"),this._listeners.error.forEach(function(t){return t(e)}),this._connect()}},{key:"_handleClose",value:function(e){this._debug("close event"),this.onclose&&this.onclose(e),this._listeners.close.forEach(function(t){return t(e)})}},{key:"_removeListeners",value:function(){if(this._ws){this._debug("removeListeners");var e=!0,t=!1,n=void 0;try{for(var i,o=this.eventToHandler[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var s=i.value,u=r(s,2),c=u[0],a=u[1];this._ws.removeEventListener(c,a)}}catch(e){t=!0,n=e}finally{try{!e&&o.return&&o.return()}finally{if(t)throw n}}}}},{key:"_addListeners",value:function(){this._debug("addListeners");var e=!0,t=!1,n=void 0;try{for(var i,o=this.eventToHandler[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var s=i.value,u=r(s,2),c=u[0],a=u[1];this._ws.addEventListener(c,a)}}catch(e){t=!0,n=e}finally{try{!e&&o.return&&o.return()}finally{if(t)throw n}}}},{key:"CONNECTING",get:function(){return n.CONNECTING}},{key:"OPEN",get:function(){return n.OPEN}},{key:"CLOSING",get:function(){return n.CLOSING}},{key:"CLOSED",get:function(){return n.CLOSED}},{key:"binaryType",get:function(){return this._ws?this._ws.binaryType:this._binaryType},set:function(e){this._binaryType=e,this._ws&&(this._ws.binaryType=e)}},{key:"retryCount",get:function(){return Math.max(this._retryCount,0)}},{key:"bufferedAmount",get:function(){return this._ws?this._ws.bufferedAmount:0}},{key:"extensions",get:function(){return this._ws?this._ws.extensions:""}},{key:"protocol",get:function(){return this._ws?this._ws.protocol:""}},{key:"readyState",get:function(){return this._ws?this._ws.readyState:n.CONNECTING}},{key:"url",get:function(){return this._ws?this._ws.url:""}}],[{key:"CONNECTING",get:function(){return 0}},{key:"OPEN",get:function(){return 1}},{key:"CLOSING",get:function(){return 2}},{key:"CLOSED",get:function(){return 3}}]),n}()}(); |
@@ -0,1 +1,7 @@ | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
import { CloseEvent, ErrorEvent, Event, WebSocketEventMap } from './events'; | ||
@@ -111,25 +117,25 @@ export declare type Options = { | ||
removeEventListener<K extends keyof WebSocketEventMap>(type: K, listener: ((event: WebSocketEventMap[K]) => void)): void; | ||
private _debug(...params); | ||
private _getNextDelay(); | ||
private _wait(); | ||
private _debug; | ||
private _getNextDelay; | ||
private _wait; | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
private _getNextUrl(urlProvider); | ||
private _connect(); | ||
private _handleTimeout(); | ||
private _disconnect(code?, reason?); | ||
private _acceptOpen(); | ||
private _handleOpen(event); | ||
private _handleMessage(event); | ||
private _handleError(event); | ||
private _handleClose(event); | ||
private _getNextUrl; | ||
private _connect; | ||
private _handleTimeout; | ||
private _disconnect; | ||
private _acceptOpen; | ||
private _handleOpen; | ||
private _handleMessage; | ||
private _handleError; | ||
private _handleClose; | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
private _removeListeners(); | ||
private _removeListeners; | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
private _addListeners(); | ||
private _addListeners; | ||
} |
{ | ||
"name": "@october/reconnecting-websocket", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Reconnecting WebSocket", | ||
"main": "./dist/reconnecting-websocket-cjs.js", | ||
"modules": "./dist/reconnecting-websocket.mjs", | ||
"types": "./dist/reconnecting-websocket.d.ts", | ||
@@ -32,2 +33,4 @@ "scripts": { | ||
"ava": "^0.25.0", | ||
"babel-plugin-external-helpers": "^6.22.0", | ||
"babel-preset-env": "^1.7.0", | ||
"coveralls": "^3.0.0", | ||
@@ -41,2 +44,3 @@ "del-cli": "^1.1.0", | ||
"rollup": "^0.59.1", | ||
"rollup-plugin-babel": "^3.0.7", | ||
"rollup-plugin-typescript2": "^0.14.0", | ||
@@ -70,3 +74,16 @@ "tslint": "^5.10.0", | ||
} | ||
}, | ||
"babel": { | ||
"presets": [ | ||
[ | ||
"env", | ||
{ | ||
"modules": false | ||
} | ||
] | ||
], | ||
"plugins": [ | ||
"external-helpers" | ||
] | ||
} | ||
} |
@@ -390,3 +390,4 @@ /*! | ||
this._debug('error event', event.message); | ||
this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
// https://github.com/pladaria/reconnecting-websocket/pull/69 | ||
this._disconnect(4008, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
@@ -393,0 +394,0 @@ if (this.onerror) { |
Sorry, the diff of this file is not supported yet
122540
2954
17