81 lines
1.9 KiB
JavaScript
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();
|
|
}
|
|
}
|