From e42995047ca05f51c12d8b4eabda557f851832f3 Mon Sep 17 00:00:00 2001 From: Jaifroid Date: Sun, 9 Jan 2022 09:19:51 +0000 Subject: [PATCH] Enable Service Worker mode in Firefox extension via PWA workaround #764 (#771) --- .github/workflows/CI.yml | 10 + docker/dockerfile-moz-extension.pwa | 12 + docker/index.nginx.html | 19 ++ index.html | 6 +- manifest.json | 2 + scripts/Publish-Implementation.ps1 | 133 +++++++++++ scripts/create_all_packages.sh | 3 +- scripts/test_duplicate_values.sh | 30 +++ scripts/test_pwa_server.sh | 14 ++ service-worker.js | 241 ++++++++++++++----- www/index.html | 19 +- www/js/app.js | 359 ++++++++++++++++++++-------- www/js/init.js | 96 ++++---- www/js/lib/settingsStore.js | 20 +- www/js/lib/uiUtil.js | 75 +++++- 15 files changed, 825 insertions(+), 214 deletions(-) create mode 100644 docker/dockerfile-moz-extension.pwa create mode 100644 docker/index.nginx.html create mode 100644 scripts/Publish-Implementation.ps1 create mode 100644 scripts/test_duplicate_values.sh create mode 100644 scripts/test_pwa_server.sh diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2d532d3af..8a2322470 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -24,6 +24,16 @@ jobs: # Clone the repo and checkout the commit for which the workflow was triggered - uses: actions/checkout@v2 + - name: Test integrity of app parameters + shell: bash + run: | + # Check that values of assetsCache and appVersion are correctly duplicated + chmod +x ./scripts/test_duplicate_values.sh + ./scripts/test_duplicate_values.sh + # Check that PWAServer is correctly set in app.js + chmod +x ./scripts/test_pwa_server.sh + ./scripts/test_pwa_server.sh + # Install Node.js LTS - uses: actions/setup-node@v2 with: diff --git a/docker/dockerfile-moz-extension.pwa b/docker/dockerfile-moz-extension.pwa new file mode 100644 index 000000000..1c6030062 --- /dev/null +++ b/docker/dockerfile-moz-extension.pwa @@ -0,0 +1,12 @@ +FROM nginx:latest + +EXPOSE 80 + +RUN mkdir /usr/share/nginx/html/current/ +COPY ./docker/index.nginx.html /usr/share/nginx/html/index.html +COPY ./manifest.json /usr/share/nginx/html/current/ +COPY ./service-worker.js /usr/share/nginx/html/current/ +COPY ./index.html /usr/share/nginx/html/current/ +COPY ./CHANGELOG.md /usr/share/nginx/html/current/ +COPY ./LICENSE-GPLv3.txt /usr/share/nginx/html/current/ +COPY ./www /usr/share/nginx/html/current/www/ diff --git a/docker/index.nginx.html b/docker/index.nginx.html new file mode 100644 index 000000000..aa55382fc --- /dev/null +++ b/docker/index.nginx.html @@ -0,0 +1,19 @@ + + + + + + + Redirection to index.html + + + + + + \ No newline at end of file diff --git a/index.html b/index.html index 8f95c4631..bb99a238d 100644 --- a/index.html +++ b/index.html @@ -1,8 +1,12 @@ + -Redirection to index.html + Redirection to index.html + + + \ No newline at end of file diff --git a/manifest.json b/manifest.json index 2bb140bc4..0003747ab 100644 --- a/manifest.json +++ b/manifest.json @@ -32,6 +32,8 @@ "id": "kiwix-html5-unlisted@kiwix.org" } }, + + "web_accessible_resources": ["www/index.html"], "background": { "scripts": ["webextension/backgroundscript.js"] diff --git a/scripts/Publish-Implementation.ps1 b/scripts/Publish-Implementation.ps1 new file mode 100644 index 000000000..f07d9e3cf --- /dev/null +++ b/scripts/Publish-Implementation.ps1 @@ -0,0 +1,133 @@ +# This is a utility script which helps developers choose sensible values for publishing the implementation of this app +# to GitHub Pages, or to eh docker container. It is useful for testing and developing code in a specific branch. It checks +# app.js and service-worker.js for consistency, and checks that the underlying branch of a PR has been checked out +# (rather than the PR itself). It then calls the GitHub REST API for dispatching the workflow using the provided values. +# +# IMPORTANT: Ensure that your personal github token is in your local copy of the '/scripts' directory, saved as 'github_token'. +# +# You may run this script with commandline switches -machine_name (this could be 'dev'), -target (either 'ghpages' or 'docker'), +# the -branch_name, and -dryrun (this will show the changes that would be made if run without the -dryrun switch). +# Alternatively, if you do not provide these values, you will be prompted with sensible defaults. + +# Prevents execution with unrecognized switches +[CmdletBinding()] +param ( + [string]$machine_name = "", + [string]$target = "", + [string]$branch_name = "", + [switch]$dryrun = $false +) + +# Provide parameters +$release_uri = 'https://api.github.com/repos/kiwix/kiwix-js/actions/workflows/publish-extension.yaml/dispatches' + +$app_params = Select-String 'appVersion' "$PSScriptRoot\..\www\js\app.js" -List +$serviceworker = Select-String 'appVersion' "$PSScriptRoot\..\service-worker.js" -List +$suggested_build = '' +$app_tag = '' +if ($app_params -match 'params\[[''"]appVersion[''"]]\s*=\s*[''"]([^''"]+)') { + $app_tag = $matches[1] + $suggested_build = 'dev-' + $app_tag +} else { + "*** WARNING: App version is incorrectly set in app.js.`nPlease correct before continuing.`n" + exit +} +$sw_tag = '' +if ($serviceworker -match 'appVersion\s*=\s*[''"]([^''"]+)') { + $sw_tag = $matches[1] + if ($sw_tag -ne $app_tag) { + "*** WARNING: The version in app.js [$app_tag] does not match the version in service-worker.js [$sw_tag]! ***" + "Please correct before continuing.`n" + exit + } else { + "`nVersion in app.js: $app_tag" + "Version in service-worker.js: $sw_tag`n" + } +} else { + "*** WARNING: App version is incorrectly set in service-worker.js.`nPlease correct before continuing.`n" + exit +} + +if (Test-Path $PSScriptRoot/github_token -PathType Leaf) { + $github_token = Get-Content -Raw "$PSScriptRoot/github_token" +} else { + Write-Warning "Missing file github_token! Please add it to $PSScriptRoot to run this script.`n" + $github_token = $false +} + +if ($machine_name -eq "") { + if (-Not $dryrun) { + $dryrun_check = Read-Host "Is this a dry run? [Y/N]" + $dryrun = -Not ( $dryrun_check -imatch 'n' ) + If ($dryrun) { + "[DRYRUN]: Initiating dry run..." + } + } + "" + if ($target -eq "") { + $target = Read-Host "Which implementation (ghpages or docker) do you wish to update? Enter to accept suggested [ghpages]" + } + $machine_name = Read-Host "Give the name to use for the implementation, or Enter to accept suggested name [$suggested_build]" + "" + if (-Not $machine_name) { + $machine_name = $suggested_build + $warning_message = "Please note that ""$app_tag"" will appear in the app as the appVersion. If you want to change that, press Ctrl-C`nand re-run this script entering a build number matching 9.9.9." + } elseif ($machine_name -match '^[\d.]+') { + $warning_message = "*** Please be aware that you have entered a release tag [$machine_name], and so it will be used as the appVersion of the container`n" + + "and will be visible to users. If this is NOT want you want, press Ctrl-C to abort this script, and re-run with the suggested build number." + } + if ($warning_message) { Write-Warning $warning_message } +} + +if (-Not $target) { + $target = "ghpages" +} + +if ($branch_name -eq "") { + $suggested_branch = &{ git branch --show-current } + $branch_name = Read-Host "`nGive the branch name to use of the implementation, or Enter to accept [$suggested_branch]" + if (-Not $branch_name) { $branch_name = $suggested_branch } + if ($branch_name -imatch '^pr/\d+') { + "" + Write-Warning "You appear to have indicated a PR. Please check out the underlying branch to use this script,`nor else run it again and give the branch name at the prompt.`n" + return + } +} + +"`nMachine name set to: $machine_name" +"Target set to: $target" +"Branch name set to: $branch_name" + +if (-Not $dryrun -and -Not $github_token) { + "`nSupply token to continue.`n" + exit +} + +# Set up dispatch_params object - for API see https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event +$dispatch_params = @{ + Uri = $release_uri + Method = 'POST' + Headers = @{ + 'Authorization' = "token $github_token" + 'Accept' = 'application/vnd.github.v3+json' + } + Body = @{ + 'ref' = $branch_name + 'inputs' = @{ + 'version' = $machine_name + 'target' = $target + } + } | ConvertTo-Json + ContentType = "application/json" +} + +$dispatch_f = ($dispatch_params | Format-List | Out-String); +"`nDispatch parameters:`n$dispatch_f" + +# Post to the release server +if (-Not $dryrun) { + Invoke-RestMethod @dispatch_params + "`nCheck for any error message above. An empty dispatch is normal, and indicates that the command was accepted.`n" +} else { + "[DRYRUN]: Complete.`n" +} diff --git a/scripts/create_all_packages.sh b/scripts/create_all_packages.sh index e33984ad8..224d37ad1 100755 --- a/scripts/create_all_packages.sh +++ b/scripts/create_all_packages.sh @@ -58,7 +58,8 @@ else sed -i -e "s/$VERSION_TO_REPLACE/$MAJOR_NUMERIC_VERSION/" tmp/manifest.json fi sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/manifest.webapp -sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/www/index.html +sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/service-worker.js +sed -i -e "s/$VERSION_TO_REPLACE/$VERSION/" tmp/www/js/app.js mkdir -p build rm -rf build/* diff --git a/scripts/test_duplicate_values.sh b/scripts/test_duplicate_values.sh new file mode 100644 index 000000000..a705c3868 --- /dev/null +++ b/scripts/test_duplicate_values.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# This bash script tests whether app.js and service-worker.js have the same value for appVersion and for ASSETS_CACHE. + +# Find the repo dir (it's the parent of the dir that contains this script) +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +REPO_DIR="$(dirname "$SCRIPT_DIR")" + +# Check values in files +cd $REPO_DIR +SW_VERSION="$(grep 'appVersion\s=' service-worker.js | sed -E "s/[^[:digit:]]+([^\"']+).*/\1/")" +APP_VERSION="$(grep 'params\[.appVersion' www/js/app.js | sed -E "s/[^[:digit:]]+([^\"']+).*/\1/")" +echo "service-worker.js : $SW_VERSION" +echo "app.js : $APP_VERSION" +if [ $SW_VERSION == $APP_VERSION ] ; then + echo "Both values of 'appVersion' are identical" +else + echo "ERROR! Please ensure values for 'appVersion' in app.js and service-worker.js are identical!" + exit 1 +fi +SW_ASSETS_CACHE="$( grep 'ASSETS_CACHE\s=' service-worker.js | sed -E "s/[^']+'([^']+).*/\1/")" +APP_ASSETS_CACHE="$(grep 'ASSETS_CACHE\s=' www/js/app.js | sed -E "s/[^']+'([^']+).*/\1/")" +echo "service-worker.js : $SW_ASSETS_CACHE" +echo "app.js : $APP_ASSETS_CACHE" +if [ $SW_ASSETS_CACHE == $APP_ASSETS_CACHE ] ; then + echo "Both values of 'ASSETS_CACHE' are identical" +else + echo "ERROR! Please ensure values for 'ASSETS_CACHE' in app.js and service-worker.js are identical!" + exit 1 +fi \ No newline at end of file diff --git a/scripts/test_pwa_server.sh b/scripts/test_pwa_server.sh new file mode 100644 index 000000000..6010dcecc --- /dev/null +++ b/scripts/test_pwa_server.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# This bash script tests whether PWAServer has been set correctly in app.js + +SERVER=$(grep -E '^[^/]+params.+?PWAServer.+?http' ./www/js/app.js) +echo "The PWAServer is set to $SERVER" +SERVER_COUNT=$(grep -o 'PWAServer' <<< "$SERVER" | wc -l) +echo "$SERVER_COUNT server(s) are set in app.js" +if [[ $SERVER_COUNT > 1 || ! $SERVER =~ 'kiwix.org' ]]; then + echo "WARNING: The value of params['PWAServer'] is incorrectly set in app.js!" + exit 1 +else + echo "PWAServer is correctly set in app.js" +fi diff --git a/service-worker.js b/service-worker.js index 0b19654ec..6271db7b8 100644 --- a/service-worker.js +++ b/service-worker.js @@ -23,22 +23,40 @@ */ 'use strict'; +/** + * App version number - ENSURE IT MATCHES VALUE IN app.js + * DEV: Changing this will cause the browser to recognize that the Service Worker has changed, and it will + * download and install a new copy; we have to hard code this here because it is needed before any other file + * is cached in APP_CACHE + */ +const appVersion = '3.3-WIP'; + /** * The name of the Cache API cache in which assets defined in regexpCachedContentTypes will be stored - * The value is defined in app.js and will be passed to Service Worker on initialization (to avoid duplication) + * The value is sometimes needed here before it can be passed from app.js, so we have to duplicate it * @type {String} */ -var CACHE_NAME; +// DEV: Ensure this matches the name defined in app.js +const ASSETS_CACHE = 'kiwixjs-assetsCache'; /** - * A global Boolean that governs whether CACHE_NAME will be used + * The name of the application cache to use for caching online code so that it can be used offline + * The cache name is made up of the prefix below and the appVersion: this is necessary so that when + * the app is updated, a new cache is created. The new cache will start being used after the user + * restarts the app, when we will also delete the old cache. + * @type {String} + */ +const APP_CACHE = 'kiwixjs-appCache-' + appVersion; + +/** + * A global Boolean that governs whether ASSETS_CACHE will be used * Caching is on by default but can be turned off by the user in Configuration * @type {Boolean} */ var useCache = true; /** - * A regular expression that matches the Content-Types of assets that may be stored in CACHE_NAME + * A regular expression that matches the Content-Types of assets that may be stored in ASSETS_CACHE * Add any further Content-Types you wish to cache to the regexp, separated by '|' * @type {RegExp} */ @@ -50,63 +68,156 @@ var regexpCachedContentTypes = /text\/css|text\/javascript|application\/javascri * 'example-extension' is included to show how to add another schema if necessary * @type {RegExp} */ -var regexpExcludedURLSchema = /^(?:chrome-extension|example-extension):/i; +var regexpExcludedURLSchema = /^(?:file|chrome-extension|example-extension):/i; /** * Pattern for ZIM file namespace: see https://wiki.openzim.org/wiki/ZIM_file_format#Namespaces * In our case, there is also the ZIM file name used as a prefix in the URL * @type {RegExp} */ -var regexpZIMUrlWithNamespace = /(?:^|\/)([^/]+\/)([-ABCIJMUVWX])\/(.+)/; +const regexpZIMUrlWithNamespace = /(?:^|\/)([^/]+\/)([-ABCIJMUVWX])\/(.+)/; -self.addEventListener('install', function (event) { - event.waitUntil(self.skipWaiting()); +/** + * The list of files that the app needs in order to run entirely from offline code + */ +let precacheFiles = [ + ".", // This caches the redirect to www/index.html, in case a user launches the app from its root directory + "manifest.json", + "service-worker.js", + "www/css/app.css", + "www/css/bootstrap.css", + "www/css/kiwixJS_invert.css", + "www/css/kiwixJS_mwInvert.css", + "www/css/transition.css", + "www/img/icons/kiwix-256.png", + "www/img/icons/kiwix-32.png", + "www/img/icons/kiwix-60.png", + "www/img/spinner.gif", + "www/img/Icon_External_Link.png", + "www/index.html", + "www/article.html", + "www/main.html", + "www/js/app.js", + "www/js/init.js", + "www/js/lib/abstractFilesystemAccess.js", + "www/js/lib/arrayFromPolyfill.js", + "www/js/lib/bootstrap.bundle.js", + "www/js/lib/filecache.js", + "www/js/lib/jquery-3.2.1.slim.js", + "www/js/lib/promisePolyfill.js", + "www/js/lib/require.js", + "www/js/lib/settingsStore.js", + "www/js/lib/uiUtil.js", + "www/js/lib/utf8.js", + "www/js/lib/util.js", + "www/js/lib/xzdec_wrapper.js", + "www/js/lib/zstddec_wrapper.js", + "www/js/lib/zimArchive.js", + "www/js/lib/zimArchiveLoader.js", + "www/js/lib/zimDirEntry.js", + "www/js/lib/zimfile.js", + "www/js/lib/fontawesome/fontawesome.js", + "www/js/lib/fontawesome/solid.js", + "www/js/lib/xzdec-asm.js", + "www/js/lib/zstddec-asm.js", + "www/js/lib/xzdec-wasm.js", + "www/js/lib/xzdec-wasm.wasm", + "www/js/lib/zstddec-wasm.js", + "www/js/lib/zstddec-wasm.wasm" +]; + +// Process install event +self.addEventListener("install", function (event) { + console.debug("[SW] Install Event processing"); + // DEV: We can't skip waiting because too many params are loaded at an early stage from the old file before the new one can activate... + // self.skipWaiting(); + // We try to circumvent the browser's cache by adding a header to the Request, and it ensures all files are explicitly versioned + var requests = precacheFiles.map(function (urlPath) { + return new Request(urlPath + '?v' + appVersion, { cache: 'no-cache' }); + }); + if (!regexpExcludedURLSchema.test(requests[0].url)) event.waitUntil( + caches.open(APP_CACHE).then(function (cache) { + return Promise.all( + requests.map(function (request) { + return fetch(request).then(function (response) { + // Fail on 404, 500 etc + if (!response.ok) throw Error('Could not fetch ' + request.url); + return cache.put(request.url.replace(/\?v[^?/]+$/, ''), response); + }).catch(function (err) { + console.error('There was an error pre-caching files', err); + }); + }) + ); + }) + ); }); +// Allow sw to control current page self.addEventListener('activate', function (event) { // "Claiming" the ServiceWorker is necessary to make it work right away, // without the need to reload the page. // See https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim event.waitUntil(self.clients.claim()); + console.debug('[SW] Claiming clients for current page'); + // Check all the cache keys, and delete any old caches + event.waitUntil( + caches.keys().then(function (keyList) { + return Promise.all(keyList.map(function (key) { + console.debug('[SW] Current cache key is ' + key); + if (key !== APP_CACHE && key !== ASSETS_CACHE) { + console.debug('[SW] App updated to version ' + appVersion + ': deleting old cache'); + return caches.delete(key); + } + })); + }) + ); }); -var outgoingMessagePort = null; -var fetchCaptureEnabled = false; +let outgoingMessagePort = null; +let fetchCaptureEnabled = false; self.addEventListener('fetch', function (event) { - if (fetchCaptureEnabled && - regexpZIMUrlWithNamespace.test(event.request.url) && - event.request.method === "GET") { - - // The ServiceWorker will handle this request either from CACHE_NAME or from app.js - - event.respondWith( - // First see if the content is in the cache - fromCache(event.request).then( - function (response) { - // The response was found in the cache so we respond with it + // Only cache GET requests + if (event.request.method !== "GET") return; + // Remove any querystring before requesting from the cache + var rqUrl = event.request.url.replace(/\?[^?]+$/i, ''); + // Select cache depending on request format + var cache = /\.zim\//i.test(rqUrl) ? ASSETS_CACHE : APP_CACHE; + if (cache === ASSETS_CACHE && !fetchCaptureEnabled) return; + event.respondWith( + // First see if the content is in the cache + fromCache(cache, rqUrl).then(function (response) { + // The response was found in the cache so we respond with it + return response; + }, function () { + // The response was not found in the cache so we look for it in the ZIM + // and add it to the cache if it is an asset type (css or js) + if (cache === ASSETS_CACHE && regexpZIMUrlWithNamespace.test(rqUrl)) { + return fetchRequestFromZIM(event).then(function (response) { + // Add css or js assets to ASSETS_CACHE (or update their cache entries) unless the URL schema is not supported + if (regexpCachedContentTypes.test(response.headers.get('Content-Type')) && + !regexpExcludedURLSchema.test(event.request.url)) { + event.waitUntil(updateCache(ASSETS_CACHE, event.request, response.clone())); + } return response; - }, - function () { - // The response was not found in the cache so we look for it in the ZIM - // and add it to the cache if it is an asset type (css or js) - return fetchRequestFromZIM(event).then(function (response) { - // Add css or js assets to CACHE_NAME (or update their cache entries) unless the URL schema is not supported - if (regexpCachedContentTypes.test(response.headers.get('Content-Type')) && - !regexpExcludedURLSchema.test(event.request.url)) { - event.waitUntil(updateCache(event.request, response.clone())); - } - return response; - }).catch(function (msgPortData, title) { - console.error('Invalid message received from app.js for ' + title, msgPortData); - return msgPortData; - }); - } - ) - ); - } - // If event.respondWith() isn't called because this wasn't a request that we want to handle, - // then the default request/response behavior will automatically be used. + }).catch(function (msgPortData, title) { + console.error('Invalid message received from app.js for ' + title, msgPortData); + return msgPortData; + }); + } else { + // It's not an asset, or it doesn't match a ZIM URL pattern, so we should fetch it with Fetch API + return fetch(event.request).then(function (response) { + // If request was successful, add or update it in the cache, but be careful not to cache the ZIM archive itself! + if (!regexpExcludedURLSchema.test(rqUrl) && !/\.zim\w{0,2}$/i.test(rqUrl)) { + event.waitUntil(updateCache(APP_CACHE, event.request, response.clone())); + } + return response; + }).catch(function (error) { + console.debug("[SW] Network request failed and no cache.", error); + }); + } + }) + ); }); self.addEventListener('message', function (event) { @@ -123,13 +234,15 @@ self.addEventListener('message', function (event) { if (event.data.action.useCache) { // Turns caching on or off (a string value of 'on' turns it on, any other string turns it off) useCache = event.data.action.useCache === 'on'; - if (useCache) CACHE_NAME = event.data.cacheName; - console.log('[SW] Caching was turned ' + event.data.action.useCache); + console.debug('[SW] Caching was turned ' + event.data.action.useCache); + } + if (event.data.action === 'getCacheNames') { + event.ports[0].postMessage({ 'app': APP_CACHE, 'assets': ASSETS_CACHE }); } if (event.data.action.checkCache) { // Checks and returns the caching strategy: checkCache key should contain a sample URL string to test testCacheAndCountAssets(event.data.action.checkCache).then(function (cacheArr) { - event.ports[0].postMessage({ 'type': cacheArr[0], 'description': cacheArr[1], 'count': cacheArr[2] }); + event.ports[0].postMessage({ type: cacheArr[0], name: cacheArr[1], description: cacheArr[2], count: cacheArr[3] }); }); } } @@ -208,51 +321,53 @@ function removeUrlParameters(url) { } /** - * Looks up a Request in CACHE_NAME and returns a Promise for the matched Response - * @param {Request} request The Request to fulfill from CACHE_NAME + * Looks up a Request in a cache and returns a Promise for the matched Response + * @param {String} cache The name of the cache to look in + * @param {String} requestUrl The Request URL to fulfill from cache * @returns {Promise} A Promise for the cached Response, or rejects with strings 'disabled' or 'no-match' */ -function fromCache(request) { +function fromCache(cache, requestUrl) { // Prevents use of Cache API if user has disabled it - if (!useCache) return Promise.reject('disabled'); - return caches.open(CACHE_NAME).then(function (cache) { - return cache.match(request).then(function (matching) { + if (!useCache && cache === ASSETS_CACHE) return Promise.reject('disabled'); + return caches.open(cache).then(function (cacheObj) { + return cacheObj.match(requestUrl).then(function (matching) { if (!matching || matching.status === 404) { return Promise.reject('no-match'); } - console.log('[SW] Supplying ' + request.url + ' from ' + CACHE_NAME + '...'); + console.debug('[SW] Supplying ' + requestUrl + ' from ' + cache + '...'); return matching; }); }); } /** - * Stores or updates in CACHE_NAME the given Request/Response pair + * Stores or updates in a cache the given Request/Response pair + * @param {String} cache The name of the cache to open * @param {Request} request The original Request object * @param {Response} response The Response received from the server/ZIM * @returns {Promise} A Promise for the update action */ -function updateCache(request, response) { +function updateCache(cache, request, response) { // Prevents use of Cache API if user has disabled it - if (!useCache) return Promise.resolve(); - return caches.open(CACHE_NAME).then(function (cache) { - console.log('[SW] Adding ' + request.url + ' to ' + CACHE_NAME + '...'); - return cache.put(request, response); + if (!useCache && cache === ASSETS_CACHE) return Promise.resolve(); + return caches.open(cache).then(function (cacheObj) { + console.debug('[SW] Adding ' + request.url + ' to ' + cache + '...'); + return cacheObj.put(request, response); }); } /** * Tests the caching strategy available to this app and if it is Cache API, count the - * number of assets in CACHE_NAME + * number of assets in ASSETS_CACHE * @param {String} url A URL to test against excludedURLSchema * @returns {Promise} A Promise for an array of format [cacheType, cacheDescription, assetCount] */ function testCacheAndCountAssets(url) { - if (regexpExcludedURLSchema.test(url)) return Promise.resolve(['custom', 'Custom', '-']); - if (!useCache) return Promise.resolve(['none', 'None', 0]); - return caches.open(CACHE_NAME).then(function (cache) { + if (regexpExcludedURLSchema.test(url)) return Promise.resolve(['custom', 'custom', 'Custom', '-']); + if (!useCache) return Promise.resolve(['none', 'none', 'None', 0]); + return caches.open(ASSETS_CACHE).then(function (cache) { return cache.keys().then(function (keys) { - return ['cacheAPI', 'Cache API', keys.length]; + return ['cacheAPI', ASSETS_CACHE, 'Cache API', keys.length]; }).catch(function(err) { return err; }); diff --git a/www/index.html b/www/index.html index 302b3b1ca..daced0ce7 100644 --- a/www/index.html +++ b/www/index.html @@ -55,7 +55,7 @@