v5shoutbox/v5shoutbox_worker.js

116 lines
3.5 KiB
JavaScript

"use strict";
self.importScripts("/static/scripts/v5shoutbox_irc.js");
function log(...args) {
const time = new Date().toISOString();
console.log(`[${time}]`, ...args);
}
let irc = null;
let clients = [];
function broadcast(obj) {
log(obj.type === "log" ? obj.text : obj);
obj.ircState = irc.state();
clients.forEach(c => c.postMessage(obj));
}
function activate() {
if(irc !== null)
return;
log("activating!");
irc = new IRCClient("wss://irc.planet-casio.com:443");
// TODO: Send certain messages only to specific clients
// (ie. history)
irc.onDebugLog = (ctgy, message) =>
broadcast({ type: "onDebugLog", ctgy: ctgy, message: message });
irc.onConnChanged = (conn) =>
broadcast({ type: "onConnChanged", conn: conn });
irc.onAuthResult = (successful) =>
broadcast({ type: "onAuthResult", successful: successful });
irc.onChannelChanged = (channel, info) =>
broadcast({ type: "onChannelChanged", channel: channel, info: info });
irc.onNewMessage = (id, channel, date, author, message) =>
broadcast({
type: "onNewMessage",
id: id,
channel: channel,
date: date,
author: author,
message: message,
});
irc.onHistoryReceived = (channel, history) =>
broadcast({
type: "onHistoryReceived",
channel: channel,
history: history,
});
}
/* Activate eagerly as soon as the worker gets updated. Normally, when a worker
is updated, the previous version still gets to control new pages until all
of its controlled pages are closed simultaneously. We skip this, so new
pages will get the latest shoutbox service worker as soon as possible. */
self.addEventListener("install", (e) => {
log("installing!");
/* This promise is guaranteed OK to ignore by API */
self.skipWaiting();
});
/* As soon as the worker activates, we claim existing clients. This means that
not only new pages will use the updated worker, but running ones will also
transition to it, giving us transparent background updates. We handle
protocol differences manually; if the main script cannot handle the new
shoutbox version it will simply ask for a reload. Doing this allows us to
take control of the shoutbox without a page refresh when it is loaded for
the first time. */
self.addEventListener("activate", (e) => {
activate();
e.waitUntil(self.clients.claim());
});
self.addEventListener("message", (e) => {
/* Messages handled by the worker itself */
if(e.data.type == "handshake") {
activate();
clients.push(e.source);
log(`New client: ${e.source.id} (total ${clients.length})`);
log("All clients:", clients);
e.source.postMessage({ type: "welcome", ircState: irc.state() });
}
// TODO: Add a mechanism to filter with self.clients.matchAll() since
// sometimes this message does not arrive and we have ghost clients
else if(e.data.type == "leave") {
clients = clients.filter(c => c.id != e.source.id);
log(`Client left: ${e.source.id} (remains ${clients.length})`);
log("All clients:", clients);
}
/* Messages that are forwarded directly to the IRC client */
else if(e.data.type == "connect") {
log("<connect call, not shown>");
irc.connect(e.data.login, e.data.password);
}
else if(e.data.type == "postMessage") {
log(e);
irc.postMessage(e.data.channel, e.data.message);
}
else if(e.data.type == "disconnect") {
log("Disconnect requested");
irc.disconnect();
}
else if(e.data.type == "getHistory") {
log(`History request for ${e.data.channel}`);
irc.getHistory(e.data.channel);
}
});