SW refinements

This commit is contained in:
MathMan05
2025-12-09 17:22:41 -06:00
parent 2583298351
commit 5ee84ca308
5 changed files with 223 additions and 45 deletions

View File

@@ -2471,8 +2471,17 @@ class Localuser {
sw.onchange = (e) => {
SW.setMode(["false", "offlineOnly", "true"][e] as "false" | "offlineOnly" | "true");
};
update.addButtonInput("", I18n.localuser.CheckUpdate(), () => {
SW.checkUpdate();
update.addButtonInput("", I18n.localuser.CheckUpdate(), async () => {
const update = await SW.checkUpdates();
const text = update ? I18n.localuser.updatesYay() : I18n.localuser.noUpdates();
const d = new Dialog("");
d.options.addTitle(text);
if (update) {
d.options.addButtonInput("", I18n.localuser.refreshPage(), () => {
window.location.reload();
});
}
d.show();
});
update.addButtonInput("", I18n.localuser.clearCache(), () => {
SW.forceClear();

View File

@@ -1,3 +1,5 @@
import {messageFrom, messageTo} from "./utils/serviceType";
function deleteoldcache() {
caches.delete("cache");
console.log("this ran :P");
@@ -19,32 +21,54 @@ self.addEventListener("activate", async () => {
console.log("Service Worker activated");
checkCache();
});
async function tryToClose() {
const portArr = [...ports];
if (portArr.length) {
for (let i = 1; i < portArr.length; i++) {
portArr[i].postMessage({code: "closing"});
}
portArr[0].postMessage({code: "close"});
} else {
throw new Error("No Fermi clients connected?");
}
}
function sendAll(message: messageFrom) {
for (const port of ports) {
port.postMessage(message);
}
}
async function checkCache() {
if (checkedrecently) {
return;
return false;
}
const promise = await caches.match("/getupdates");
if (promise) {
lastcache = await promise.text();
}
console.log(lastcache);
fetch("/getupdates").then(async (data) => {
return fetch("/getupdates").then(async (data) => {
setTimeout(
(_: any) => {
checkedrecently = false;
},
1000 * 60 * 30,
);
if (!data.ok) return;
if (!data.ok) return false;
const text = await data.clone().text();
console.log(text, lastcache);
if (lastcache !== text) {
deleteoldcache();
putInCache("/getupdates", data);
self.close();
tryToClose();
checkedrecently = true;
sendAll({
code: "updates",
updates: true,
});
return true;
}
checkedrecently = true;
return false;
});
}
var checkedrecently = false;
@@ -133,17 +157,56 @@ self.addEventListener("fetch", (e) => {
console.error(e);
}
});
const ports = new Set<MessagePort>();
function listenToPort(port: MessagePort) {
function sendMessage(message: messageFrom) {
port.postMessage(message);
}
port.onmessage = async (e) => {
const data = e.data as messageTo;
switch (data.code) {
case "ping": {
sendMessage({
code: "pong",
count: ports.size,
});
break;
}
case "close": {
ports.delete(port);
break;
}
case "replace": {
//@ts-ignore-error Just the type or wrong or something
self.skipWaiting();
break;
}
case "CheckUpdate": {
checkedrecently = false;
if (!(await checkCache())) {
sendMessage({
code: "updates",
updates: false,
});
}
break;
}
}
};
port.addEventListener("close", () => {
ports.delete(port);
});
}
console.log("heya");
//
self.addEventListener("message", (message) => {
const data = message.data;
switch (data.code) {
case "setMode":
enabled = data.data;
break;
case "CheckUpdate":
checkedrecently = false;
checkCache();
break;
case "ForceClear":
deleteoldcache();
break;
@@ -152,5 +215,10 @@ self.addEventListener("message", (message) => {
console.error("Hey!");
port.postMessage({code: "isValid", res: toPathNoDefault(data.url)});
break;
case "port": {
const port = data.port as MessagePort;
ports.add(port);
listenToPort(port);
}
}
});

View File

@@ -0,0 +1,28 @@
export type messageTo =
| {
code: "ping";
}
| {
code: "close";
}
| {
code: "replace";
}
| {
code: "CheckUpdate";
};
export type messageFrom =
| {
code: "pong";
count: number;
}
| {
code: "close";
}
| {
code: "closing";
}
| {
code: "updates";
updates: boolean;
};

View File

@@ -2,6 +2,7 @@ import {I18n} from "../i18n.js";
import {MarkDown} from "../markdown.js";
import {Dialog} from "../settings.js";
import {fix} from "./cssMagic.js";
import {messageFrom, messageTo} from "./serviceType.js";
fix();
let instances:
| {
@@ -833,23 +834,120 @@ export {checkInstance};
export class SW {
static worker: undefined | ServiceWorker;
static port?: MessagePort;
static init() {
SW.setMode(
(localStorage.getItem("SWMode") as "false" | "offlineOnly" | "true" | undefined) || "true",
);
const port = new MessageChannel();
SW.worker?.postMessage(
{
code: "port",
port: port.port2,
},
[port.port2],
);
this.port = port.port1;
this.port.onmessage = (e) => {
this.handleMessage(e.data);
};
window.addEventListener("beforeunload", () => {
this.postMessage({code: "close"});
port.port1.close();
});
this.postMessage({code: "ping"});
}
static postMessage(message: messageTo) {
this.port?.postMessage(message);
}
private static updateWatchers = new Set<(updates: boolean) => void>();
static watchForUpdates(func: (updates: boolean) => void) {
this.updateWatchers.add(func);
}
static stopWatchForUpdates(func: (updates: boolean) => void) {
this.updateWatchers.delete(func);
}
static async handleMessage(message: messageFrom) {
switch (message.code) {
case "pong": {
console.log(message);
break;
}
case "close": {
for (const thing of await navigator.serviceWorker.getRegistrations()) {
await thing.unregister();
}
await this.start();
this.postMessage({code: "replace"});
break;
}
case "closing": {
await this.start();
break;
}
case "updates": {
for (const thing of this.updateWatchers) {
thing(message.updates);
}
}
}
}
static async checkUpdates(): Promise<boolean> {
return new Promise((res) => {
const func = (update: boolean) => {
this.stopWatchForUpdates(func);
res(update);
};
this.watchForUpdates(func);
this.postMessage({code: "CheckUpdate"});
});
}
static async start() {
if (!("serviceWorker" in navigator)) return;
return new Promise<void>((res) => {
navigator.serviceWorker
.register("/service.js", {
scope: "/",
})
.then((registration) => {
let serviceWorker: ServiceWorker | undefined;
if (registration.installing) {
serviceWorker = registration.installing;
console.log("installing");
} else if (registration.waiting) {
serviceWorker = registration.waiting;
console.log("waiting");
} else if (registration.active) {
serviceWorker = registration.active;
console.log("active");
}
SW.worker = serviceWorker;
SW.init();
if (serviceWorker) {
console.log(serviceWorker.state);
serviceWorker.addEventListener("statechange", (_) => {
console.log(serviceWorker.state);
});
res();
}
});
});
}
static setMode(mode: "false" | "offlineOnly" | "true") {
localStorage.setItem("SWMode", mode);
if (this.worker) {
this.worker.postMessage({data: mode, code: "setMode"});
}
}
static checkUpdate() {
if (this.worker) {
this.worker.postMessage({code: "CheckUpdate"});
}
}
static forceClear() {
if (this.worker) {
this.worker.postMessage({code: "ForceClear"});
}
}
}
SW.start();
let installPrompt: Event | undefined = undefined;
window.addEventListener("beforeinstallprompt", (event) => {
event.preventDefault();
@@ -858,35 +956,7 @@ window.addEventListener("beforeinstallprompt", (event) => {
export function installPGet() {
return installPrompt;
}
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/service.js", {
scope: "/",
})
.then((registration) => {
let serviceWorker: ServiceWorker | undefined;
if (registration.installing) {
serviceWorker = registration.installing;
console.log("installing");
} else if (registration.waiting) {
serviceWorker = registration.waiting;
console.log("waiting");
} else if (registration.active) {
serviceWorker = registration.active;
console.log("active");
}
SW.worker = serviceWorker;
SW.setMode(
(localStorage.getItem("SWMode") as "false" | "offlineOnly" | "true" | undefined) || "true",
);
if (serviceWorker) {
console.log(serviceWorker.state);
serviceWorker.addEventListener("statechange", (_) => {
console.log(serviceWorker.state);
});
}
});
}
export function getInstances() {
return instances;
}

View File

@@ -485,6 +485,9 @@
"keyname":"Key name:"
},
"localuser": {
"noUpdates":"No updates found",
"updatesYay":"Updates have been found!",
"refreshPage":"Refresh to apply",
"trusted":"Trusted Domains",
"trustedDesc":"These domains when you click on links from them will ***not*** prompt you for permission to open like other links, only give this to URLs you trust",
"trace": "Traces",