126 lines
3.2 KiB
JavaScript
126 lines
3.2 KiB
JavaScript
/** @type {ConnectionManager} */
|
|
let manager;
|
|
|
|
const Status = {
|
|
ERROR: 0,
|
|
CONNECTING: 1,
|
|
CONNFAIL: 2,
|
|
AUTHENTICATING: 3,
|
|
AUTHFAIL: 4,
|
|
CONNECTED: 5,
|
|
DISCONNECTED: 6,
|
|
DISCONNECTING: 7,
|
|
ATTACHED: 8,
|
|
REDIRECT: 9,
|
|
CONNTIMEOUT: 10,
|
|
BINDREQUIRED: 11,
|
|
ATTACHFAIL: 12,
|
|
};
|
|
|
|
/** Class: ConnectionManager
|
|
*
|
|
* Manages the shared websocket connection as well as the ports of the
|
|
* connected tabs.
|
|
*/
|
|
class ConnectionManager {
|
|
constructor() {
|
|
/** @type {MessagePort[]} */
|
|
this.ports = [];
|
|
}
|
|
|
|
/** @param {MessagePort} port */
|
|
addPort(port) {
|
|
this.ports.push(port);
|
|
port.addEventListener('message', (e) => {
|
|
const method = e.data[0];
|
|
try {
|
|
this[/** @type {'send'|'_closeSocket'}*/ (method)](e.data.splice(1));
|
|
} catch (e) {
|
|
console?.error(e);
|
|
}
|
|
});
|
|
port.start();
|
|
}
|
|
|
|
/**
|
|
* @param {[string, string]} data
|
|
*/
|
|
_connect(data) {
|
|
this.jid = data[1];
|
|
this._closeSocket();
|
|
this.socket = new WebSocket(data[0], 'xmpp');
|
|
this.socket.onopen = () => this._onOpen();
|
|
this.socket.onerror = (e) => this._onError(e);
|
|
this.socket.onclose = (e) => this._onClose(e);
|
|
this.socket.onmessage = (message) => this._onMessage(message);
|
|
}
|
|
|
|
_attach() {
|
|
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
|
|
this.ports.forEach((p) => p.postMessage(['_attachCallback', Status.ATTACHED, this.jid]));
|
|
} else {
|
|
this.ports.forEach((p) => p.postMessage(['_attachCallback', Status.ATTACHFAIL]));
|
|
}
|
|
}
|
|
|
|
/** @param {string} str */
|
|
send(str) {
|
|
this.socket.send(str);
|
|
}
|
|
|
|
/** @param {string} str */
|
|
close(str) {
|
|
if (this.socket && this.socket.readyState !== WebSocket.CLOSED) {
|
|
try {
|
|
this.socket.send(str);
|
|
} catch (e) {
|
|
this.ports.forEach((p) => p.postMessage(['log', 'error', e]));
|
|
this.ports.forEach((p) => p.postMessage(['log', 'error', "Couldn't send <close /> tag."]));
|
|
}
|
|
}
|
|
}
|
|
|
|
_onOpen() {
|
|
this.ports.forEach((p) => p.postMessage(['_onOpen']));
|
|
}
|
|
|
|
/** @param {CloseEvent} e */
|
|
_onClose(e) {
|
|
this.ports.forEach((p) => p.postMessage(['_onClose', e.reason]));
|
|
}
|
|
|
|
/** @param {MessageEvent} message */
|
|
_onMessage(message) {
|
|
const o = { 'data': message.data };
|
|
this.ports.forEach((p) => p.postMessage(['_onMessage', o]));
|
|
}
|
|
|
|
/** @param {Event} error */
|
|
_onError(error) {
|
|
this.ports.forEach((p) => p.postMessage(['_onError', error]));
|
|
}
|
|
|
|
_closeSocket() {
|
|
if (this.socket) {
|
|
try {
|
|
this.socket.onclose = null;
|
|
this.socket.onerror = null;
|
|
this.socket.onmessage = null;
|
|
this.socket.close();
|
|
} catch (e) {
|
|
this.ports.forEach((p) => p.postMessage(['log', 'error', e]));
|
|
}
|
|
}
|
|
this.socket = null;
|
|
}
|
|
}
|
|
|
|
addEventListener(
|
|
'connect',
|
|
/** @param {MessageEvent} e */
|
|
(e) => {
|
|
manager = manager || new ConnectionManager();
|
|
manager.addPort(e.ports[0]);
|
|
}
|
|
);
|