176 lines
4.0 KiB
JavaScript
176 lines
4.0 KiB
JavaScript
class SmartWebSocket{
|
|
|
|
socket;
|
|
url;
|
|
protocols;
|
|
debugName;
|
|
|
|
autoreconnect;
|
|
|
|
#events;
|
|
#reconnecting;
|
|
|
|
|
|
constructor(url, protocols = [], autoreconnect = true, debugName = null) {
|
|
this.url = url;
|
|
this.protocols = protocols;
|
|
this.autoreconnect = autoreconnect;
|
|
this.debugName = debugName;
|
|
|
|
this.#events = {};
|
|
this.#reconnecting = false;
|
|
|
|
this.#connect();
|
|
}
|
|
|
|
#formatedConsole(method, message, color) {
|
|
if (color && typeof message == "string") {
|
|
console[method]("%c%s\t | %c%s", "font-weight: bold; color: cyan;", this.debugName ?? this.url, `color: ${color};`, message);
|
|
} else {
|
|
console[method]("%c%s\t |", "font-weight: bold; color: cyan;", this.debugName ?? this.url, message);
|
|
}
|
|
}
|
|
|
|
#log(message, color = null) {
|
|
this.#formatedConsole("log", message, color);
|
|
}
|
|
#error(message) {
|
|
this.#formatedConsole("error", message);
|
|
}
|
|
#warn(message) {
|
|
this.#formatedConsole("warn", message);
|
|
}
|
|
#info(message, color = null) {
|
|
this.#formatedConsole("info", message, color);
|
|
}
|
|
|
|
#connect() {
|
|
this.#info("Connecting socket...", "yellow");
|
|
this.socket = new WebSocket(this.url, this.protocols);
|
|
|
|
this.socket.addEventListener("open", (eventData) => this.#openHandler(eventData));
|
|
this.socket.addEventListener("close", (eventData) => this.#closeHandler(eventData));
|
|
this.socket.addEventListener("error", (eventData) => this.#errorHandler(eventData));
|
|
this.socket.addEventListener("message", (eventData) => this.#messageHandler(eventData));
|
|
}
|
|
|
|
|
|
#eventHandler(event, data = null) {
|
|
if (!(event in this.#events)) {
|
|
return;
|
|
}
|
|
for (let i = 0; i < this.#events[event].length; i++) {
|
|
this.#events[event][i](data);
|
|
}
|
|
}
|
|
|
|
#openHandler(eventData) {
|
|
this.#info("Socket connected.", "lime");
|
|
this.#reconnecting = false;
|
|
|
|
this.#eventHandler("open", eventData);
|
|
}
|
|
|
|
#closeHandler(eventData) {
|
|
if (eventData.wasClean) {
|
|
this.#info("Socket disconnected cleanly.");
|
|
} else {
|
|
if (!this.#reconnecting) {
|
|
this.#warn("Socket disconnected apruptly!");
|
|
if (!this.autoreconnect) {
|
|
this.#warn("autoreconnect is set to false! Socket will not automatically reconnect in case of an unexpected loss of connection.");
|
|
}
|
|
}
|
|
}
|
|
if (this.autoreconnect) {
|
|
if (!this.#reconnecting) {
|
|
this.#info("Automatically reconnecting.");
|
|
this.#reconnecting = true;
|
|
}
|
|
this.reconnect();
|
|
}
|
|
|
|
this.#eventHandler("close", eventData);
|
|
}
|
|
|
|
#errorHandler(eventData) {
|
|
if (!this.#reconnecting) {
|
|
this.#error(eventData);
|
|
}
|
|
this.#eventHandler("error", eventData);
|
|
}
|
|
|
|
#messageHandler(eventData) {
|
|
let jsonObj = false;
|
|
try {
|
|
jsonObj = JSON.parse(eventData.data);
|
|
} catch (err) {
|
|
this.#warn("received non-JSON data from WebSocket");
|
|
jsonObj = false;
|
|
}
|
|
|
|
if (jsonObj && "event" in jsonObj) {
|
|
if ("data" in jsonObj) {
|
|
this.#eventHandler(jsonObj.event, jsonObj.data);
|
|
} else {
|
|
this.#eventHandler(jsonObj.event);
|
|
}
|
|
}
|
|
|
|
this.#eventHandler("message", eventData);
|
|
}
|
|
|
|
reconnect() {
|
|
if (this.socket != undefined && this.socket.readyState < 3) {
|
|
if (!this.autoreconnect) {
|
|
this.socket.addEventListener("close", () => this.#connect());
|
|
}
|
|
this.socket.close();
|
|
this.#info("Closing socket.", "lime")
|
|
} else {
|
|
this.#connect();
|
|
}
|
|
}
|
|
|
|
close() {
|
|
if (this.socket.readyState == 4) {
|
|
throw "socket already closed";
|
|
}
|
|
this.autoreconnect = false;
|
|
this.socket.close();
|
|
}
|
|
|
|
isReady() {
|
|
return this.socket.readyState == 1;
|
|
}
|
|
|
|
on(event, handler) {
|
|
if (typeof event != "string") {
|
|
throw "argument event is expected to be of type string";
|
|
}
|
|
if (typeof handler != "function") {
|
|
throw "argument handler is expected to be of type function";
|
|
}
|
|
|
|
if (event in this.#events) {
|
|
this.#events[event].push(handler);
|
|
} else {
|
|
this.#events[event] = [handler];
|
|
}
|
|
}
|
|
|
|
send(event, data = null) {
|
|
if (typeof event != "string") {
|
|
throw "argument event is expected to be of type string";
|
|
}
|
|
this.socket.send(JSON.stringify({event: event, data: data}));
|
|
}
|
|
|
|
sendRaw(data) {
|
|
this.socket.send(data);
|
|
}
|
|
|
|
get events() {
|
|
return this.#events;
|
|
}
|
|
} |