Refresh service workers when new versions of sw.js come in

- Check once a minute
- When a new sw is here, skip waiting around for the old ones to die and claim the clients

NB: On Chrome, this results in a 2 minute wait with lost connectivity before logout. Refresh to
immediately use the new sw.

NBB: On Firefox, this automatically logs you out without needing to refresh.
This commit is contained in:
Kegan Dougal 2020-03-10 16:26:38 +00:00
parent bf13ec2285
commit 1f1f0f1264
2 changed files with 51 additions and 12 deletions

View File

@ -176,7 +176,28 @@ export async function loadApp() {
window.addEventListener('load', ()=>{ window.addEventListener('load', ()=>{
navigator.serviceWorker.register(window.vector_dendrite_worker_script, { scope: "/" }).then(function(registration) { navigator.serviceWorker.register(window.vector_dendrite_worker_script, { scope: "/" }).then(function(registration) {
// Registration was successful // Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope) console.log('ServiceWorker sw.js registration successful with scope: ', registration.scope);
/* const currWorker = registration.active;
currWorker.addEventListener('statechange', () => {
console.log("Current sw.js state: ", currWorker.state)
}); */
registration.addEventListener('updatefound', () => {
console.log("New dendrite sw.js found!")
const newWorker = registration.installing;
if (!newWorker) {
return;
}
newWorker.addEventListener('statechange', () => {
console.log("New sw.js state: ", newWorker.state)
});
})
console.log("sw.js listening for new updates...");
// periodically check for updates
setInterval(function() {
registration.update();
}, 1000 * 60) // once a minute
}, (err)=>{ }, (err)=>{
// registration failed :( // registration failed :(
console.log('ServiceWorker registration failed: ', err) console.log('ServiceWorker registration failed: ', err)

View File

@ -16,16 +16,21 @@
const bundle_path = self.location.href.replace("/dendrite_sw.js", "") const bundle_path = self.location.href.replace("/dendrite_sw.js", "")
const version = "0.0.2"
self.importScripts(`${bundle_path}/wasm_exec.js`, self.importScripts(`${bundle_path}/wasm_exec.js`,
`${bundle_path}/go_http_bridge.js`, `${bundle_path}/go_http_bridge.js`,
`${bundle_path}/sqlite_bridge.js`) `${bundle_path}/sqlite_bridge.js`)
self.addEventListener('install', function(event) { self.addEventListener('install', function(event) {
console.log("installing SW") console.log(`dendrite-sw.js: v${version} SW install`)
// Tell the browser to kill old sw's running in other tabs and replace them with this one
// This may cause spontaneous logouts.
self.skipWaiting();
}) })
self.addEventListener('activate', function(event) { self.addEventListener('activate', function(event) {
console.log("SW activated") console.log(`dendrite-sw.js: v${version} SW activate`)
global.process = { global.process = {
pid: 1, pid: 1,
env: { env: {
@ -44,11 +49,13 @@ self.addEventListener('activate', function(event) {
event.waitUntil( event.waitUntil(
sqlite_bridge.init(config).then(()=>{ sqlite_bridge.init(config).then(()=>{
console.log(`dendrite-sw.js: v${version} starting dendrite.wasm...`)
const go = new Go() const go = new Go()
WebAssembly.instantiateStreaming(fetch(`${bundle_path}/../../dendrite.wasm`), go.importObject).then((result) => { WebAssembly.instantiateStreaming(fetch(`${bundle_path}/../../dendrite.wasm`), go.importObject).then((result) => {
go.run(result.instance) go.run(result.instance)
// make fetch calls go through this sw - notably if a page registers a sw, it does NOT go through any sw by default // make fetch calls go through this sw - notably if a page registers a sw, it does NOT go through any sw by default
// unless you refresh or call this function. // unless you refresh or call this function.
console.log(`dendrite-sw.js: v${version} claiming open browser tabs`)
self.clients.claim() self.clients.claim()
}); });
}) })
@ -57,16 +64,27 @@ self.addEventListener('activate', function(event) {
self.addEventListener('fetch', function(event) { self.addEventListener('fetch', function(event) {
if (event.request.url.match(/\/_matrix\/client/)) { event.respondWith((async () => {
if (global.fetchListener) { // If this is a page refresh for the current page, then shunt in the new sw
console.log("Forwarding " + event.request.url); // https://github.com/w3c/ServiceWorker/issues/1238
event.respondWith(global.fetchListener.onFetch(event)); if (event.request.mode === "navigate" && event.request.method === "GET" && registration.waiting && (await clients.matchAll()).length < 2) {
console.log("Forcing new sw.js into page")
registration.waiting.postMessage('skipWaiting');
return new Response("", {headers: {"Refresh": "0"}});
}
if (event.request.url.match(/\/_matrix\/client/)) {
if (global.fetchListener) {
console.log(`dendrite-sw.js: v${version} Forwarding ${event.request.url}`);
const response = await global.fetchListener.onFetch(event);
return response;
}
else {
console.log(`dendrite-sw.js: v${version} no fetch listener present for ${event.request.url}`);
}
} }
else { else {
console.log("no fetch listener present for " + event.request.url); return fetch(event.request);
} }
} })());
else {
return fetch(event.request);
}
}) })