From 9f2437ad0d89a2b5c079431bf262578ded303fcc Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Mon, 17 Nov 2014 06:17:08 -0500 Subject: [PATCH 01/20] Register serviceworker --- content/src/worker.js | 1 + content/welcome.html | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 content/src/worker.js diff --git a/content/src/worker.js b/content/src/worker.js new file mode 100644 index 00000000..cbc570e1 --- /dev/null +++ b/content/src/worker.js @@ -0,0 +1 @@ +console.log('ServiceWorker is running!'); diff --git a/content/welcome.html b/content/welcome.html index 90c9a4c8..3c2d7c51 100644 --- a/content/welcome.html +++ b/content/welcome.html @@ -371,4 +371,11 @@

Resources

ga('send', 'pageview'); }); + From 425decdeb41268ec934d8a0c9849fc494e06b56e Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Tue, 18 Nov 2014 11:03:28 -0500 Subject: [PATCH 02/20] Log each event --- content/src/worker.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/src/worker.js b/content/src/worker.js index cbc570e1..da135441 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -1 +1,5 @@ console.log('ServiceWorker is running!'); + +self.addEventListener('fetch', function(event) { + console.log(event.request); +}); From d96c111cbe4453a9c232cc5f331a35cee783c56f Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Tue, 18 Nov 2014 12:15:13 -0500 Subject: [PATCH 03/20] ServiceWorker that caches everything and reports on the cache Visit https://pencilcode.net.dev/stats to see the stats page. --- content/src/worker.js | 79 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/content/src/worker.js b/content/src/worker.js index da135441..794af9b9 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -1,5 +1,78 @@ console.log('ServiceWorker is running!'); -self.addEventListener('fetch', function(event) { - console.log(event.request); -}); +var cache_hits = 0; +var cache_misses = 0; +var cache_errors = 0; + +function onactivate(event) { + console.log("Activated"); + var p = self.caches.open('main') + .then(function(cache) { + console.log("Inital cache open succeeded"); + }); + event.waitUntil(p); +} + +function lookupRequestOnCache(request) { + var my_cache = null; + var p = self.caches.open('main') + .then(function(cache) { + my_cache = cache; + return cache.match(request); + }) + .then(function(response) { + if (response === undefined) { + return fetch(request) + .then(function(response) { + console.log('Fetch succeeded for ' + request.url); + ++cache_misses; + return my_cache.put(request, response) + .then(function() { + return response; + }); + }); + } else { + ++cache_hits; + console.log('Cache hit for ' + request.url); + return response; + } + }) + .catch(function(e) { + ++cache_errors; + console.log('Caught ' + e + ' for ' + request.url); + throw e; + }); + return p; +} + +function returnStatsPage() { + var p = self.caches.open('main') + .then(function(cache) { + return cache.keys(); + }) + .then(function(keys) { + var body = 'Cache hits = ' + cache_hits + '\n'; + body += 'Cache misses = ' + cache_misses + '\n'; + body += 'Cache errors = ' + cache_errors + '\n'; + body += 'Keys:\n' + keys.map(function(response) { + return response.url; + }).sort().join('\n'); + return new Response(body, { + headers: { 'Content-Type': 'text/plain' } + }); + }); + return p; +} + +function onfetch(event) { + console.log(event.request.url); + var myurl = new URL(event.request.url); + if (myurl.pathname === '/stats') { + event.respondWith(returnStatsPage()); + } + event.respondWith(lookupRequestOnCache(event.request)); +} + +self.addEventListener('activate', onactivate); + +self.addEventListener('fetch', onfetch); From 87e77a566efbe2715b687d05b755c8998536e570 Mon Sep 17 00:00:00 2001 From: David Bau Date: Tue, 18 Nov 2014 13:10:31 -0500 Subject: [PATCH 04/20] Add service worker to /edit/ urls. --- .gitignore | 1 + Gruntfile.js | 3 ++- content/blankframe.html | 1 + content/src/storage.js | 10 ++++++++++ content/src/view.js | 2 +- 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 content/blankframe.html diff --git a/.gitignore b/.gitignore index 0e0719b6..c56b5fa5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ content/editor.js content/framed.html content/turtlebits.js content/welcome.css +content/worker.js diff --git a/Gruntfile.js b/Gruntfile.js index b6c4d7d2..aecbd626 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -107,7 +107,8 @@ module.exports = function(grunt) { flatten: true, src: [ 'content/src/editor.html', - 'content/src/framed.html' + 'content/src/framed.html', + 'content/src/worker.js' ], dest: 'content' } ] diff --git a/content/blankframe.html b/content/blankframe.html new file mode 100644 index 00000000..c50eddd4 --- /dev/null +++ b/content/blankframe.html @@ -0,0 +1 @@ + diff --git a/content/src/storage.js b/content/src/storage.js index 0132da9c..d9a4efe4 100644 --- a/content/src/storage.js +++ b/content/src/storage.js @@ -5,6 +5,16 @@ define(['jquery', 'see', 'filetype'], function($, see, filetype) { +var sw = null; +function installServiceWorker() { + navigator.serviceWorker.register('/worker.js').then(function(reg) { + console.log('happy', reg); + }, function(err) { + console.log('sad', err); + }); +} +installServiceWorker(); + eval(see.scope('storage')); function hasBackup(filename) { try { diff --git a/content/src/view.js b/content/src/view.js index d4b06220..6343307f 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -1087,7 +1087,7 @@ function setPaneRunHtml( p.html(''); var iframe = $('').appendTo(p); // Destroy and create new iframe. - iframe.attr('src', 'about:blank'); + iframe.attr('src', '/blankframe.html'); var framewin = iframe[0].contentWindow; var framedoc = framewin.document; framedoc.open(); From 9c92237eaad401609dd0869ba0963c9d841aa75e Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Tue, 18 Nov 2014 13:18:37 -0500 Subject: [PATCH 05/20] Detect serviceWorker feature when registering. --- content/welcome.html | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/content/welcome.html b/content/welcome.html index 3c2d7c51..44075171 100644 --- a/content/welcome.html +++ b/content/welcome.html @@ -372,10 +372,12 @@

