Skip to content

Commit

Permalink
Merge 2ec1437 into 4353319
Browse files Browse the repository at this point in the history
  • Loading branch information
peuter committed Mar 17, 2019
2 parents 4353319 + 2ec1437 commit 43524d6
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 7 deletions.
1 change: 1 addition & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"smarttabs": true,
"multistr": true,
"jasmine": true,
"worker": true,
"globals": {
"browser": false,
"describe": false,
Expand Down
12 changes: 10 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@
"version",
"library_version.inc.php",
"manifest.json",
"../node_modules/monaco-editor"
"../node_modules/monaco-editor",
"ServiceWorker.js"
]
}
},
Expand Down Expand Up @@ -353,6 +354,13 @@
}
},

"update-version-cache": {
"shell" :
{
"command" : "utils/update_version.py worker"
}
},

"build" :
{
"extend" : [ "parts-config" ],
Expand All @@ -365,7 +373,7 @@
"run" :
[
"build-resources",
"update-version",
"update-version-cache",
"build-script",
"build-files",
"build-libs",
Expand Down
14 changes: 14 additions & 0 deletions doc/manual/de/config/url-params.rst
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,17 @@ In der Entwicklerversion sind diese standardmäßig eingeschaltet in einem Relea
Default: false im Release, true in Entwicklerversion
Options: true (log=true), false (log=false)
.. _worker:

*worker* - ServiceWorker Cache in der Entwicklerversion einschalten

In der Entwicklerversion ist der ServiceWorker zum Caching der Dateien abgeschaltet, damit man Änderungen
während des Entwickelns beim neu Laden direkt testen kann. Mit diesem URL-Parameter kann der ServiceWorker
trotzdem eingeschaltet werden

.. code::
Default: false (worker=false)
Options: true (worker=true) [nur in Entwicklungsversion, in einem Release hat dieser Parameter eine Funktion]
189 changes: 189 additions & 0 deletions source/ServiceWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/**
* ServiceWorker for the CometVisu
*
* @author Tobias Bräutigam
* @since (0.11.0) 2017
*/

var CACHE = "cv-cache-v2";
var NO_CACHE_TEST = /.+\.php$/i;
var CONFIG_TEST = /.+visu_config.*\.xml.*/i;
var config = {};
var updateQueue = [];
var queueTid = null;
let startTime = 0;
const logPrefix = 'cv.ServiceWorker:';
const logStyling = 'color: #0044b2;';

const logger = {
log: function () {
console.log.apply(console, this._generateArgs(arguments));
},

debug: function () {
if (config.debug === true) {
console.debug.apply(console, this._generateArgs(arguments));
}
},

_generateArgs(argsIn) {
let args = Array.prototype.slice.call(argsIn);
let message = this._getPrefix();
let params = [logStyling];
// apply the style prefix
args.forEach(msg => {
switch (typeof msg) {
case 'object':
message += ' %o';
params.push(msg);
break;
default:
message += ' ' + msg;
break;
}
});
params.unshift(message);
return params;
},

_getPrefix() {
return '%c' + (Date.now() - startTime).toString().padStart(6, '0') + ' ' +logPrefix;
}
};

function fromNetwork(request, timeout) {
return new Promise(function (resolve, reject) {
if (timeout) {
var timeoutId = setTimeout(reject, timeout);
}

fetch(request).then(function (response) {
if (timeoutId) {
clearTimeout(timeoutId);
}
resolve(response);
}, reject);
});
}

/**
* Fetch request from network and update the cache
* @param request {Request}
* @return {Promise}
*/
function update(request) {
caches.open(CACHE).then(function (cache) {
fetch(request).then(function (response) {
if (response.status < 400) {
cache.put(request, response);
}
});
});
}

function processQueue() {
while (updateQueue.length) {
var request = updateQueue.shift();
update(request);
}
}

/**
* Get response from cache
* @param request {Request}
* @return {Response}
*/
function fromCache(request) {
return caches.open(CACHE).then(function (cache) {
return cache.match(request).then(function (matching) {
return matching || Promise.reject('no-match');
});
});
}

/**
* Fetch request from network, update the cache and return the response
* @param request {Request}
* @return {Response}
*/
function fetchAndUpdate(request) {
return caches.open(CACHE).then(function (cache) {
return fetch(request).then(function (response) {
if (response.status < 400) {
cache.put(request, response.clone());
}
return response;
});
});
}

self.addEventListener('message', function (event) {
var data = event.data;

if (data.command === "configure") {
config = data.message;
logger.debug('Configuration:', config);
}
});

self.addEventListener('install', function () {
startTime = Date.now();
// take over right now
logger.log("CometVisu service worker installed");
});

// delete old caches after activation
self.addEventListener('activate', function (event) {
logger.log("CometVisu service worker activated");
var cacheWhitelist = [CACHE];
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});

self.addEventListener('fetch', function(ev) {
if (config.disableCache === true ||
!ev.request.url.startsWith(this.registration.scope) ||
CONFIG_TEST.test(ev.request.url)
) {
// fallback to "normal" behaviour without serviceWorker -> sends HTTP request
logger.debug("ignore cache for " + ev.request.url);
return;
}

if (!NO_CACHE_TEST.test(ev.request.url) &&
(!ev.request.headers.pragma || ev.request.headers.pragma !== "no-cache") &&
(!ev.request.headers['Cache-Control'] || ev.request.headers['Cache-Control'] !== "no-cache")
) {

ev.respondWith(fromCache(ev.request).then(function(response){
logger.debug('load from cache ' + ev.request.url);
if (config.forceReload === true) {
update(ev.request);
} else {
updateQueue.push(ev.request);
if (queueTid) {
clearTimeout(queueTid);
}
queueTid = setTimeout(processQueue, 1000);
}

return response;
}).catch(function () {
// not cached -> do now
logger.debug("caching " + ev.request.url);
return fetchAndUpdate(ev.request);
}));
} else {
logger.debug('load from network ' + ev.request.url);
ev.respondWith(fromNetwork(ev.request));
}
});
39 changes: 39 additions & 0 deletions source/class/cv/Application.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ qx.Class.define("cv.Application",

console.log(info);

this.registerServiceWorker();

if (qx.core.Environment.get("qx.aspects")) {
qx.dev.Profile.stop();
qx.dev.Profile.start();
Expand Down Expand Up @@ -613,6 +615,43 @@ qx.Class.define("cv.Application",
cv.Config.initialPage = cv.TemplateEngine.getInstance().getPageIdByPath(startpage) || "id_";
});
}
},

/**
* Install the service-worker if possible
*/
registerServiceWorker: function() {
if (cv.Config.useServiceWorker === true) {
navigator.serviceWorker.register('ServiceWorker.js').then(function(reg) {
this.debug("ServiceWorker successfully registered for scope "+reg.scope);

// configure service worker
var configMessage = {
"command": "configure",
"message": {
forceReload: cv.Config.forceReload,
debug: qx.core.Environment.get('qx.debug')
}
};

if (reg.active) {
reg.active.postMessage(configMessage);
} else {
navigator.serviceWorker.ready.then(function(ev) {
ev.active.postMessage(configMessage);
});
}
}.bind(this)).catch(function(err) {
this.error("Error registering service-worker: ", err);
}.bind(this));
} else {
navigator.serviceWorker.getRegistrations().then(function(registrations) {
this.debug('unregistering existing service workers');
registrations.forEach(function (registration) {
registration.unregister();
});
}.bind(this));
}
}
}
});
17 changes: 14 additions & 3 deletions source/class/cv/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,11 @@ qx.Class.define('cv.Config', {
configServer: null,

/**
* In testMode the visu can be filled with some demo data
* If the CometVisu can use service workers
*/
initialDemoData: null,
useServiceWorker: false,

enableServiceWorkerCache : true,

/**
* Get the structure that is related to this design
Expand Down Expand Up @@ -353,5 +355,14 @@ qx.Class.define('cv.Config', {
if (isNaN(cv.Config.use_maturity)) {
cv.Config.use_maturity = statics.Maturity.release; // default to release
}

cv.Config.useServiceWorker = 'serviceWorker' in navigator && (req.protocol === "https" || req.host === "localhost");

if (cv.Config.useServiceWorker) {
if (qx.core.Environment.get("qx.debug")) {
// disable service worker in dev environment unless the user wants it
cv.Config.useServiceWorker = req.queryKey.worker === "true";
}
}
}
});
});
14 changes: 12 additions & 2 deletions utils/update_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import datetime
import json
import os
import sys
import re

root_dir = os.path.abspath(os.path.join(os.path.realpath(os.path.dirname(__file__)), '..'))


def update_version():
def update_version(service_worker_cache=False):
# gather information from git
data = {
"revision": subprocess.check_output(["git", "rev-parse", "HEAD"]).strip("\n"),
Expand All @@ -34,5 +36,13 @@ def update_version():
});
''' % data)

if service_worker_cache is True:
regex = re.compile("var CACHE = \"(.+)\";", re.IGNORECASE)
with open(os.path.join(root_dir, "source", "ServiceWorker.js"), 'r+') as f:
content = f.read()
content = regex.sub("var CACHE = \"%s\";" % data['revision'], content)
f.seek(0)
f.write(content)

if __name__ == '__main__':
update_version()
update_version(len(sys.argv) == 2 and sys.argv[1] == "worker")

0 comments on commit 43524d6

Please sign in to comment.