///
///
import ReconnectingWebsocket from 'reconnecting-websocket';
import { FLAG_I18N, FLAG_INFO } from 'vj/constant/message';
declare const self: SharedWorkerGlobalScope;
console.log('SharedWorker init');
let conn: ReconnectingWebsocket;
let lcookie: string;
const ports: Set = new Set();
interface RequestInitSharedConnPayload {
type: 'conn';
cookie: string;
path: string;
}
interface RequestAckPayload {
type: 'ack';
id: string;
payload?: any;
}
interface RequestUnloadPayload {
type: 'unload';
}
type RequestPayload = RequestInitSharedConnPayload | RequestAckPayload | RequestUnloadPayload;
const ack = {};
function broadcastMsg(message: any) {
for (const p of ports) p.postMessage(message);
}
function onMessage(message: any) {
broadcastMsg({ type: 'message', payload: message });
let acked = false;
let payload = message;
ack[message.mdoc._id] = () => { acked = true; };
ack[`${message.mdoc._id}-i18n`] = (v) => { payload = v; };
if (message.mdoc.flag & FLAG_I18N) broadcastMsg({ type: 'i18n', payload: message });
setTimeout(() => {
delete ack[message.mdoc._id];
delete ack[`${message.mdoc._id}-i18n`];
if (acked) return;
if (message.mdoc.flag & FLAG_INFO) return;
if (Notification?.permission !== 'granted') {
console.log('Notification permission denied');
return;
}
console.log('Sending as system notification');
// eslint-disable-next-line no-new
new Notification(
payload.udoc._id === 1 ? payload.mdoc.content.split('\n')[0] : payload.udoc.uname || 'Hydro Notification',
payload.udoc._id === 1 ? {
tag: `notification-${payload.mdoc._id}`,
icon: payload.mdoc.avatar || '/android-chrome-192x192.png',
body: payload.mdoc.content.split('\n').slice(1).join('\n'),
} : {
tag: `message-${payload.mdoc._id}`,
icon: payload.udoc.avatarUrl || '/android-chrome-192x192.png',
body: payload.mdoc.content,
},
);
}, 3000);
}
function initConn(path: string, port: MessagePort, cookie: any) {
ports.add(port);
console.log('Init connection');
lcookie = cookie.split('sid=')[1].split(';')[0];
if (conn) return;
const url = new URL(path, location.origin);
conn = new ReconnectingWebsocket(url.toString().replace('http', 'ws'));
conn.onopen = () => {
console.log('Connected');
broadcastMsg({ type: 'open' });
conn.send(JSON.stringify({
operation: 'subscribe',
request_id: Math.random().toString(16).substring(2),
credential: lcookie,
channels: ['message'],
}));
};
conn.onerror = () => broadcastMsg({ type: 'error' });
conn.onclose = (ev) => broadcastMsg({ type: 'close', error: ev.reason });
conn.onmessage = (message) => {
if (process.env.NODE_ENV !== 'production') console.log('SharedWorker.port.onmessage: ', message);
if (message.data === 'ping') {
conn.send('pong');
return;
}
const payload = JSON.parse(message.data);
if (['PermissionError', 'PrivilegeError'].includes(payload.error)) {
broadcastMsg({ type: 'close', error: payload.error });
conn.close();
} else if (payload.operation === 'event') {
onMessage(payload.payload);
}
};
}
self.onconnect = function (e) {
const port = e.ports[0];
port.addEventListener('message', (msg: { data: RequestPayload }) => {
if (msg.data.type === 'conn') initConn(msg.data.path, port, msg.data.cookie);
if (msg.data.type === 'ack') ack[msg.data.id]?.(msg.data.payload);
if (msg.data.type === 'unload') ports.delete(port);
});
port.start();
};