|
// retoor <retoor@molodetz.nl>
|
|
|
|
const RECONNECT_DELAY_MS = 1500;
|
|
const WRONG_WORKER_RETRY_MS = 200;
|
|
const WRONG_WORKER_CODE = 4013;
|
|
|
|
export class MessagesSocket {
|
|
constructor(handlers) {
|
|
this.handlers = handlers || {};
|
|
this.ws = null;
|
|
this.url = (location.protocol === "https:" ? "wss://" : "ws://") + location.host + "/messages/ws";
|
|
this._shouldRun = false;
|
|
this._settled = false;
|
|
}
|
|
|
|
connect() {
|
|
this._shouldRun = true;
|
|
this._open();
|
|
}
|
|
|
|
isOpen() {
|
|
return this.ws && this.ws.readyState === WebSocket.OPEN;
|
|
}
|
|
|
|
_open() {
|
|
this._settled = false;
|
|
this.ws = new WebSocket(this.url);
|
|
this.ws.addEventListener("open", () => this._emit("onOpen"));
|
|
this.ws.addEventListener("close", (event) => {
|
|
const transient = !this._settled && event.code === WRONG_WORKER_CODE;
|
|
if (!transient) this._emit("onClose");
|
|
if (this._shouldRun) {
|
|
const delay = transient ? WRONG_WORKER_RETRY_MS : RECONNECT_DELAY_MS;
|
|
window.setTimeout(() => this._open(), delay);
|
|
}
|
|
});
|
|
this.ws.addEventListener("error", () => this._emit("onError"));
|
|
this.ws.addEventListener("message", (event) => {
|
|
let payload;
|
|
try {
|
|
payload = JSON.parse(event.data);
|
|
} catch {
|
|
return;
|
|
}
|
|
if (!this._settled) {
|
|
this._settled = true;
|
|
this._emit("onReady", payload);
|
|
}
|
|
this._emit("onMessage", payload);
|
|
});
|
|
}
|
|
|
|
send(message) {
|
|
if (this.isOpen()) {
|
|
this.ws.send(JSON.stringify(message));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
close() {
|
|
this._shouldRun = false;
|
|
if (this.ws) this.ws.close();
|
|
}
|
|
|
|
_emit(name, payload) {
|
|
const handler = this.handlers[name];
|
|
if (typeof handler === "function") handler(payload);
|
|
}
|
|
}
|