From 1f1f0f126475af7cabd268b35955a6d93aa0c6b4 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 10 Mar 2020 16:26:38 +0000 Subject: [PATCH] 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. --- src/vector/app.js | 23 +++++++++++++++++++++- src/vector/dendrite-sw.js | 40 ++++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/vector/app.js b/src/vector/app.js index 27d81421..ee65980d 100644 --- a/src/vector/app.js +++ b/src/vector/app.js @@ -176,7 +176,28 @@ export async function loadApp() { window.addEventListener('load', ()=>{ navigator.serviceWorker.register(window.vector_dendrite_worker_script, { scope: "/" }).then(function(registration) { // 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)=>{ // registration failed :( console.log('ServiceWorker registration failed: ', err) diff --git a/src/vector/dendrite-sw.js b/src/vector/dendrite-sw.js index 1ded2b1c..bd5c7ba7 100644 --- a/src/vector/dendrite-sw.js +++ b/src/vector/dendrite-sw.js @@ -16,16 +16,21 @@ const bundle_path = self.location.href.replace("/dendrite_sw.js", "") +const version = "0.0.2" + self.importScripts(`${bundle_path}/wasm_exec.js`, `${bundle_path}/go_http_bridge.js`, `${bundle_path}/sqlite_bridge.js`) 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) { - console.log("SW activated") + console.log(`dendrite-sw.js: v${version} SW activate`) global.process = { pid: 1, env: { @@ -44,11 +49,13 @@ self.addEventListener('activate', function(event) { event.waitUntil( sqlite_bridge.init(config).then(()=>{ + console.log(`dendrite-sw.js: v${version} starting dendrite.wasm...`) const go = new Go() WebAssembly.instantiateStreaming(fetch(`${bundle_path}/../../dendrite.wasm`), go.importObject).then((result) => { 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 // unless you refresh or call this function. + console.log(`dendrite-sw.js: v${version} claiming open browser tabs`) self.clients.claim() }); }) @@ -57,16 +64,27 @@ self.addEventListener('activate', function(event) { self.addEventListener('fetch', function(event) { - if (event.request.url.match(/\/_matrix\/client/)) { - if (global.fetchListener) { - console.log("Forwarding " + event.request.url); - event.respondWith(global.fetchListener.onFetch(event)); + event.respondWith((async () => { + // If this is a page refresh for the current page, then shunt in the new sw + // https://github.com/w3c/ServiceWorker/issues/1238 + 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 { - console.log("no fetch listener present for " + event.request.url); + return fetch(event.request); } - } - else { - return fetch(event.request); - } + })()); })