reconnecting-websocket
Advanced tools
Comparing version 4.0.0-rc5 to 4.1.0
@@ -23,2 +23,6 @@ export declare class Event { | ||
} | ||
export declare type EventListener = (event: Event | CloseEvent | MessageEvent) => void; | ||
declare type Listener = (event: Event | CloseEvent | MessageEvent) => void; | ||
export declare type EventListener = Listener | { | ||
handleEvent: Listener; | ||
}; | ||
export {}; |
define(function () { 'use strict'; | ||
class Event { | ||
constructor(type, target) { | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
***************************************************************************** */ | ||
/* global Reflect, Promise */ | ||
var extendStatics = function(d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
function __extends(d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
} | ||
function __values(o) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; | ||
if (m) return m.call(o); | ||
return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
} | ||
function __read(o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
} | ||
function __spread() { | ||
for (var ar = [], i = 0; i < arguments.length; i++) | ||
ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
} | ||
var Event = /** @class */ (function () { | ||
function Event(type, target) { | ||
this.target = target; | ||
this.type = type; | ||
} | ||
} | ||
class ErrorEvent extends Event { | ||
constructor(error, target) { | ||
super('error', target); | ||
this.message = error.message; | ||
this.error = error; | ||
return Event; | ||
}()); | ||
var ErrorEvent = /** @class */ (function (_super) { | ||
__extends(ErrorEvent, _super); | ||
function ErrorEvent(error, target) { | ||
var _this = _super.call(this, 'error', target) || this; | ||
_this.message = error.message; | ||
_this.error = error; | ||
return _this; | ||
} | ||
} | ||
class CloseEvent extends Event { | ||
constructor(code = 1000, reason = '', target) { | ||
super('close', target); | ||
this.wasClean = true; | ||
this.code = code; | ||
this.reason = reason; | ||
return ErrorEvent; | ||
}(Event)); | ||
var CloseEvent = /** @class */ (function (_super) { | ||
__extends(CloseEvent, _super); | ||
function CloseEvent(code, reason, target) { | ||
if (code === void 0) { code = 1000; } | ||
if (reason === void 0) { reason = ''; } | ||
var _this = _super.call(this, 'close', target) || this; | ||
_this.wasClean = true; | ||
_this.code = code; | ||
_this.reason = reason; | ||
return _this; | ||
} | ||
} | ||
return CloseEvent; | ||
}(Event)); | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
const getGlobalWebSocket = () => { | ||
var getGlobalWebSocket = function () { | ||
if (typeof WebSocket !== 'undefined') { | ||
@@ -40,4 +106,4 @@ // @ts-ignore | ||
*/ | ||
const isWebSocket = (w) => typeof w === 'function' && w.CLOSING === 2; | ||
const DEFAULT = { | ||
var isWebSocket = function (w) { return typeof w === 'function' && w.CLOSING === 2; }; | ||
var DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
@@ -51,4 +117,5 @@ minReconnectionDelay: 1000 + Math.random() * 4000, | ||
}; | ||
class ReconnectingWebSocket { | ||
constructor(url, protocols, options = {}) { | ||
var ReconnectingWebSocket = /** @class */ (function () { | ||
function ReconnectingWebSocket(url, protocols, options) { | ||
if (options === void 0) { options = {}; } | ||
this._listeners = { | ||
@@ -64,2 +131,4 @@ error: [], | ||
this._binaryType = 'blob'; | ||
this._closeCalled = false; | ||
this._messageQueue = []; | ||
this.eventToHandler = new Map([ | ||
@@ -93,89 +162,156 @@ ['open', this._handleOpen.bind(this)], | ||
} | ||
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; | ||
} | ||
} | ||
Object.defineProperty(ReconnectingWebSocket, "CONNECTING", { | ||
get: function () { | ||
return 0; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "OPEN", { | ||
get: function () { | ||
return 1; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "CLOSING", { | ||
get: function () { | ||
return 2; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "CLOSED", { | ||
get: function () { | ||
return 3; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CONNECTING", { | ||
get: function () { | ||
return ReconnectingWebSocket.CONNECTING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "OPEN", { | ||
get: function () { | ||
return ReconnectingWebSocket.OPEN; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CLOSING", { | ||
get: function () { | ||
return ReconnectingWebSocket.CLOSING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CLOSED", { | ||
get: function () { | ||
return ReconnectingWebSocket.CLOSED; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "binaryType", { | ||
get: function () { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
}, | ||
set: function (value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "retryCount", { | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
get: function () { | ||
return Math.max(this._retryCount, 0); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "bufferedAmount", { | ||
/** | ||
* 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: function () { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "extensions", { | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.extensions : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "protocol", { | ||
/** | ||
* 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: function () { | ||
return this._ws ? this._ws.protocol : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "readyState", { | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "url", { | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.url : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
/** | ||
* 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) { | ||
ReconnectingWebSocket.prototype.close = function (code, reason) { | ||
if (code === void 0) { code = 1000; } | ||
this._closeCalled = true; | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
if (!this._ws) { | ||
this._debug('close enqueued: no ws instance'); | ||
return; | ||
} | ||
if (this._ws.readyState === this.CLOSED) { | ||
this._debug('close: already closed'); | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
}; | ||
/** | ||
@@ -185,3 +321,3 @@ * Closes the WebSocket connection or connection attempt and connects again. | ||
*/ | ||
reconnect(code, reason) { | ||
ReconnectingWebSocket.prototype.reconnect = function (code, reason) { | ||
this._shouldReconnect = true; | ||
@@ -194,39 +330,46 @@ this._retryCount = -1; | ||
this._connect(); | ||
} | ||
}; | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
* Enqueue specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data) { | ||
ReconnectingWebSocket.prototype.send = function (data) { | ||
if (this._ws) { | ||
this._debug('send', data); | ||
this._ws.send(data); | ||
} | ||
} | ||
else { | ||
this._debug('enqueue', data); | ||
this._messageQueue.push(data); | ||
} | ||
}; | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener(type, listener) { | ||
ReconnectingWebSocket.prototype.addEventListener = function (type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
}; | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener(type, listener) { | ||
ReconnectingWebSocket.prototype.removeEventListener = function (type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
this._listeners[type] = this._listeners[type].filter(function (l) { return l !== listener; }); | ||
} | ||
} | ||
_debug(...params) { | ||
}; | ||
ReconnectingWebSocket.prototype._debug = function () { | ||
var params = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
params[_i] = arguments[_i]; | ||
} | ||
if (this._options.debug) { | ||
// tslint:disable-next-line | ||
console.log('RWS>', ...params); | ||
console.log.apply(console, __spread(['RWS>'], params)); | ||
} | ||
} | ||
_getNextDelay() { | ||
let delay = 0; | ||
}; | ||
ReconnectingWebSocket.prototype._getNextDelay = function () { | ||
var delay = 0; | ||
if (this._retryCount > 0) { | ||
const { reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor, minReconnectionDelay = DEFAULT.minReconnectionDelay, maxReconnectionDelay = DEFAULT.maxReconnectionDelay, } = this._options; | ||
var _a = this._options, _b = _a.reconnectionDelayGrowFactor, reconnectionDelayGrowFactor = _b === void 0 ? DEFAULT.reconnectionDelayGrowFactor : _b, _c = _a.minReconnectionDelay, minReconnectionDelay = _c === void 0 ? DEFAULT.minReconnectionDelay : _c, _d = _a.maxReconnectionDelay, maxReconnectionDelay = _d === void 0 ? DEFAULT.maxReconnectionDelay : _d; | ||
delay = | ||
@@ -240,12 +383,13 @@ minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
return delay; | ||
} | ||
_wait() { | ||
return new Promise(resolve => { | ||
setTimeout(resolve, this._getNextDelay()); | ||
}; | ||
ReconnectingWebSocket.prototype._wait = function () { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, _this._getNextDelay()); | ||
}); | ||
} | ||
}; | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
_getNextUrl(urlProvider) { | ||
ReconnectingWebSocket.prototype._getNextUrl = function (urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
@@ -255,3 +399,3 @@ return Promise.resolve(urlProvider); | ||
if (typeof urlProvider === 'function') { | ||
const url = urlProvider(); | ||
var url = urlProvider(); | ||
if (typeof url === 'string') { | ||
@@ -265,9 +409,10 @@ return Promise.resolve(url); | ||
throw Error('Invalid URL'); | ||
} | ||
_connect() { | ||
if (this._connectLock) { | ||
}; | ||
ReconnectingWebSocket.prototype._connect = function () { | ||
var _this = this; | ||
if (this._connectLock || !this._shouldReconnect) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
const { maxRetries = DEFAULT.maxRetries, connectionTimeout = DEFAULT.connectionTimeout, WebSocket = getGlobalWebSocket(), } = this._options; | ||
var _a = this._options, _b = _a.maxRetries, maxRetries = _b === void 0 ? DEFAULT.maxRetries : _b, _c = _a.connectionTimeout, connectionTimeout = _c === void 0 ? DEFAULT.connectionTimeout : _c, _d = _a.WebSocket, WebSocket = _d === void 0 ? getGlobalWebSocket() : _d; | ||
if (this._retryCount >= maxRetries) { | ||
@@ -284,18 +429,26 @@ this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
this._wait() | ||
.then(() => this._getNextUrl(this._url)) | ||
.then(url => { | ||
this._debug('connect', { url, protocols: this._protocols }); | ||
this._ws = new WebSocket(url, this._protocols); | ||
.then(function () { return _this._getNextUrl(_this._url); }) | ||
.then(function (url) { | ||
_this._debug('connect', { url: 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); | ||
_this._ws.binaryType = _this._binaryType; | ||
_this._connectLock = false; | ||
_this._addListeners(); | ||
// close could be called before creating the ws | ||
if (_this._closeCalled) { | ||
_this._closeCalled = true; | ||
_this._ws.close(); | ||
} | ||
else { | ||
_this._connectTimeout = setTimeout(function () { return _this._handleTimeout(); }, connectionTimeout); | ||
} | ||
}); | ||
} | ||
_handleTimeout() { | ||
}; | ||
ReconnectingWebSocket.prototype._handleTimeout = function () { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
_disconnect(code, reason) { | ||
}; | ||
ReconnectingWebSocket.prototype._disconnect = function (code, reason) { | ||
if (code === void 0) { code = 1000; } | ||
clearTimeout(this._connectTimeout); | ||
@@ -313,20 +466,33 @@ if (!this._ws) { | ||
} | ||
} | ||
_acceptOpen() { | ||
}; | ||
ReconnectingWebSocket.prototype._acceptOpen = function () { | ||
this._retryCount = 0; | ||
} | ||
_handleOpen(event) { | ||
}; | ||
ReconnectingWebSocket.prototype._callEventListener = function (event, listener) { | ||
if ('handleEvent' in listener) { | ||
listener.handleEvent(event); | ||
} | ||
else { | ||
listener(event); | ||
} | ||
}; | ||
ReconnectingWebSocket.prototype._handleOpen = function (event) { | ||
var _this = this; | ||
this._debug('open event'); | ||
const { minUptime = DEFAULT.minUptime } = this._options; | ||
var _a = this._options.minUptime, minUptime = _a === void 0 ? DEFAULT.minUptime : _a; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); | ||
this._uptimeTimeout = setTimeout(function () { return _this._acceptOpen(); }, minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
// send enqueued messages (messages sent before websocket initialization) | ||
this._messageQueue.forEach(function (message) { return _this._ws.send(message); }); | ||
this._messageQueue = []; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
} | ||
_handleMessage(event) { | ||
this._listeners.open.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
ReconnectingWebSocket.prototype._handleMessage = function (event) { | ||
var _this = this; | ||
this._debug('message event'); | ||
@@ -336,5 +502,6 @@ if (this.onmessage) { | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
} | ||
_handleError(event) { | ||
this._listeners.message.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
ReconnectingWebSocket.prototype._handleError = function (event) { | ||
var _this = this; | ||
this._debug('error event', event.message); | ||
@@ -346,16 +513,21 @@ this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._listeners.error.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
this._connect(); | ||
} | ||
_handleClose(event) { | ||
}; | ||
ReconnectingWebSocket.prototype._handleClose = function (event) { | ||
var _this = this; | ||
this._debug('close event'); | ||
if (this._shouldReconnect) { | ||
this._connect(); | ||
} | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
} | ||
this._listeners.close.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
_removeListeners() { | ||
ReconnectingWebSocket.prototype._removeListeners = function () { | ||
var e_1, _a; | ||
if (!this._ws) { | ||
@@ -365,16 +537,38 @@ return; | ||
this._debug('removeListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.removeEventListener(type, handler); | ||
try { | ||
for (var _b = __values(this.eventToHandler), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), type = _d[0], handler = _d[1]; | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}; | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
_addListeners() { | ||
ReconnectingWebSocket.prototype._addListeners = function () { | ||
var e_2, _a; | ||
this._debug('addListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.addEventListener(type, handler); | ||
try { | ||
for (var _b = __values(this.eventToHandler), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), type = _d[0], handler = _d[1]; | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} | ||
} | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
}; | ||
return ReconnectingWebSocket; | ||
}()); | ||
@@ -381,0 +575,0 @@ return ReconnectingWebSocket; |
'use strict'; | ||
class Event { | ||
constructor(type, target) { | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
***************************************************************************** */ | ||
/* global Reflect, Promise */ | ||
var extendStatics = function(d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
function __extends(d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
} | ||
function __values(o) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; | ||
if (m) return m.call(o); | ||
return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
} | ||
function __read(o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
} | ||
function __spread() { | ||
for (var ar = [], i = 0; i < arguments.length; i++) | ||
ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
} | ||
var Event = /** @class */ (function () { | ||
function Event(type, target) { | ||
this.target = target; | ||
this.type = type; | ||
} | ||
} | ||
class ErrorEvent extends Event { | ||
constructor(error, target) { | ||
super('error', target); | ||
this.message = error.message; | ||
this.error = error; | ||
return Event; | ||
}()); | ||
var ErrorEvent = /** @class */ (function (_super) { | ||
__extends(ErrorEvent, _super); | ||
function ErrorEvent(error, target) { | ||
var _this = _super.call(this, 'error', target) || this; | ||
_this.message = error.message; | ||
_this.error = error; | ||
return _this; | ||
} | ||
} | ||
class CloseEvent extends Event { | ||
constructor(code = 1000, reason = '', target) { | ||
super('close', target); | ||
this.wasClean = true; | ||
this.code = code; | ||
this.reason = reason; | ||
return ErrorEvent; | ||
}(Event)); | ||
var CloseEvent = /** @class */ (function (_super) { | ||
__extends(CloseEvent, _super); | ||
function CloseEvent(code, reason, target) { | ||
if (code === void 0) { code = 1000; } | ||
if (reason === void 0) { reason = ''; } | ||
var _this = _super.call(this, 'close', target) || this; | ||
_this.wasClean = true; | ||
_this.code = code; | ||
_this.reason = reason; | ||
return _this; | ||
} | ||
} | ||
return CloseEvent; | ||
}(Event)); | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
const getGlobalWebSocket = () => { | ||
var getGlobalWebSocket = function () { | ||
if (typeof WebSocket !== 'undefined') { | ||
@@ -40,4 +106,4 @@ // @ts-ignore | ||
*/ | ||
const isWebSocket = (w) => typeof w === 'function' && w.CLOSING === 2; | ||
const DEFAULT = { | ||
var isWebSocket = function (w) { return typeof w === 'function' && w.CLOSING === 2; }; | ||
var DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
@@ -51,4 +117,5 @@ minReconnectionDelay: 1000 + Math.random() * 4000, | ||
}; | ||
class ReconnectingWebSocket { | ||
constructor(url, protocols, options = {}) { | ||
var ReconnectingWebSocket = /** @class */ (function () { | ||
function ReconnectingWebSocket(url, protocols, options) { | ||
if (options === void 0) { options = {}; } | ||
this._listeners = { | ||
@@ -64,2 +131,4 @@ error: [], | ||
this._binaryType = 'blob'; | ||
this._closeCalled = false; | ||
this._messageQueue = []; | ||
this.eventToHandler = new Map([ | ||
@@ -93,89 +162,156 @@ ['open', this._handleOpen.bind(this)], | ||
} | ||
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; | ||
} | ||
} | ||
Object.defineProperty(ReconnectingWebSocket, "CONNECTING", { | ||
get: function () { | ||
return 0; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "OPEN", { | ||
get: function () { | ||
return 1; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "CLOSING", { | ||
get: function () { | ||
return 2; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "CLOSED", { | ||
get: function () { | ||
return 3; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CONNECTING", { | ||
get: function () { | ||
return ReconnectingWebSocket.CONNECTING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "OPEN", { | ||
get: function () { | ||
return ReconnectingWebSocket.OPEN; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CLOSING", { | ||
get: function () { | ||
return ReconnectingWebSocket.CLOSING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CLOSED", { | ||
get: function () { | ||
return ReconnectingWebSocket.CLOSED; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "binaryType", { | ||
get: function () { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
}, | ||
set: function (value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "retryCount", { | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
get: function () { | ||
return Math.max(this._retryCount, 0); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "bufferedAmount", { | ||
/** | ||
* 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: function () { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "extensions", { | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.extensions : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "protocol", { | ||
/** | ||
* 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: function () { | ||
return this._ws ? this._ws.protocol : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "readyState", { | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "url", { | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.url : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
/** | ||
* 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) { | ||
ReconnectingWebSocket.prototype.close = function (code, reason) { | ||
if (code === void 0) { code = 1000; } | ||
this._closeCalled = true; | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
if (!this._ws) { | ||
this._debug('close enqueued: no ws instance'); | ||
return; | ||
} | ||
if (this._ws.readyState === this.CLOSED) { | ||
this._debug('close: already closed'); | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
}; | ||
/** | ||
@@ -185,3 +321,3 @@ * Closes the WebSocket connection or connection attempt and connects again. | ||
*/ | ||
reconnect(code, reason) { | ||
ReconnectingWebSocket.prototype.reconnect = function (code, reason) { | ||
this._shouldReconnect = true; | ||
@@ -194,39 +330,46 @@ this._retryCount = -1; | ||
this._connect(); | ||
} | ||
}; | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
* Enqueue specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data) { | ||
ReconnectingWebSocket.prototype.send = function (data) { | ||
if (this._ws) { | ||
this._debug('send', data); | ||
this._ws.send(data); | ||
} | ||
} | ||
else { | ||
this._debug('enqueue', data); | ||
this._messageQueue.push(data); | ||
} | ||
}; | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener(type, listener) { | ||
ReconnectingWebSocket.prototype.addEventListener = function (type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
}; | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener(type, listener) { | ||
ReconnectingWebSocket.prototype.removeEventListener = function (type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
this._listeners[type] = this._listeners[type].filter(function (l) { return l !== listener; }); | ||
} | ||
} | ||
_debug(...params) { | ||
}; | ||
ReconnectingWebSocket.prototype._debug = function () { | ||
var params = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
params[_i] = arguments[_i]; | ||
} | ||
if (this._options.debug) { | ||
// tslint:disable-next-line | ||
console.log('RWS>', ...params); | ||
console.log.apply(console, __spread(['RWS>'], params)); | ||
} | ||
} | ||
_getNextDelay() { | ||
let delay = 0; | ||
}; | ||
ReconnectingWebSocket.prototype._getNextDelay = function () { | ||
var delay = 0; | ||
if (this._retryCount > 0) { | ||
const { reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor, minReconnectionDelay = DEFAULT.minReconnectionDelay, maxReconnectionDelay = DEFAULT.maxReconnectionDelay, } = this._options; | ||
var _a = this._options, _b = _a.reconnectionDelayGrowFactor, reconnectionDelayGrowFactor = _b === void 0 ? DEFAULT.reconnectionDelayGrowFactor : _b, _c = _a.minReconnectionDelay, minReconnectionDelay = _c === void 0 ? DEFAULT.minReconnectionDelay : _c, _d = _a.maxReconnectionDelay, maxReconnectionDelay = _d === void 0 ? DEFAULT.maxReconnectionDelay : _d; | ||
delay = | ||
@@ -240,12 +383,13 @@ minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
return delay; | ||
} | ||
_wait() { | ||
return new Promise(resolve => { | ||
setTimeout(resolve, this._getNextDelay()); | ||
}; | ||
ReconnectingWebSocket.prototype._wait = function () { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, _this._getNextDelay()); | ||
}); | ||
} | ||
}; | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
_getNextUrl(urlProvider) { | ||
ReconnectingWebSocket.prototype._getNextUrl = function (urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
@@ -255,3 +399,3 @@ return Promise.resolve(urlProvider); | ||
if (typeof urlProvider === 'function') { | ||
const url = urlProvider(); | ||
var url = urlProvider(); | ||
if (typeof url === 'string') { | ||
@@ -265,9 +409,10 @@ return Promise.resolve(url); | ||
throw Error('Invalid URL'); | ||
} | ||
_connect() { | ||
if (this._connectLock) { | ||
}; | ||
ReconnectingWebSocket.prototype._connect = function () { | ||
var _this = this; | ||
if (this._connectLock || !this._shouldReconnect) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
const { maxRetries = DEFAULT.maxRetries, connectionTimeout = DEFAULT.connectionTimeout, WebSocket = getGlobalWebSocket(), } = this._options; | ||
var _a = this._options, _b = _a.maxRetries, maxRetries = _b === void 0 ? DEFAULT.maxRetries : _b, _c = _a.connectionTimeout, connectionTimeout = _c === void 0 ? DEFAULT.connectionTimeout : _c, _d = _a.WebSocket, WebSocket = _d === void 0 ? getGlobalWebSocket() : _d; | ||
if (this._retryCount >= maxRetries) { | ||
@@ -284,18 +429,26 @@ this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
this._wait() | ||
.then(() => this._getNextUrl(this._url)) | ||
.then(url => { | ||
this._debug('connect', { url, protocols: this._protocols }); | ||
this._ws = new WebSocket(url, this._protocols); | ||
.then(function () { return _this._getNextUrl(_this._url); }) | ||
.then(function (url) { | ||
_this._debug('connect', { url: 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); | ||
_this._ws.binaryType = _this._binaryType; | ||
_this._connectLock = false; | ||
_this._addListeners(); | ||
// close could be called before creating the ws | ||
if (_this._closeCalled) { | ||
_this._closeCalled = true; | ||
_this._ws.close(); | ||
} | ||
else { | ||
_this._connectTimeout = setTimeout(function () { return _this._handleTimeout(); }, connectionTimeout); | ||
} | ||
}); | ||
} | ||
_handleTimeout() { | ||
}; | ||
ReconnectingWebSocket.prototype._handleTimeout = function () { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
_disconnect(code, reason) { | ||
}; | ||
ReconnectingWebSocket.prototype._disconnect = function (code, reason) { | ||
if (code === void 0) { code = 1000; } | ||
clearTimeout(this._connectTimeout); | ||
@@ -313,20 +466,33 @@ if (!this._ws) { | ||
} | ||
} | ||
_acceptOpen() { | ||
}; | ||
ReconnectingWebSocket.prototype._acceptOpen = function () { | ||
this._retryCount = 0; | ||
} | ||
_handleOpen(event) { | ||
}; | ||
ReconnectingWebSocket.prototype._callEventListener = function (event, listener) { | ||
if ('handleEvent' in listener) { | ||
listener.handleEvent(event); | ||
} | ||
else { | ||
listener(event); | ||
} | ||
}; | ||
ReconnectingWebSocket.prototype._handleOpen = function (event) { | ||
var _this = this; | ||
this._debug('open event'); | ||
const { minUptime = DEFAULT.minUptime } = this._options; | ||
var _a = this._options.minUptime, minUptime = _a === void 0 ? DEFAULT.minUptime : _a; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); | ||
this._uptimeTimeout = setTimeout(function () { return _this._acceptOpen(); }, minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
// send enqueued messages (messages sent before websocket initialization) | ||
this._messageQueue.forEach(function (message) { return _this._ws.send(message); }); | ||
this._messageQueue = []; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
} | ||
_handleMessage(event) { | ||
this._listeners.open.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
ReconnectingWebSocket.prototype._handleMessage = function (event) { | ||
var _this = this; | ||
this._debug('message event'); | ||
@@ -336,5 +502,6 @@ if (this.onmessage) { | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
} | ||
_handleError(event) { | ||
this._listeners.message.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
ReconnectingWebSocket.prototype._handleError = function (event) { | ||
var _this = this; | ||
this._debug('error event', event.message); | ||
@@ -346,16 +513,21 @@ this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._listeners.error.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
this._connect(); | ||
} | ||
_handleClose(event) { | ||
}; | ||
ReconnectingWebSocket.prototype._handleClose = function (event) { | ||
var _this = this; | ||
this._debug('close event'); | ||
if (this._shouldReconnect) { | ||
this._connect(); | ||
} | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
} | ||
this._listeners.close.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
_removeListeners() { | ||
ReconnectingWebSocket.prototype._removeListeners = function () { | ||
var e_1, _a; | ||
if (!this._ws) { | ||
@@ -365,17 +537,39 @@ return; | ||
this._debug('removeListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.removeEventListener(type, handler); | ||
try { | ||
for (var _b = __values(this.eventToHandler), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), type = _d[0], handler = _d[1]; | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}; | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
_addListeners() { | ||
ReconnectingWebSocket.prototype._addListeners = function () { | ||
var e_2, _a; | ||
this._debug('addListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.addEventListener(type, handler); | ||
try { | ||
for (var _b = __values(this.eventToHandler), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), type = _d[0], handler = _d[1]; | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} | ||
} | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
}; | ||
return ReconnectingWebSocket; | ||
}()); | ||
module.exports = ReconnectingWebSocket; |
var ReconnectingWebSocket = (function () { | ||
'use strict'; | ||
class Event { | ||
constructor(type, target) { | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
***************************************************************************** */ | ||
/* global Reflect, Promise */ | ||
var extendStatics = function(d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
function __extends(d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
} | ||
function __values(o) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; | ||
if (m) return m.call(o); | ||
return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
} | ||
function __read(o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
} | ||
function __spread() { | ||
for (var ar = [], i = 0; i < arguments.length; i++) | ||
ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
} | ||
var Event = /** @class */ (function () { | ||
function Event(type, target) { | ||
this.target = target; | ||
this.type = type; | ||
} | ||
} | ||
class ErrorEvent extends Event { | ||
constructor(error, target) { | ||
super('error', target); | ||
this.message = error.message; | ||
this.error = error; | ||
return Event; | ||
}()); | ||
var ErrorEvent = /** @class */ (function (_super) { | ||
__extends(ErrorEvent, _super); | ||
function ErrorEvent(error, target) { | ||
var _this = _super.call(this, 'error', target) || this; | ||
_this.message = error.message; | ||
_this.error = error; | ||
return _this; | ||
} | ||
} | ||
class CloseEvent extends Event { | ||
constructor(code = 1000, reason = '', target) { | ||
super('close', target); | ||
this.wasClean = true; | ||
this.code = code; | ||
this.reason = reason; | ||
return ErrorEvent; | ||
}(Event)); | ||
var CloseEvent = /** @class */ (function (_super) { | ||
__extends(CloseEvent, _super); | ||
function CloseEvent(code, reason, target) { | ||
if (code === void 0) { code = 1000; } | ||
if (reason === void 0) { reason = ''; } | ||
var _this = _super.call(this, 'close', target) || this; | ||
_this.wasClean = true; | ||
_this.code = code; | ||
_this.reason = reason; | ||
return _this; | ||
} | ||
} | ||
return CloseEvent; | ||
}(Event)); | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
const getGlobalWebSocket = () => { | ||
var getGlobalWebSocket = function () { | ||
if (typeof WebSocket !== 'undefined') { | ||
@@ -41,4 +107,4 @@ // @ts-ignore | ||
*/ | ||
const isWebSocket = (w) => typeof w === 'function' && w.CLOSING === 2; | ||
const DEFAULT = { | ||
var isWebSocket = function (w) { return typeof w === 'function' && w.CLOSING === 2; }; | ||
var DEFAULT = { | ||
maxReconnectionDelay: 10000, | ||
@@ -52,4 +118,5 @@ minReconnectionDelay: 1000 + Math.random() * 4000, | ||
}; | ||
class ReconnectingWebSocket { | ||
constructor(url, protocols, options = {}) { | ||
var ReconnectingWebSocket = /** @class */ (function () { | ||
function ReconnectingWebSocket(url, protocols, options) { | ||
if (options === void 0) { options = {}; } | ||
this._listeners = { | ||
@@ -65,2 +132,4 @@ error: [], | ||
this._binaryType = 'blob'; | ||
this._closeCalled = false; | ||
this._messageQueue = []; | ||
this.eventToHandler = new Map([ | ||
@@ -94,89 +163,156 @@ ['open', this._handleOpen.bind(this)], | ||
} | ||
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; | ||
} | ||
} | ||
Object.defineProperty(ReconnectingWebSocket, "CONNECTING", { | ||
get: function () { | ||
return 0; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "OPEN", { | ||
get: function () { | ||
return 1; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "CLOSING", { | ||
get: function () { | ||
return 2; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket, "CLOSED", { | ||
get: function () { | ||
return 3; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CONNECTING", { | ||
get: function () { | ||
return ReconnectingWebSocket.CONNECTING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "OPEN", { | ||
get: function () { | ||
return ReconnectingWebSocket.OPEN; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CLOSING", { | ||
get: function () { | ||
return ReconnectingWebSocket.CLOSING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "CLOSED", { | ||
get: function () { | ||
return ReconnectingWebSocket.CLOSED; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "binaryType", { | ||
get: function () { | ||
return this._ws ? this._ws.binaryType : this._binaryType; | ||
}, | ||
set: function (value) { | ||
this._binaryType = value; | ||
if (this._ws) { | ||
// @ts-ignore | ||
this._ws.binaryType = value; | ||
} | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "retryCount", { | ||
/** | ||
* Returns the number or connection retries | ||
*/ | ||
get: function () { | ||
return Math.max(this._retryCount, 0); | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "bufferedAmount", { | ||
/** | ||
* 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: function () { | ||
return this._ws ? this._ws.bufferedAmount : 0; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "extensions", { | ||
/** | ||
* The extensions selected by the server. This is currently only the empty string or a list of | ||
* extensions as negotiated by the connection | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.extensions : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "protocol", { | ||
/** | ||
* 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: function () { | ||
return this._ws ? this._ws.protocol : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "readyState", { | ||
/** | ||
* The current state of the connection; this is one of the Ready state constants | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.readyState : ReconnectingWebSocket.CONNECTING; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ReconnectingWebSocket.prototype, "url", { | ||
/** | ||
* The URL as resolved by the constructor | ||
*/ | ||
get: function () { | ||
return this._ws ? this._ws.url : ''; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
/** | ||
* 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) { | ||
ReconnectingWebSocket.prototype.close = function (code, reason) { | ||
if (code === void 0) { code = 1000; } | ||
this._closeCalled = true; | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
if (!this._ws) { | ||
this._debug('close enqueued: no ws instance'); | ||
return; | ||
} | ||
if (this._ws.readyState === this.CLOSED) { | ||
this._debug('close: already closed'); | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
} | ||
}; | ||
/** | ||
@@ -186,3 +322,3 @@ * Closes the WebSocket connection or connection attempt and connects again. | ||
*/ | ||
reconnect(code, reason) { | ||
ReconnectingWebSocket.prototype.reconnect = function (code, reason) { | ||
this._shouldReconnect = true; | ||
@@ -195,39 +331,46 @@ this._retryCount = -1; | ||
this._connect(); | ||
} | ||
}; | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
* Enqueue specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data) { | ||
ReconnectingWebSocket.prototype.send = function (data) { | ||
if (this._ws) { | ||
this._debug('send', data); | ||
this._ws.send(data); | ||
} | ||
} | ||
else { | ||
this._debug('enqueue', data); | ||
this._messageQueue.push(data); | ||
} | ||
}; | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener(type, listener) { | ||
ReconnectingWebSocket.prototype.addEventListener = function (type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
} | ||
} | ||
}; | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener(type, listener) { | ||
ReconnectingWebSocket.prototype.removeEventListener = function (type, listener) { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
this._listeners[type] = this._listeners[type].filter(function (l) { return l !== listener; }); | ||
} | ||
} | ||
_debug(...params) { | ||
}; | ||
ReconnectingWebSocket.prototype._debug = function () { | ||
var params = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
params[_i] = arguments[_i]; | ||
} | ||
if (this._options.debug) { | ||
// tslint:disable-next-line | ||
console.log('RWS>', ...params); | ||
console.log.apply(console, __spread(['RWS>'], params)); | ||
} | ||
} | ||
_getNextDelay() { | ||
let delay = 0; | ||
}; | ||
ReconnectingWebSocket.prototype._getNextDelay = function () { | ||
var delay = 0; | ||
if (this._retryCount > 0) { | ||
const { reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor, minReconnectionDelay = DEFAULT.minReconnectionDelay, maxReconnectionDelay = DEFAULT.maxReconnectionDelay, } = this._options; | ||
var _a = this._options, _b = _a.reconnectionDelayGrowFactor, reconnectionDelayGrowFactor = _b === void 0 ? DEFAULT.reconnectionDelayGrowFactor : _b, _c = _a.minReconnectionDelay, minReconnectionDelay = _c === void 0 ? DEFAULT.minReconnectionDelay : _c, _d = _a.maxReconnectionDelay, maxReconnectionDelay = _d === void 0 ? DEFAULT.maxReconnectionDelay : _d; | ||
delay = | ||
@@ -241,12 +384,13 @@ minReconnectionDelay + Math.pow(this._retryCount - 1, reconnectionDelayGrowFactor); | ||
return delay; | ||
} | ||
_wait() { | ||
return new Promise(resolve => { | ||
setTimeout(resolve, this._getNextDelay()); | ||
}; | ||
ReconnectingWebSocket.prototype._wait = function () { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
setTimeout(resolve, _this._getNextDelay()); | ||
}); | ||
} | ||
}; | ||
/** | ||
* @return Promise<string> | ||
*/ | ||
_getNextUrl(urlProvider) { | ||
ReconnectingWebSocket.prototype._getNextUrl = function (urlProvider) { | ||
if (typeof urlProvider === 'string') { | ||
@@ -256,3 +400,3 @@ return Promise.resolve(urlProvider); | ||
if (typeof urlProvider === 'function') { | ||
const url = urlProvider(); | ||
var url = urlProvider(); | ||
if (typeof url === 'string') { | ||
@@ -266,9 +410,10 @@ return Promise.resolve(url); | ||
throw Error('Invalid URL'); | ||
} | ||
_connect() { | ||
if (this._connectLock) { | ||
}; | ||
ReconnectingWebSocket.prototype._connect = function () { | ||
var _this = this; | ||
if (this._connectLock || !this._shouldReconnect) { | ||
return; | ||
} | ||
this._connectLock = true; | ||
const { maxRetries = DEFAULT.maxRetries, connectionTimeout = DEFAULT.connectionTimeout, WebSocket = getGlobalWebSocket(), } = this._options; | ||
var _a = this._options, _b = _a.maxRetries, maxRetries = _b === void 0 ? DEFAULT.maxRetries : _b, _c = _a.connectionTimeout, connectionTimeout = _c === void 0 ? DEFAULT.connectionTimeout : _c, _d = _a.WebSocket, WebSocket = _d === void 0 ? getGlobalWebSocket() : _d; | ||
if (this._retryCount >= maxRetries) { | ||
@@ -285,18 +430,26 @@ this._debug('max retries reached', this._retryCount, '>=', maxRetries); | ||
this._wait() | ||
.then(() => this._getNextUrl(this._url)) | ||
.then(url => { | ||
this._debug('connect', { url, protocols: this._protocols }); | ||
this._ws = new WebSocket(url, this._protocols); | ||
.then(function () { return _this._getNextUrl(_this._url); }) | ||
.then(function (url) { | ||
_this._debug('connect', { url: 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); | ||
_this._ws.binaryType = _this._binaryType; | ||
_this._connectLock = false; | ||
_this._addListeners(); | ||
// close could be called before creating the ws | ||
if (_this._closeCalled) { | ||
_this._closeCalled = true; | ||
_this._ws.close(); | ||
} | ||
else { | ||
_this._connectTimeout = setTimeout(function () { return _this._handleTimeout(); }, connectionTimeout); | ||
} | ||
}); | ||
} | ||
_handleTimeout() { | ||
}; | ||
ReconnectingWebSocket.prototype._handleTimeout = function () { | ||
this._debug('timeout event'); | ||
this._handleError(new ErrorEvent(Error('TIMEOUT'), this)); | ||
} | ||
_disconnect(code, reason) { | ||
}; | ||
ReconnectingWebSocket.prototype._disconnect = function (code, reason) { | ||
if (code === void 0) { code = 1000; } | ||
clearTimeout(this._connectTimeout); | ||
@@ -314,20 +467,33 @@ if (!this._ws) { | ||
} | ||
} | ||
_acceptOpen() { | ||
}; | ||
ReconnectingWebSocket.prototype._acceptOpen = function () { | ||
this._retryCount = 0; | ||
} | ||
_handleOpen(event) { | ||
}; | ||
ReconnectingWebSocket.prototype._callEventListener = function (event, listener) { | ||
if ('handleEvent' in listener) { | ||
listener.handleEvent(event); | ||
} | ||
else { | ||
listener(event); | ||
} | ||
}; | ||
ReconnectingWebSocket.prototype._handleOpen = function (event) { | ||
var _this = this; | ||
this._debug('open event'); | ||
const { minUptime = DEFAULT.minUptime } = this._options; | ||
var _a = this._options.minUptime, minUptime = _a === void 0 ? DEFAULT.minUptime : _a; | ||
clearTimeout(this._connectTimeout); | ||
this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime); | ||
this._uptimeTimeout = setTimeout(function () { return _this._acceptOpen(); }, minUptime); | ||
this._debug('assign binary type'); | ||
// @ts-ignore | ||
this._ws.binaryType = this._binaryType; | ||
// send enqueued messages (messages sent before websocket initialization) | ||
this._messageQueue.forEach(function (message) { return _this._ws.send(message); }); | ||
this._messageQueue = []; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
} | ||
_handleMessage(event) { | ||
this._listeners.open.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
ReconnectingWebSocket.prototype._handleMessage = function (event) { | ||
var _this = this; | ||
this._debug('message event'); | ||
@@ -337,5 +503,6 @@ if (this.onmessage) { | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
} | ||
_handleError(event) { | ||
this._listeners.message.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
ReconnectingWebSocket.prototype._handleError = function (event) { | ||
var _this = this; | ||
this._debug('error event', event.message); | ||
@@ -347,16 +514,21 @@ this._disconnect(undefined, event.message === 'TIMEOUT' ? 'timeout' : undefined); | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._listeners.error.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
this._connect(); | ||
} | ||
_handleClose(event) { | ||
}; | ||
ReconnectingWebSocket.prototype._handleClose = function (event) { | ||
var _this = this; | ||
this._debug('close event'); | ||
if (this._shouldReconnect) { | ||
this._connect(); | ||
} | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
} | ||
this._listeners.close.forEach(function (listener) { return _this._callEventListener(event, listener); }); | ||
}; | ||
/** | ||
* Remove event listeners to WebSocket instance | ||
*/ | ||
_removeListeners() { | ||
ReconnectingWebSocket.prototype._removeListeners = function () { | ||
var e_1, _a; | ||
if (!this._ws) { | ||
@@ -366,16 +538,38 @@ return; | ||
this._debug('removeListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.removeEventListener(type, handler); | ||
try { | ||
for (var _b = __values(this.eventToHandler), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), type = _d[0], handler = _d[1]; | ||
this._ws.removeEventListener(type, handler); | ||
} | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}; | ||
/** | ||
* Assign event listeners to WebSocket instance | ||
*/ | ||
_addListeners() { | ||
ReconnectingWebSocket.prototype._addListeners = function () { | ||
var e_2, _a; | ||
this._debug('addListeners'); | ||
for (const [type, handler] of this.eventToHandler) { | ||
this._ws.addEventListener(type, handler); | ||
try { | ||
for (var _b = __values(this.eventToHandler), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), type = _d[0], handler = _d[1]; | ||
this._ws.addEventListener(type, handler); | ||
} | ||
} | ||
} | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
}; | ||
return ReconnectingWebSocket; | ||
}()); | ||
@@ -382,0 +576,0 @@ 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(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};function t(t,n){function o(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(o.prototype=n.prototype,new o)}function n(e){var t="function"==typeof Symbol&&e[Symbol.iterator],n=0;return t?t.call(e):{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}}}function o(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var o,r,i=n.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(o=i.next()).done;)s.push(o.value)}catch(e){r={error:e}}finally{try{o&&!o.done&&(n=i.return)&&n.call(i)}finally{if(r)throw r.error}}return s}var r=function(){return function(e,t){this.target=t,this.type=e}}(),i=function(e){function n(t,n){var o=e.call(this,"error",n)||this;return o.message=t.message,o.error=t,o}return t(n,e),n}(r),s=function(e){function n(t,n,o){void 0===t&&(t=1e3),void 0===n&&(n="");var r=e.call(this,"close",o)||this;return r.wasClean=!0,r.code=t,r.reason=n,r}return t(n,e),n}(r),c=function(){if("undefined"!=typeof WebSocket)return WebSocket},u={maxReconnectionDelay:1e4,minReconnectionDelay:1e3+4e3*Math.random(),minUptime:5e3,reconnectionDelayGrowFactor:1.3,connectionTimeout:4e3,maxRetries:1/0,debug:!1};return function(){function e(e,t,n){void 0===n&&(n={}),this._listeners={error:[],message:[],open:[],close:[]},this._retryCount=-1,this._shouldReconnect=!0,this._connectLock=!1,this._binaryType="blob",this._closeCalled=!1,this._messageQueue=[],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=n,this._connect()}return Object.defineProperty(e,"CONNECTING",{get:function(){return 0},enumerable:!0,configurable:!0}),Object.defineProperty(e,"OPEN",{get:function(){return 1},enumerable:!0,configurable:!0}),Object.defineProperty(e,"CLOSING",{get:function(){return 2},enumerable:!0,configurable:!0}),Object.defineProperty(e,"CLOSED",{get:function(){return 3},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"CONNECTING",{get:function(){return e.CONNECTING},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"OPEN",{get:function(){return e.OPEN},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"CLOSING",{get:function(){return e.CLOSING},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"CLOSED",{get:function(){return e.CLOSED},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"binaryType",{get:function(){return this._ws?this._ws.binaryType:this._binaryType},set:function(e){this._binaryType=e,this._ws&&(this._ws.binaryType=e)},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"retryCount",{get:function(){return Math.max(this._retryCount,0)},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"bufferedAmount",{get:function(){return this._ws?this._ws.bufferedAmount:0},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"extensions",{get:function(){return this._ws?this._ws.extensions:""},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"protocol",{get:function(){return this._ws?this._ws.protocol:""},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"readyState",{get:function(){return this._ws?this._ws.readyState:e.CONNECTING},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"url",{get:function(){return this._ws?this._ws.url:""},enumerable:!0,configurable:!0}),e.prototype.close=function(e,t){void 0===e&&(e=1e3),this._closeCalled=!0,this._shouldReconnect=!1,this._ws?this._ws.readyState!==this.CLOSED?this._ws.close(e,t):this._debug("close: already closed"):this._debug("close enqueued: no ws instance")},e.prototype.reconnect=function(e,t){this._shouldReconnect=!0,this._retryCount=-1,this._ws&&this._ws.readyState!==this.CLOSED||this._connect(),this._disconnect(e,t),this._connect()},e.prototype.send=function(e){this._ws?(this._debug("send",e),this._ws.send(e)):(this._debug("enqueue",e),this._messageQueue.push(e))},e.prototype.addEventListener=function(e,t){this._listeners[e]&&this._listeners[e].push(t)},e.prototype.removeEventListener=function(e,t){this._listeners[e]&&(this._listeners[e]=this._listeners[e].filter(function(e){return e!==t}))},e.prototype._debug=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];this._options.debug&&console.log.apply(console,function(){for(var e=[],t=0;t<arguments.length;t++)e=e.concat(o(arguments[t]));return e}(["RWS>"],e))},e.prototype._getNextDelay=function(){var e=0;if(this._retryCount>0){var t=this._options,n=t.reconnectionDelayGrowFactor,o=void 0===n?u.reconnectionDelayGrowFactor:n,r=t.minReconnectionDelay,i=void 0===r?u.minReconnectionDelay:r,s=t.maxReconnectionDelay,c=void 0===s?u.maxReconnectionDelay:s;(e=i+Math.pow(this._retryCount-1,o))>c&&(e=c)}return this._debug("next delay",e),e},e.prototype._wait=function(){var e=this;return new Promise(function(t){setTimeout(t,e._getNextDelay())})},e.prototype._getNextUrl=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")},e.prototype._connect=function(){var e=this;if(!this._connectLock&&this._shouldReconnect){this._connectLock=!0;var t=this._options,n=t.maxRetries,o=void 0===n?u.maxRetries:n,r=t.connectionTimeout,i=void 0===r?u.connectionTimeout:r,s=t.WebSocket,a=void 0===s?c():s;if(this._retryCount>=o)this._debug("max retries reached",this._retryCount,">=",o);else{if(this._retryCount++,this._debug("connect",this._retryCount),this._removeListeners(),"function"!=typeof(h=a)||2!==h.CLOSING)throw Error("No valid WebSocket class provided");var h;this._wait().then(function(){return e._getNextUrl(e._url)}).then(function(t){e._debug("connect",{url:t,protocols:e._protocols}),e._ws=new a(t,e._protocols),e._ws.binaryType=e._binaryType,e._connectLock=!1,e._addListeners(),e._closeCalled?(e._closeCalled=!0,e._ws.close()):e._connectTimeout=setTimeout(function(){return e._handleTimeout()},i)})}}},e.prototype._handleTimeout=function(){this._debug("timeout event"),this._handleError(new i(Error("TIMEOUT"),this))},e.prototype._disconnect=function(e,t){if(void 0===e&&(e=1e3),clearTimeout(this._connectTimeout),this._ws){this._removeListeners();try{this._ws.close(e,t),this._handleClose(new s(e,t,this))}catch(e){}}},e.prototype._acceptOpen=function(){this._retryCount=0},e.prototype._callEventListener=function(e,t){"handleEvent"in t?t.handleEvent(e):t(e)},e.prototype._handleOpen=function(e){var t=this;this._debug("open event");var n=this._options.minUptime,o=void 0===n?u.minUptime:n;clearTimeout(this._connectTimeout),this._uptimeTimeout=setTimeout(function(){return t._acceptOpen()},o),this._debug("assign binary type"),this._ws.binaryType=this._binaryType,this._messageQueue.forEach(function(e){return t._ws.send(e)}),this._messageQueue=[],this.onopen&&this.onopen(e),this._listeners.open.forEach(function(n){return t._callEventListener(e,n)})},e.prototype._handleMessage=function(e){var t=this;this._debug("message event"),this.onmessage&&this.onmessage(e),this._listeners.message.forEach(function(n){return t._callEventListener(e,n)})},e.prototype._handleError=function(e){var t=this;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(function(n){return t._callEventListener(e,n)}),this._connect()},e.prototype._handleClose=function(e){var t=this;this._debug("close event"),this._shouldReconnect&&this._connect(),this.onclose&&this.onclose(e),this._listeners.close.forEach(function(n){return t._callEventListener(e,n)})},e.prototype._removeListeners=function(){var e,t;if(this._ws){this._debug("removeListeners");try{for(var r=n(this.eventToHandler),i=r.next();!i.done;i=r.next()){var s=o(i.value,2),c=s[0],u=s[1];this._ws.removeEventListener(c,u)}}catch(t){e={error:t}}finally{try{i&&!i.done&&(t=r.return)&&t.call(r)}finally{if(e)throw e.error}}}},e.prototype._addListeners=function(){var e,t;this._debug("addListeners");try{for(var r=n(this.eventToHandler),i=r.next();!i.done;i=r.next()){var s=o(i.value,2),c=s[0],u=s[1];this._ws.addEventListener(c,u)}}catch(t){e={error:t}}finally{try{i&&!i.done&&(t=r.return)&&t.call(r)}finally{if(e)throw e.error}}},e}()}(); |
@@ -1,2 +0,8 @@ | ||
import { CloseEvent, ErrorEvent, Event, WebSocketEventMap } from './events'; | ||
/*! | ||
* Reconnecting WebSocket | ||
* by Pedro Ladaria <pedro.ladaria@gmail.com> | ||
* https://github.com/pladaria/reconnecting-websocket | ||
* License MIT | ||
*/ | ||
import { CloseEvent, Event, EventListener, WebSocketEventMap } from './events'; | ||
export declare type Options = { | ||
@@ -13,7 +19,8 @@ WebSocket?: any; | ||
export declare type UrlProvider = string | (() => string) | (() => Promise<string>); | ||
export declare type Message = string | ArrayBuffer | Blob | ArrayBufferView; | ||
export declare type ListenersMap = { | ||
error: Array<((event: ErrorEvent) => void)>; | ||
message: Array<((event: MessageEvent) => void)>; | ||
open: Array<((event: Event) => void)>; | ||
close: Array<((event: CloseEvent) => void)>; | ||
error: EventListener[]; | ||
message: EventListener[]; | ||
open: EventListener[]; | ||
close: EventListener[]; | ||
}; | ||
@@ -29,2 +36,4 @@ export default class ReconnectingWebSocket { | ||
private _binaryType; | ||
private _closeCalled; | ||
private _messageQueue; | ||
private readonly _url; | ||
@@ -102,36 +111,37 @@ private readonly _protocols?; | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
* Enqueue specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
send(data: string | ArrayBuffer | Blob | ArrayBufferView): void; | ||
send(data: Message): void; | ||
/** | ||
* Register an event handler of a specific event type | ||
*/ | ||
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: ((event: WebSocketEventMap[K]) => void)): void; | ||
addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: EventListener): void; | ||
/** | ||
* Removes an event listener | ||
*/ | ||
removeEventListener<K extends keyof WebSocketEventMap>(type: K, listener: ((event: WebSocketEventMap[K]) => void)): void; | ||
private _debug(...params); | ||
private _getNextDelay(); | ||
private _wait(); | ||
removeEventListener<K extends keyof WebSocketEventMap>(type: K, listener: EventListener): void; | ||
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 _callEventListener; | ||
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; | ||
} |
@@ -37,2 +37,4 @@ export class Event { | ||
export type EventListener = (event: Event | CloseEvent | MessageEvent) => void; | ||
type Listener = (event: Event | CloseEvent | MessageEvent) => void; | ||
export type EventListener = Listener | {handleEvent: Listener}; |
{ | ||
"name": "reconnecting-websocket", | ||
"version": "4.0.0-rc5", | ||
"version": "4.1.0", | ||
"description": "Reconnecting WebSocket", | ||
@@ -9,5 +9,4 @@ "main": "./dist/reconnecting-websocket-cjs.js", | ||
"scripts": { | ||
"build": | ||
"npm run clean && rollup -c && uglifyjs --compress --mangle -o dist/reconnecting-websocket-iife.min.js dist/reconnecting-websocket-iife.js", | ||
"test": "nyc --reporter=text-summary --reporter=lcov ava --verbose --serial test/test.js", | ||
"build": "npm run clean && rollup -c && uglifyjs --compress --mangle -o dist/reconnecting-websocket-iife.min.js dist/reconnecting-websocket-iife.js", | ||
"test": "npm run build && nyc --reporter=text-summary --reporter=lcov ava --verbose --serial test/test.js", | ||
"clean": "del dist && del coverage && del .nyc_output", | ||
@@ -35,15 +34,16 @@ "report": "nyc report --reporter=html && opn coverage/index.html", | ||
"ava": "^0.25.0", | ||
"coveralls": "^3.0.0", | ||
"coveralls": "^3.0.2", | ||
"del-cli": "^1.1.0", | ||
"husky": "^0.14.3", | ||
"lint-staged": "^7.1.0", | ||
"nyc": "^11.8.0", | ||
"husky": "^1.0.1", | ||
"lint-staged": "^7.3.0", | ||
"nyc": "^13.0.1", | ||
"opn-cli": "^3.1.0", | ||
"prettier": "^1.12.1", | ||
"rollup": "^0.59.1", | ||
"rollup-plugin-typescript2": "^0.14.0", | ||
"tslint": "^5.10.0", | ||
"typescript": "^2.8.3", | ||
"prettier": "^1.14.3", | ||
"rollup": "^0.66.2", | ||
"rollup-plugin-typescript2": "^0.17.0", | ||
"tslib": "^1.9.3", | ||
"tslint": "^5.11.0", | ||
"typescript": "^3.1.1", | ||
"uglify-es": "^3.3.9", | ||
"ws": "^5.1.1" | ||
"ws": "^6.0.0" | ||
}, | ||
@@ -67,5 +67,8 @@ "dependencies": {}, | ||
"linters": { | ||
"*.{js,md,ts}, !dist/*": ["prettier --write", "git add"] | ||
"*.{js,md,ts}": [ | ||
"prettier --write", | ||
"git add" | ||
] | ||
} | ||
} | ||
} |
@@ -15,5 +15,4 @@ # Reconnecting WebSocket | ||
* Handle connection timeouts | ||
* Full test coverage | ||
* Debug mode | ||
* AMD build available (see dist folder) | ||
* Multiple builds available (see dist folder) | ||
* Allows changing server URL between reconnections | ||
@@ -20,0 +19,0 @@ |
@@ -44,7 +44,9 @@ /*! | ||
export type Message = string | ArrayBuffer | Blob | ArrayBufferView; | ||
export type ListenersMap = { | ||
error: Array<((event: ErrorEvent) => void)>; | ||
message: Array<((event: MessageEvent) => void)>; | ||
open: Array<((event: Event) => void)>; | ||
close: Array<((event: CloseEvent) => void)>; | ||
error: EventListener[]; | ||
message: EventListener[]; | ||
open: EventListener[]; | ||
close: EventListener[]; | ||
}; | ||
@@ -65,2 +67,4 @@ export default class ReconnectingWebSocket { | ||
private _binaryType = 'blob'; | ||
private _closeCalled = false; | ||
private _messageQueue: Message[] = []; | ||
@@ -196,7 +200,13 @@ private readonly _url: UrlProvider; | ||
*/ | ||
public close(code?: number, reason?: string) { | ||
public close(code: number = 1000, reason?: string) { | ||
this._closeCalled = true; | ||
this._shouldReconnect = false; | ||
if (!this._ws || this._ws.readyState === this.CLOSED) { | ||
if (!this._ws) { | ||
this._debug('close enqueued: no ws instance'); | ||
return; | ||
} | ||
if (this._ws.readyState === this.CLOSED) { | ||
this._debug('close: already closed'); | ||
return; | ||
} | ||
this._ws.close(code, reason); | ||
@@ -220,7 +230,11 @@ } | ||
/** | ||
* Enqueues the specified data to be transmitted to the server over the WebSocket connection | ||
* Enqueue specified data to be transmitted to the server over the WebSocket connection | ||
*/ | ||
public send(data: string | ArrayBuffer | Blob | ArrayBufferView) { | ||
public send(data: Message) { | ||
if (this._ws) { | ||
this._debug('send', data); | ||
this._ws.send(data); | ||
} else { | ||
this._debug('enqueue', data); | ||
this._messageQueue.push(data); | ||
} | ||
@@ -234,6 +248,5 @@ } | ||
type: K, | ||
listener: ((event: WebSocketEventMap[K]) => void), | ||
listener: EventListener, | ||
): void { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type].push(listener); | ||
@@ -248,6 +261,5 @@ } | ||
type: K, | ||
listener: ((event: WebSocketEventMap[K]) => void), | ||
listener: EventListener, | ||
): void { | ||
if (this._listeners[type]) { | ||
// @ts-ignore | ||
this._listeners[type] = this._listeners[type].filter(l => l !== listener); | ||
@@ -309,3 +321,3 @@ } | ||
private _connect() { | ||
if (this._connectLock) { | ||
if (this._connectLock || !this._shouldReconnect) { | ||
return; | ||
@@ -342,3 +354,13 @@ } | ||
this._addListeners(); | ||
this._connectTimeout = setTimeout(() => this._handleTimeout(), connectionTimeout); | ||
// close could be called before creating the ws | ||
if (this._closeCalled) { | ||
this._closeCalled = true; | ||
this._ws!.close(); | ||
} else { | ||
this._connectTimeout = setTimeout( | ||
() => this._handleTimeout(), | ||
connectionTimeout, | ||
); | ||
} | ||
}); | ||
@@ -352,3 +374,3 @@ } | ||
private _disconnect(code?: number, reason?: string) { | ||
private _disconnect(code: number = 1000, reason?: string) { | ||
clearTimeout(this._connectTimeout); | ||
@@ -371,2 +393,10 @@ if (!this._ws) { | ||
private _callEventListener(event: Event | CloseEvent | MessageEvent, listener: EventListener) { | ||
if ('handleEvent' in listener) { | ||
listener.handleEvent(event); | ||
} else { | ||
listener(event); | ||
} | ||
} | ||
private _handleOpen(event: Event) { | ||
@@ -383,6 +413,10 @@ this._debug('open event'); | ||
// send enqueued messages (messages sent before websocket initialization) | ||
this._messageQueue.forEach(message => this._ws!.send(message)); | ||
this._messageQueue = []; | ||
if (this.onopen) { | ||
this.onopen(event); | ||
} | ||
this._listeners.open.forEach(listener => listener(event)); | ||
this._listeners.open.forEach(listener => this._callEventListener(event, listener)); | ||
} | ||
@@ -396,3 +430,3 @@ | ||
} | ||
this._listeners.message.forEach(listener => listener(event)); | ||
this._listeners.message.forEach(listener => this._callEventListener(event, listener)); | ||
} | ||
@@ -408,3 +442,3 @@ | ||
this._debug('exec error listeners'); | ||
this._listeners.error.forEach(listener => listener(event)); | ||
this._listeners.error.forEach(listener => this._callEventListener(event, listener)); | ||
@@ -417,6 +451,10 @@ this._connect(); | ||
if (this._shouldReconnect) { | ||
this._connect(); | ||
} | ||
if (this.onclose) { | ||
this.onclose(event); | ||
} | ||
this._listeners.close.forEach(listener => listener(event)); | ||
this._listeners.close.forEach(listener => this._callEventListener(event, listener)); | ||
} | ||
@@ -423,0 +461,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
123891
14
2823
0
15
1
173