lib0
Version:
> Monorepo of isomorphic utility functions
158 lines (146 loc) • 4.43 kB
JavaScript
'use strict';
var observable = require('./observable.cjs');
var time = require('./time-bc2081b9.cjs');
var math = require('./math-08e068f9.cjs');
/* eslint-env browser */
const reconnectTimeoutBase = 1200;
const maxReconnectTimeout = 2500;
// @todo - this should depend on awareness.outdatedTime
const messageReconnectTimeout = 30000;
/**
* @param {WebsocketClient} wsclient
*/
const setupWS = (wsclient) => {
if (wsclient.shouldConnect && wsclient.ws === null) {
const websocket = new WebSocket(wsclient.url);
const binaryType = wsclient.binaryType;
/**
* @type {any}
*/
let pingTimeout = null;
if (binaryType) {
websocket.binaryType = binaryType;
}
wsclient.ws = websocket;
wsclient.connecting = true;
wsclient.connected = false;
websocket.onmessage = event => {
wsclient.lastMessageReceived = time.getUnixTime();
const data = event.data;
const message = typeof data === 'string' ? JSON.parse(data) : data;
if (message && message.type === 'pong') {
clearTimeout(pingTimeout);
pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2);
}
wsclient.emit('message', [message, wsclient]);
};
/**
* @param {any} error
*/
const onclose = error => {
if (wsclient.ws !== null) {
wsclient.ws = null;
wsclient.connecting = false;
if (wsclient.connected) {
wsclient.connected = false;
wsclient.emit('disconnect', [{ type: 'disconnect', error }, wsclient]);
} else {
wsclient.unsuccessfulReconnects++;
}
// Start with no reconnect timeout and increase timeout by
// log10(wsUnsuccessfulReconnects).
// The idea is to increase reconnect timeout slowly and have no reconnect
// timeout at the beginning (log(1) = 0)
setTimeout(setupWS, math.min(math.log10(wsclient.unsuccessfulReconnects + 1) * reconnectTimeoutBase, maxReconnectTimeout), wsclient);
}
clearTimeout(pingTimeout);
};
const sendPing = () => {
if (wsclient.ws === websocket) {
wsclient.send({
type: 'ping'
});
}
};
websocket.onclose = () => onclose(null);
websocket.onerror = error => onclose(error);
websocket.onopen = () => {
wsclient.lastMessageReceived = time.getUnixTime();
wsclient.connecting = false;
wsclient.connected = true;
wsclient.unsuccessfulReconnects = 0;
wsclient.emit('connect', [{ type: 'connect' }, wsclient]);
// set ping
pingTimeout = setTimeout(sendPing, messageReconnectTimeout / 2);
};
}
};
/**
* @deprecated
* @extends Observable<string>
*/
class WebsocketClient extends observable.Observable {
/**
* @param {string} url
* @param {object} opts
* @param {'arraybuffer' | 'blob' | null} [opts.binaryType] Set `ws.binaryType`
*/
constructor (url, { binaryType } = {}) {
super();
this.url = url;
/**
* @type {WebSocket?}
*/
this.ws = null;
this.binaryType = binaryType || null;
this.connected = false;
this.connecting = false;
this.unsuccessfulReconnects = 0;
this.lastMessageReceived = 0;
/**
* Whether to connect to other peers or not
* @type {boolean}
*/
this.shouldConnect = true;
this._checkInterval = setInterval(() => {
if (this.connected && messageReconnectTimeout < time.getUnixTime() - this.lastMessageReceived) {
// no message received in a long time - not even your own awareness
// updates (which are updated every 15 seconds)
/** @type {WebSocket} */ (this.ws).close();
}
}, messageReconnectTimeout / 2);
setupWS(this);
}
/**
* @param {any} message
*/
send (message) {
if (this.ws) {
this.ws.send(JSON.stringify(message));
}
}
destroy () {
clearInterval(this._checkInterval);
this.disconnect();
super.destroy();
}
disconnect () {
this.shouldConnect = false;
if (this.ws !== null) {
this.ws.close();
}
}
connect () {
this.shouldConnect = true;
if (!this.connected && this.ws === null) {
setupWS(this);
}
}
}
var websocket = /*#__PURE__*/Object.freeze({
__proto__: null,
WebsocketClient: WebsocketClient
});
exports.WebsocketClient = WebsocketClient;
exports.websocket = websocket;
//# sourceMappingURL=websocket-aa53d26d.cjs.map