Resources

}); From 306243d6b5a7f13ecdfaddda542926f0dfce4486 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Tue, 18 Nov 2014 13:33:16 -0500 Subject: [PATCH 06/20] Add a Kill cache button --- content/src/worker.js | 46 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/content/src/worker.js b/content/src/worker.js index 794af9b9..5410c9d9 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -51,24 +51,56 @@ function returnStatsPage() { return cache.keys(); }) .then(function(keys) { - var body = 'Cache hits = ' + cache_hits + '\n'; - body += 'Cache misses = ' + cache_misses + '\n'; - body += 'Cache errors = ' + cache_errors + '\n'; - body += 'Keys:\n' + keys.map(function(response) { - return response.url; - }).sort().join('\n'); + var key_list = keys.map(function(response) { + return response.url; + }).sort().join('
'); + var body = '\ + \ + \ +

Cache hits = ' + cache_hits + '

\ +

Cache misses = ' + cache_misses + '

\ +

Cache errors = ' + cache_errors + '

\ +

\ +

Keys :

\ +

' + key_list + '\ +

\ + \ + \ + '; return new Response(body, { - headers: { 'Content-Type': 'text/plain' } + headers: { 'Content-Type': 'text/html' } }); }); return p; } +function killCache() { + var p = self.caches.delete('main') + .then(function() { + return new Response('OK'); + }); + return p; +} + function onfetch(event) { console.log(event.request.url); var myurl = new URL(event.request.url); if (myurl.pathname === '/stats') { event.respondWith(returnStatsPage()); + return; + } + if (myurl.pathname === '/killcache') { + event.respondWith(killCache()); + return; } event.respondWith(lookupRequestOnCache(event.request)); } From 75ce18c8e8454e94a9ee2fef06669b2fb4278f05 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Tue, 18 Nov 2014 14:02:56 -0500 Subject: [PATCH 07/20] Add blacklisted URLs --- content/src/worker.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/content/src/worker.js b/content/src/worker.js index 5410c9d9..bf9d8a75 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -91,15 +91,32 @@ function killCache() { return p; } +var blacklisted_prefixes = [ + '/load', '/save', '/log' + ]; + function onfetch(event) { console.log(event.request.url); var myurl = new URL(event.request.url); - if (myurl.pathname === '/stats') { - event.respondWith(returnStatsPage()); - return; + var scopeurl = new URL(self.scope); + if (myurl.host === myurl.host) { + if (myurl.pathname === '/stats') { + event.respondWith(returnStatsPage()); + return; + } + if (myurl.pathname === '/killcache') { + event.respondWith(killCache()); + return; + } + if (blacklisted_prefixes.some(function(prefix) { + return myurl.pathname.indexOf(prefix) == 0; + })) { + event.default(); + return; + } } - if (myurl.pathname === '/killcache') { - event.respondWith(killCache()); + if (myurl.host === 'www.google-analytics.com') { + event.default(); return; } event.respondWith(lookupRequestOnCache(event.request)); From 862787c292897578cb4b18e63e5ac2ae0e0a4930 Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Tue, 18 Nov 2014 14:12:10 -0500 Subject: [PATCH 08/20] Use relative URLs for editor.html --- content/src/editor.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/src/editor.html b/content/src/editor.html index ed9879b4..b620b43b 100644 --- a/content/src/editor.html +++ b/content/src/editor.html @@ -10,9 +10,9 @@ -/editor.css"> -/lib/tooltipster/css/tooltipster.css"> -/lib/droplet.css"> + + +
From dd3ffaa34be5363869e9eaaeb5858504fb870cc4 Mon Sep 17 00:00:00 2001 From: Josh Karlin Date: Tue, 18 Nov 2014 14:29:40 -0500 Subject: [PATCH 09/20] Get the online version in the background --- content/image/art.png | Bin 4107 -> 4104 bytes content/src/worker.js | 8 ++++++++ 2 files changed, 8 insertions(+) diff --git a/content/image/art.png b/content/image/art.png index 91839cb208452357b731139c75bab97267167139..6e2eb83ed26f40fd6cd37d324e8b1d0626d25500 100644 GIT binary patch literal 4104 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 JPDHLkV1m Date: Tue, 18 Nov 2014 14:34:33 -0500 Subject: [PATCH 10/20] sorry art --- content/image/art.png | Bin 4104 -> 4107 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/content/image/art.png b/content/image/art.png index 6e2eb83ed26f40fd6cd37d324e8b1d0626d25500..91839cb208452357b731139c75bab97267167139 100644 GIT binary patch literal 4107 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 JPDHLkV1m|D^_ww@lRz|vCuzLs)$;-`! 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 Date: Tue, 18 Nov 2014 14:44:04 -0500 Subject: [PATCH 11/20] Try to load serviceworker in-frame. --- content/src/debug.js | 3 ++- content/src/showturtle.js | 4 ++++ content/src/view.js | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/content/src/debug.js b/content/src/debug.js index 78ae3d3d..b9077bd5 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -104,7 +104,8 @@ var debug = window.ide = { }, setEditorText: function(text) { view.changePaneEditorText(view.paneid('left'), text); - } + }, + serviceWorker: '/worker.js' }; ////////////////////////////////////////////////////////////////////// diff --git a/content/src/showturtle.js b/content/src/showturtle.js index 9a224fce..b26dd6b1 100644 --- a/content/src/showturtle.js +++ b/content/src/showturtle.js @@ -26,6 +26,10 @@ $.isFunction(ww.parent.ide.getEditorText)) { ww.ide = ww.parent.ide; } + // Now try to register a service worker if possible + if (ww.ide && ww.ide.serviceWorker) { + navigator.serviceWorker.register(ww.ide.serviceWorker); + } } catch (e) {} ww._start_ide_ = function(pump) { if (ww.see) ww.see.init(pump); diff --git a/content/src/view.js b/content/src/view.js index 6343307f..bce14f4c 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -1085,9 +1085,8 @@ function setPaneRunHtml( var p = $(this).find('.preview'); if (p.data('session') == session) { p.html(''); - var iframe = $('').appendTo(p); + var iframe = $('').appendTo(p); // Destroy and create new iframe. - iframe.attr('src', '/blankframe.html'); var framewin = iframe[0].contentWindow; var framedoc = framewin.document; framedoc.open(); From 347ba0c3fbdbedfc2cdd514dda89f4e3931b64f1 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Tue, 18 Nov 2014 15:20:41 -0500 Subject: [PATCH 12/20] Remove unused code --- server/load.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/server/load.js b/server/load.js index 9fee422e..00efed17 100644 --- a/server/load.js +++ b/server/load.js @@ -7,16 +7,9 @@ var filemeta = require('./filemeta'); exports.handleLoad = function(req, res, app, format) { var filename = req.param('file', utils.filenameFromUri(req)); - var callback = req.param('callback', null); - var tail = req.param('tail', null); var user = res.locals.owner; var origfilename = filename; - tail = parseInt(tail); - if (Number.isNaN(tail)) { - tail = null; - } - if (filename == null) { filename = ''; } From e9e658fa4fa0a2c5abfc3bb09c73038ea276062b Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Tue, 18 Nov 2014 15:20:53 -0500 Subject: [PATCH 13/20] Add TODO --- server/save.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/save.js b/server/save.js index 6a925217..5f5a431f 100644 --- a/server/save.js +++ b/server/save.js @@ -30,6 +30,7 @@ exports.handleSave = function(req, res, app) { conditional: conditional}); */ + // TODO: Remove file after validation below. try { fsExtra.removeSync(utils.getRootCacheName(app, res)); } From 4277462d8cb793ec8604f2f2b722efb22cea8250 Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Tue, 18 Nov 2014 15:43:34 -0500 Subject: [PATCH 14/20] /edit/ loads from common editor.html file. --- content/src/worker.js | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/content/src/worker.js b/content/src/worker.js index 794af9b9..f41f0e32 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -64,15 +64,45 @@ function returnStatsPage() { return p; } +function serveEditPage(request, filename) { + var p = self.caches.open('main') + .then(function(cache) { + return cache.match('/editor.html'); + }).then(function(response) { + if (response) { + // Replace some of the text. + console.log('serving editor.html'); + return response.text().then(function(text) { + var sub_text = text.replace('', filename); + var b = new Blob([sub_text], {'type': 'text/html'}); + return new Response(b); + }); + } else { + // Just go back to the origin server if possible. + return fetch(request); + } + }); + return p; +} + function onfetch(event) { - console.log(event.request.url); var myurl = new URL(event.request.url); if (myurl.pathname === '/stats') { event.respondWith(returnStatsPage()); + } else if (myurl.pathname.indexOf('/edit/') == 0) { + event.respondWith(serveEditPage(event.request, myurl.pathname.substr('/edit'.length))); + } else { + event.respondWith(lookupRequestOnCache(event.request)); } - event.respondWith(lookupRequestOnCache(event.request)); } +function oninstall(event) { + console.log('oninstall'); + event.waitUntil(lookupRequestOnCache('/editor.html')); +} + +self.addEventListener('install', oninstall); + self.addEventListener('activate', onactivate); self.addEventListener('fetch', onfetch); From eeaee35a29d911890282efec1c61aeeb2034e797 Mon Sep 17 00:00:00 2001 From: David Bau Date: Tue, 18 Nov 2014 15:52:05 -0500 Subject: [PATCH 15/20] Comment out a crashing line. --- content/src/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/src/debug.js b/content/src/debug.js index b9077bd5..c07f13f0 100644 --- a/content/src/debug.js +++ b/content/src/debug.js @@ -105,7 +105,7 @@ var debug = window.ide = { setEditorText: function(text) { view.changePaneEditorText(view.paneid('left'), text); }, - serviceWorker: '/worker.js' + serviceWorker: false // '/worker.js' }; ////////////////////////////////////////////////////////////////////// From 88afc91734a9450bbeac6706ccaa5fce94c6f6f8 Mon Sep 17 00:00:00 2001 From: David Bau Date: Tue, 18 Nov 2014 16:15:07 -0500 Subject: [PATCH 16/20] Remove blankframe. --- content/blankframe.html | 1 - content/src/view.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 content/blankframe.html diff --git a/content/blankframe.html b/content/blankframe.html deleted file mode 100644 index c50eddd4..00000000 --- a/content/blankframe.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/content/src/view.js b/content/src/view.js index bce14f4c..bcc8e6e0 100644 --- a/content/src/view.js +++ b/content/src/view.js @@ -1085,7 +1085,7 @@ function setPaneRunHtml( var p = $(this).find('.preview'); if (p.data('session') == session) { p.html(''); - var iframe = $('').appendTo(p); + var iframe = $('').appendTo(p); // Destroy and create new iframe. var framewin = iframe[0].contentWindow; var framedoc = framewin.document; From 8bab0cf51272bd3f54e7d41a1fc33dc367ea6b5a Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Tue, 18 Nov 2014 17:48:05 -0500 Subject: [PATCH 17/20] Put back load-from-cache as default fetch behavior. Remove event.default() calls as these seem not to exist on recent canary. --- content/src/worker.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/src/worker.js b/content/src/worker.js index ae2bed14..4178a14c 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -143,14 +143,13 @@ function onfetch(event) { if (blacklisted_prefixes.some(function(prefix) { return myurl.pathname.indexOf(prefix) == 0; })) { - event.default(); return; } } if (myurl.host === 'www.google-analytics.com') { - event.default(); return; } + event.respondWith(lookupRequestOnCache(event.request)); } function oninstall(event) { From 80b0699051afff8e6b51eea027eeffac4d369770 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Tue, 18 Nov 2014 15:34:27 -0500 Subject: [PATCH 18/20] Caching user data and /load fallback. Also includes improvements to /stats --- .gitignore | 1 + Gruntfile.js | 3 +- content/src/worker-stats.html | 104 +++++++++++ content/src/worker.js | 342 ++++++++++++++++++++++++++-------- server/save.js | 1 - 5 files changed, 373 insertions(+), 78 deletions(-) create mode 100644 content/src/worker-stats.html diff --git a/.gitignore b/.gitignore index c56b5fa5..19af6383 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ content/framed.html content/turtlebits.js content/welcome.css content/worker.js +content/worker-stats.html diff --git a/Gruntfile.js b/Gruntfile.js index aecbd626..47de3afa 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -108,7 +108,8 @@ module.exports = function(grunt) { src: [ 'content/src/editor.html', 'content/src/framed.html', - 'content/src/worker.js' + 'content/src/worker.js', + 'content/src/worker-stats.html' ], dest: 'content' } ] diff --git a/content/src/worker-stats.html b/content/src/worker-stats.html new file mode 100644 index 00000000..3c8e8720 --- /dev/null +++ b/content/src/worker-stats.html @@ -0,0 +1,104 @@ + + + + ServiceWorker stats for ${worker_scope} + + + +

ServiceWorker stats for PencilCode

+

Cache hits: Loading...

+

Cache misses: Loading...

+

Cache errors: Loading...

+

+

Recent activity

+
+
+

Main cache keys

+
+
+

User cache keys

+
+
+ + diff --git a/content/src/worker.js b/content/src/worker.js index 4178a14c..3b49346a 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -1,31 +1,55 @@ -console.log('ServiceWorker is running!'); +var internal_cache_name = 'internal'; +var main_cache_name = 'main'; +var user_cache_name = 'user'; +// Some stats for this service worker session. var cache_hits = 0; var cache_misses = 0; var cache_errors = 0; +var cache_activity = []; +var max_cache_activity = 30; +var CACHE_HIT = 'hit'; +var CACHE_MISS = 'miss'; +var CACHE_UPDATED = 'updated'; +var CACHE_FALLBACK = 'fallback'; +var CACHE_SKIPPED = 'skip'; -function onactivate(event) { - console.log("Activated"); - var p = self.caches.open('main') - .then(function(cache) { - console.log("Inital cache open succeeded"); - }); - event.waitUntil(p); +function statAddRequest(url) { + if (cache_activity.some(function(value) { + if (value[0] === url) { + return true; + } + })) { + return; + } + if (cache_activity > max_cache_activity) { + cache_activity.shift(); + } + + cache_activity.push([url]); +} + +function statAddResult(url, result) { + cache_activity.some(function(value) { + if (value[0] === url) { + value.push(result); + } + }); } -function lookupRequestOnCache(request) { +function getCachedResponse(request) { var my_cache = null; - var p = self.caches.open('main') + return self.caches.open(main_cache_name) .then(function(cache) { my_cache = cache; return cache.match(request); }) .then(function(response) { if (response === undefined) { + console.log('Cache miss for ' + request.url); + ++cache_misses; return fetch(request) .then(function(response) { - console.log('Fetch succeeded for ' + request.url); - ++cache_misses; return my_cache.put(request, response) .then(function() { return response; @@ -33,14 +57,14 @@ function lookupRequestOnCache(request) { }); } else { ++cache_hits; - console.log('Cache hit for ' + request.url); + statAddResult(request.url, CACHE_HIT); - // Return the cached response but update the cache with the online - // version in the background. - fetch(request).then(function(response) { - if (response) - my_cache.put(request, response); - }); + // Return the cached response but update the cache with the online + // version in the background. + fetch(request).then(function(response) { + if (response) + my_cache.put(request, response); + }); return response; } @@ -50,58 +74,203 @@ function lookupRequestOnCache(request) { console.log('Caught ' + e + ' for ' + request.url); throw e; }); - return p; } -function returnStatsPage() { - var p = self.caches.open('main') +function preloadInternalPages() { + var internal_pages = ['worker-stats.html']; + return Promise.all(internal_pages.map(function(page) { + return fetch(page) + .then(function(response) { + return self.caches.open(internal_cache_name) + .then(function(cache) { + return cache.put(page, response); + }); + }); + })); +} + +function handleStatsRequest(url) { + if (url.pathname === '/stats/killcache') { + return killCache(); + } + if (url.pathname === '/stats/get') { + return getStats(); + } + return self.caches.open(internal_cache_name) + .then(function(cache) { + return cache.match('worker-stats.html'); + }); +} + +function getStats() { + var main_cache_entries = null; + var user_cache_entries = null; + + return self.caches.open(main_cache_name) + .then(function(cache) { + return cache.keys(); + }) + .then(function(keys) { + main_cache_entries = keys.map(function(request) { + return request.url; + }); + }) + .then(function() { + return self.caches.open(user_cache_name); + }) .then(function(cache) { return cache.keys(); }) .then(function(keys) { - var key_list = keys.map(function(response) { - return response.url; - }).sort().join('
'); - var body = '\ - \ - \ -

Cache hits = ' + cache_hits + '

\ -

Cache misses = ' + cache_misses + '

\ -

Cache errors = ' + cache_errors + '

\ -

\ -

Keys :

\ -

' + key_list + '\ -

\ - \ - \ - '; - return new Response(body, { - headers: { 'Content-Type': 'text/html' } + user_cache_entries = keys.map(function(request) { + return request.url; }); + }) + .then(function() { + var data = { + worker_scope: self.scope, + cache_hits: cache_hits, + cache_misses: cache_misses, + cache_errors: cache_errors, + main_cache_keys: main_cache_entries, + user_cache_keys: user_cache_entries, + recent_requests: cache_activity + }; + var blob = new Blob([JSON.stringify(data)], { type: 'text/javascript' }); + return new Response(blob); }); - return p; } function killCache() { - var p = self.caches.delete('main') + return Promise.all([ + self.caches.delete(main_cache_name), + self.caches.delete(user_cache_name) + ]) .then(function() { return new Response('OK'); }); +} + +function appendPath(base, name) { + if (base === '') { + return name; + } + return base + '/' + name; +} + +function cachePath(filename) { + return '/raw/' + filename; +} + +function fetchUserFiles(path, list) { + var p = Promise.all(list.map(function(entry) { + var entry_path = appendPath(path, entry.name); + if (entry.mode === 'drwx') { + return fetchUserDirectory(entry_path); + } else { + return fetch('/load?file=' + entry_path) + .then(function(response) { + return self.caches.open(user_cache_name) + .then(function(cache) { + console.log("Adding user file: " + entry_path); + return cache.put(cachePath(entry_path), response); + }); + }); + } + })); return p; } -var blacklisted_prefixes = [ - '/load', '/save', '/log' - ]; +function fetchUserDirectory(path) { + path = path || ''; + // path must be a directory. + var p = fetch('/load?file=' + path) + .then(function(response) { + return self.caches.open(user_cache_name) + .then(function(cache) { + console.log("Adding user directory : " + path); + return cache.put(cachePath(path), response.clone()); + }) + .then(function() { + // response should be json. + return response.json(); + }); + }) + .then(function(data) { + var list = data.list; + return fetchUserFiles(path, list); + }); + return p; +} + +function getSearchParams(search) { + var params = {}; + if (search.length === 0 || search[0] !== '?') { + return {}; + } + search.substr(1).split('&').forEach(function(pair) { + var kv = pair.split('='); + if (kv.length === 2) { + params[kv[0]] = decodeURIComponent(kv[1]); + } + }); + return params; +} + +function handleLoadRequest(request, pathname) { + var url = new URL(request.url); + var params = getSearchParams(url.search); + var filename = params.file || (pathname.length > 1 && pathname.substr(1)) || ''; + + console.log('Load for ' + filename + ' with URL ' + request.url); + + return fetch(request) + .then(function(response) { + var response_clone = response.clone(); + return self.caches.open(user_cache_name) + .then(function(cache) { + statAddResult(request.url, CACHE_UPDATED); + console.log('Updating cached entry: ' + filename); + return cache.put(cachePath(filename), response.clone()); + }) + .then(function() { + return response; + }); + }) + .catch(function(e) { + return self.caches.open(user_cache_name) + .then(function(cache) { + statAddResult(request.url, CACHE_FALLBACK); + console.log('Serving from cache: ' + request.url); + return cache.match(cachePath(filename)); + }) + .then(function(result) { + if (result) { + statAddResult(request.url, CACHE_HIT); + return result; + } else { + statAddResult(request.url, CACHE_MISS); + throw new NetworkError(); + } + }); + }); +} + +function handleSaveRequest(request, pathname) { + var params = getSearchParams(url.search); + var data = params.data; + var meta = params.meta; + var mode = params.mode; + var sourcefile = params.sourcefile; + var conditional = params.conditional; + var key = params.key; + var sourcekey = params.sourcekey; + + console.log("Search params: " + params); + + // TODO: We currently don't get here because SW doesn't handle POST requests. + return fetch(request); +} function serveEditPage(request, filename) { var p = self.caches.open('main') @@ -110,6 +279,7 @@ function serveEditPage(request, filename) { }).then(function(response) { if (response) { // Replace some of the text. + statAddResult(request.url, CACHE_HIT); console.log('serving editor.html'); return response.text().then(function(text) { var sub_text = text.replace('', filename); @@ -117,6 +287,7 @@ function serveEditPage(request, filename) { return new Response(b); }); } else { + statAddResult(request.url, CACHE_MISS); // Just go back to the origin server if possible. return fetch(request); } @@ -124,41 +295,60 @@ function serveEditPage(request, filename) { return p; } -function onfetch(event) { - var myurl = new URL(event.request.url); +function onInstall(event) { + // Kick off an update, but don't wait for it. + fetchUserDirectory(); + // TODO: Should also fetch on Sync. + // TODO: Should validate exisiting cache entries while we are here. +} + +function onActivate(event) { + var p = preloadInternalPages() + .then(function() { + return lookupRequestOnCache('/editor.html'); + }) + .catch(function() {}); + event.waitUntil(p); +} + +var blacklisted_prefixes = [ + '/log', '/raw' + ]; + +function onFetch(event) { + statAddRequest(event.request.url); + var url = new URL(event.request.url); var scopeurl = new URL(self.scope); - if (myurl.host === myurl.host) { - if (myurl.pathname === '/stats') { - event.respondWith(returnStatsPage()); + if (url.host === url.host) { + if (url.pathname.indexOf('/stats') === 0) { + event.respondWith(handleStatsRequest(url)); + return; + } + if (url.pathname.indexOf('/edit/') == 0) { + event.respondWith(serveEditPage(event.request, url.pathname.substr('/edit'.length))); return; } - if (myurl.pathname.indexOf('/edit/') == 0) { - event.respondWith(serveEditPage(event.request, myurl.pathname.substr('/edit'.length))); + if (url.pathname.indexOf('/load') === 0) { + event.respondWith(handleLoadRequest(event.request, url.pathname.substr('/load'.length))); return; } - if (myurl.pathname === '/killcache') { - event.respondWith(killCache()); + if (url.pathname.indexOf('/save') === 0) { + event.respondWith(handleSaveRequest(event.request, url.pathname.substr('/save'.length))); return; } if (blacklisted_prefixes.some(function(prefix) { - return myurl.pathname.indexOf(prefix) == 0; + return url.pathname.indexOf(prefix) == 0; })) { + statAddResult(event.request.url, CACHE_SKIPPED); return; } } - if (myurl.host === 'www.google-analytics.com') { + if (url.host === 'www.google-analytics.com') { return; } - event.respondWith(lookupRequestOnCache(event.request)); -} - -function oninstall(event) { - console.log('oninstall'); - event.waitUntil(lookupRequestOnCache('/editor.html')); + event.respondWith(getCachedResponse(event.request)); } -self.addEventListener('install', oninstall); - -self.addEventListener('activate', onactivate); - -self.addEventListener('fetch', onfetch); +self.addEventListener('install', onInstall); +self.addEventListener('activate', onActivate); +self.addEventListener('fetch', onFetch); diff --git a/server/save.js b/server/save.js index 5f5a431f..6a925217 100644 --- a/server/save.js +++ b/server/save.js @@ -30,7 +30,6 @@ exports.handleSave = function(req, res, app) { conditional: conditional}); */ - // TODO: Remove file after validation below. try { fsExtra.removeSync(utils.getRootCacheName(app, res)); } From 1e765242914902e611df78bcd3f16d3fa03aba62 Mon Sep 17 00:00:00 2001 From: Chris Bentzel Date: Sun, 23 Nov 2014 12:55:47 -0500 Subject: [PATCH 19/20] Use getCachedResponse --- content/src/worker.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/content/src/worker.js b/content/src/worker.js index 3b49346a..dd43855d 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -296,6 +296,7 @@ function serveEditPage(request, filename) { } function onInstall(event) { + console.log('onInstall'); // Kick off an update, but don't wait for it. fetchUserDirectory(); // TODO: Should also fetch on Sync. @@ -303,9 +304,11 @@ function onInstall(event) { } function onActivate(event) { + console.log('onActivate'); var p = preloadInternalPages() .then(function() { - return lookupRequestOnCache('/editor.html'); + console.log('Going to lookup request on cache.'); + return getCachedResponse('/editor.html'); }) .catch(function() {}); event.waitUntil(p); From 1948025688722f9dd22fa200c33724f0b7dd5e11 Mon Sep 17 00:00:00 2001 From: Asanka Herath Date: Fri, 5 Dec 2014 22:16:11 -0500 Subject: [PATCH 20/20] Fix handling of /edit/ URLs and clean up /stats/. This is close, but we aren't there yet for offline editing. The missing piece is the association of script created documents with a service worker. Without it, the preview window doesn't work offline. Then of course we need to figure out how offline saves are handled. --- Gruntfile.js | 1 + content/src/worker-stats.html | 98 ++++++------ content/src/worker-stats.js | 106 +++++++++++++ content/src/worker.js | 279 ++++++++++------------------------ 4 files changed, 232 insertions(+), 252 deletions(-) create mode 100644 content/src/worker-stats.js diff --git a/Gruntfile.js b/Gruntfile.js index 47de3afa..bea0e386 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -109,6 +109,7 @@ module.exports = function(grunt) { 'content/src/editor.html', 'content/src/framed.html', 'content/src/worker.js', + 'content/src/worker-stats.js', 'content/src/worker-stats.html' ], dest: 'content' diff --git a/content/src/worker-stats.html b/content/src/worker-stats.html index 3c8e8720..a755de2f 100644 --- a/content/src/worker-stats.html +++ b/content/src/worker-stats.html @@ -2,30 +2,38 @@ ServiceWorker stats for ${worker_scope} + @@ -92,13 +88,13 @@

ServiceWorker stats for PencilCode

Cache errors: Loading...

Recent activity

-
+

Main cache keys

-
+

User cache keys

-
+
diff --git a/content/src/worker-stats.js b/content/src/worker-stats.js new file mode 100644 index 00000000..9a733162 --- /dev/null +++ b/content/src/worker-stats.js @@ -0,0 +1,106 @@ +// Some stats for this service worker session. + +var CACHE_HIT = 'hit'; +var CACHE_MISS = 'miss'; +var CACHE_ERROR = 'error'; +var CACHE_UPDATED = 'updated'; +var CACHE_FALLBACK = 'fallback'; +var CACHE_SKIPPED = 'skip'; + +(function() { + var cache_hits = 0; + var cache_misses = 0; + var cache_errors = 0; + var cache_activity = {}; + var max_cache_activity = 30; + var result_handler = { + hit: function() { ++cache_hits; }, + miss: function() { ++cache_misses; }, + error: function() { ++cache_errors; } + }; + + var stats_page = '/worker-stats.html'; + + function addResult(url, result) { + if (!(url in cache_activity)) + cache_activity[url] = []; + cache_activity[url].push(result); + if (result in result_handler) + (result_handler[result])(); + } + + function handlePageRequest(request, path) { + if (path === '/killcache') { + return killCache(); + } + if (path === '/get') { + return getStats(); + } + return getStatsPage(); + } + + function getStats() { + var main_cache_entries = null; + var user_cache_entries = null; + + return self.caches.open(main_cache_name) + .then(function(cache) { + return cache.keys(); + }) + .then(function(keys) { + main_cache_entries = keys.map(function(request) { + return request.url; + }); + }) + .then(function() { + return self.caches.open(user_cache_name); + }) + .then(function(cache) { + return cache.keys(); + }) + .then(function(keys) { + user_cache_entries = keys.map(function(request) { + return request.url; + }); + }) + .then(function() { + var data = { + worker_scope: self.scope, + cache_hits: cache_hits, + cache_misses: cache_misses, + cache_errors: cache_errors, + main_cache_keys: main_cache_entries, + user_cache_keys: user_cache_entries, + recent_requests: Object.keys(cache_activity).map(function(key) { + return [key].concat(cache_activity[key]); + }) + }; + var blob = new Blob([JSON.stringify(data)], { type: 'text/javascript' }); + return new Response(blob); + }); + } + + function killCache() { + return Promise.all([ + self.caches.delete(main_cache_name), + self.caches.delete(user_cache_name) + ]) + .then(function() { + return getStatsPage(); + }) + .then(function() { + return new Response('OK'); + }); + } + + function getStatsPage() { + return getCachedResponse(new Request(stats_page)); + } + + self.stats = { + addResult: addResult, + handlePageRequest: handlePageRequest, + prefetch: getStatsPage, + }; +})(); + diff --git a/content/src/worker.js b/content/src/worker.js index dd43855d..67f174c4 100644 --- a/content/src/worker.js +++ b/content/src/worker.js @@ -1,153 +1,30 @@ -var internal_cache_name = 'internal'; +importScripts('worker-stats.js'); + +// TODO: Cache names should be versioned. var main_cache_name = 'main'; var user_cache_name = 'user'; -// Some stats for this service worker session. -var cache_hits = 0; -var cache_misses = 0; -var cache_errors = 0; -var cache_activity = []; -var max_cache_activity = 30; -var CACHE_HIT = 'hit'; -var CACHE_MISS = 'miss'; -var CACHE_UPDATED = 'updated'; -var CACHE_FALLBACK = 'fallback'; -var CACHE_SKIPPED = 'skip'; - -function statAddRequest(url) { - if (cache_activity.some(function(value) { - if (value[0] === url) { - return true; - } - })) { - return; - } - if (cache_activity > max_cache_activity) { - cache_activity.shift(); - } - - cache_activity.push([url]); -} - -function statAddResult(url, result) { - cache_activity.some(function(value) { - if (value[0] === url) { - value.push(result); - } - }); -} - function getCachedResponse(request) { - var my_cache = null; return self.caches.open(main_cache_name) .then(function(cache) { - my_cache = cache; - return cache.match(request); - }) - .then(function(response) { - if (response === undefined) { - console.log('Cache miss for ' + request.url); - ++cache_misses; - return fetch(request) - .then(function(response) { - return my_cache.put(request, response) - .then(function() { + return cache.match(request) + .then(function(response) { + if (response === undefined) { + stats.addResult(request.url, CACHE_MISS); + return fetch(request) + .then(function(response) { + cache.put(request, response.clone()); return response; }); - }); - } else { - ++cache_hits; - statAddResult(request.url, CACHE_HIT); - - // Return the cached response but update the cache with the online - // version in the background. - fetch(request).then(function(response) { - if (response) - my_cache.put(request, response); + } else { + stats.addResult(request.url, CACHE_HIT); + fetch(request) + .then(function(response) { + return response && cache.put(request, response); + }); + return response; + } }); - - return response; - } - }) - .catch(function(e) { - ++cache_errors; - console.log('Caught ' + e + ' for ' + request.url); - throw e; - }); -} - -function preloadInternalPages() { - var internal_pages = ['worker-stats.html']; - return Promise.all(internal_pages.map(function(page) { - return fetch(page) - .then(function(response) { - return self.caches.open(internal_cache_name) - .then(function(cache) { - return cache.put(page, response); - }); - }); - })); -} - -function handleStatsRequest(url) { - if (url.pathname === '/stats/killcache') { - return killCache(); - } - if (url.pathname === '/stats/get') { - return getStats(); - } - return self.caches.open(internal_cache_name) - .then(function(cache) { - return cache.match('worker-stats.html'); - }); -} - -function getStats() { - var main_cache_entries = null; - var user_cache_entries = null; - - return self.caches.open(main_cache_name) - .then(function(cache) { - return cache.keys(); - }) - .then(function(keys) { - main_cache_entries = keys.map(function(request) { - return request.url; - }); - }) - .then(function() { - return self.caches.open(user_cache_name); - }) - .then(function(cache) { - return cache.keys(); - }) - .then(function(keys) { - user_cache_entries = keys.map(function(request) { - return request.url; - }); - }) - .then(function() { - var data = { - worker_scope: self.scope, - cache_hits: cache_hits, - cache_misses: cache_misses, - cache_errors: cache_errors, - main_cache_keys: main_cache_entries, - user_cache_keys: user_cache_entries, - recent_requests: cache_activity - }; - var blob = new Blob([JSON.stringify(data)], { type: 'text/javascript' }); - return new Response(blob); - }); -} - -function killCache() { - return Promise.all([ - self.caches.delete(main_cache_name), - self.caches.delete(user_cache_name) - ]) - .then(function() { - return new Response('OK'); }); } @@ -158,22 +35,22 @@ function appendPath(base, name) { return base + '/' + name; } -function cachePath(filename) { +function rawCacheEntryName(filename) { return '/raw/' + filename; } -function fetchUserFiles(path, list) { +function prefetchUserFiles(path, list) { var p = Promise.all(list.map(function(entry) { var entry_path = appendPath(path, entry.name); if (entry.mode === 'drwx') { - return fetchUserDirectory(entry_path); + return prefetchUserDirectory(entry_path); } else { return fetch('/load?file=' + entry_path) .then(function(response) { return self.caches.open(user_cache_name) .then(function(cache) { console.log("Adding user file: " + entry_path); - return cache.put(cachePath(entry_path), response); + return cache.put(rawCacheEntryName(entry_path), response); }); }); } @@ -181,7 +58,7 @@ function fetchUserFiles(path, list) { return p; } -function fetchUserDirectory(path) { +function prefetchUserDirectory(path) { path = path || ''; // path must be a directory. var p = fetch('/load?file=' + path) @@ -189,7 +66,7 @@ function fetchUserDirectory(path) { return self.caches.open(user_cache_name) .then(function(cache) { console.log("Adding user directory : " + path); - return cache.put(cachePath(path), response.clone()); + return cache.put(rawCacheEntryName(path), response.clone()); }) .then(function() { // response should be json. @@ -198,7 +75,7 @@ function fetchUserDirectory(path) { }) .then(function(data) { var list = data.list; - return fetchUserFiles(path, list); + return prefetchUserFiles(path, list); }); return p; } @@ -229,9 +106,9 @@ function handleLoadRequest(request, pathname) { var response_clone = response.clone(); return self.caches.open(user_cache_name) .then(function(cache) { - statAddResult(request.url, CACHE_UPDATED); + stats.addResult(request.url, CACHE_UPDATED); console.log('Updating cached entry: ' + filename); - return cache.put(cachePath(filename), response.clone()); + return cache.put(rawCacheEntryName(filename), response.clone()); }) .then(function() { return response; @@ -240,16 +117,16 @@ function handleLoadRequest(request, pathname) { .catch(function(e) { return self.caches.open(user_cache_name) .then(function(cache) { - statAddResult(request.url, CACHE_FALLBACK); + stats.addResult(request.url, CACHE_FALLBACK); console.log('Serving from cache: ' + request.url); - return cache.match(cachePath(filename)); + return cache.match(rawCacheEntryName(filename)); }) .then(function(result) { if (result) { - statAddResult(request.url, CACHE_HIT); + stats.addResult(request.url, CACHE_HIT); return result; } else { - statAddResult(request.url, CACHE_MISS); + stats.addResult(request.url, CACHE_MISS); throw new NetworkError(); } }); @@ -257,6 +134,7 @@ function handleLoadRequest(request, pathname) { } function handleSaveRequest(request, pathname) { + var url = new URL(request.url); var params = getSearchParams(url.search); var data = params.data; var meta = params.meta; @@ -268,85 +146,84 @@ function handleSaveRequest(request, pathname) { console.log("Search params: " + params); - // TODO: We currently don't get here because SW doesn't handle POST requests. return fetch(request); } function serveEditPage(request, filename) { - var p = self.caches.open('main') + return self.caches.open(main_cache_name) .then(function(cache) { - return cache.match('/editor.html'); - }).then(function(response) { - if (response) { - // Replace some of the text. - statAddResult(request.url, CACHE_HIT); - console.log('serving editor.html'); - return response.text().then(function(text) { - var sub_text = text.replace('', filename); - var b = new Blob([sub_text], {'type': 'text/html'}); - return new Response(b); - }); - } else { - statAddResult(request.url, CACHE_MISS); - // Just go back to the origin server if possible. - return fetch(request); - } - }); - return p; + return cache.match('/editor.html'); + }) + .then(function(response) { + if (response) { + // Replace some of the text. + stats.addResult(request.url, CACHE_HIT); + console.log('serving editor.html'); + return response.text().then(function(text) { + var sub_text = text.replace('', filename); + var b = new Blob([sub_text], {'type': 'text/html'}); + return new Response(b); + }); + } else { + stats.addResult(request.url, CACHE_MISS); + // Just go back to the origin server if possible. + return fetch(request); + } + }); } function onInstall(event) { console.log('onInstall'); + // TODO: Should validate exisiting cache entries here. // Kick off an update, but don't wait for it. - fetchUserDirectory(); + prefetchUserDirectory(); + var p = Promise.all([ + stats.prefetch(), + getCachedResponse(new Request('/editor.html')) + ]); + event.waitUntil(p); // TODO: Should also fetch on Sync. - // TODO: Should validate exisiting cache entries while we are here. } function onActivate(event) { console.log('onActivate'); - var p = preloadInternalPages() - .then(function() { - console.log('Going to lookup request on cache.'); - return getCachedResponse('/editor.html'); - }) - .catch(function() {}); - event.waitUntil(p); } var blacklisted_prefixes = [ - '/log', '/raw' - ]; + '/log', '/raw' +]; + +var page_handlers = [ + // Note that it's important to begin and end the prefix string with /. + { prefix: '/stats/', handler: stats.handlePageRequest }, + { prefix: '/edit/', handler: serveEditPage }, + { prefix: '/load/', handler: handleLoadRequest }, + { prefix: '/save/', handler: handleSaveRequest } +]; function onFetch(event) { - statAddRequest(event.request.url); var url = new URL(event.request.url); var scopeurl = new URL(self.scope); if (url.host === url.host) { - if (url.pathname.indexOf('/stats') === 0) { - event.respondWith(handleStatsRequest(url)); - return; - } - if (url.pathname.indexOf('/edit/') == 0) { - event.respondWith(serveEditPage(event.request, url.pathname.substr('/edit'.length))); - return; - } - if (url.pathname.indexOf('/load') === 0) { - event.respondWith(handleLoadRequest(event.request, url.pathname.substr('/load'.length))); - return; - } - if (url.pathname.indexOf('/save') === 0) { - event.respondWith(handleSaveRequest(event.request, url.pathname.substr('/save'.length))); + if (page_handlers.some(function(h) { + if (url.pathname.indexOf(h.prefix) === 0) { + var remaining_path = url.pathname.substr(h.prefix.length - 1); + event.respondWith(h.handler(event.request, remaining_path)); + return true; + } + return false; + })) { return; } if (blacklisted_prefixes.some(function(prefix) { return url.pathname.indexOf(prefix) == 0; })) { - statAddResult(event.request.url, CACHE_SKIPPED); + stats.addResult(event.request.url, CACHE_SKIPPED); return; } } if (url.host === 'www.google-analytics.com') { + stats.addResult(event.request.url, CACHE_SKIPPED); return; } event.respondWith(getCachedResponse(event.request));