2025-11-05 17:04:23 -03:00

81 lines
1.9 KiB
JavaScript

import { EventEmitter, listeners } from "@xmpp/events";
import { parseURI } from "@xmpp/connection/lib/util.js";
const CODE = "ECONNERROR";
export function isSecure(url) {
const uri = parseURI(url);
if (uri.protocol === "wss:") return true;
if (["localhost", "127.0.0.1", "::1"].includes(uri.hostname)) return true;
return false;
}
export default class Socket extends EventEmitter {
#listeners = null;
socket = null;
url = null;
secure = false;
connect(url) {
this.url = url;
this.secure = isSecure(url);
// eslint-disable-next-line n/no-unsupported-features/node-builtins
this._attachSocket(new WebSocket(url, ["xmpp"]));
}
_attachSocket(socket) {
this.socket = socket;
this.#listeners ??= listeners({
open: () => this.emit("connect"),
message: ({ data }) => this.emit("data", data),
error: (event) => {
const { url } = this;
// WS
let { error } = event;
// DOM
if (!error) {
error = new Error(event.message || `WebSocket ${CODE} ${url}`);
error.errno = CODE;
error.code = CODE;
}
error.event = event;
error.url = url;
this.emit("error", error);
},
close: (event) => {
this._detachSocket();
this.emit("close", !event.wasClean, event);
},
});
this.#listeners.subscribe(this.socket);
}
_detachSocket() {
this.url = null;
this.secure = false;
this.socket && this.#listeners?.unsubscribe(this.socket);
this.socket = null;
}
end() {
this.socket.close();
}
write(data, fn) {
function done(err) {
if (!fn) return;
// eslint-disable-next-line promise/catch-or-return, promise/no-promise-in-callback
Promise.resolve().then(() => fn(err));
}
try {
this.socket.send(data);
} catch (err) {
done(err);
return;
}
done();
}
}