// 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);
}
}