|
|
|
@ -39,7 +39,7 @@ if (!Array.isArray(self.LibResilientPlugins)) {
|
|
|
|
|
// initialize the LibResilientConfig array
|
|
|
|
|
//
|
|
|
|
|
// this also sets some sane defaults,
|
|
|
|
|
// which then can be modified via config.js
|
|
|
|
|
// which then can be modified via config.json
|
|
|
|
|
if (typeof self.LibResilientConfig !== 'object' || self.LibResilientConfig === null) {
|
|
|
|
|
self.LibResilientConfig = {
|
|
|
|
|
// how long do we wait before we decide that a plugin is unresponsive,
|
|
|
|
@ -93,119 +93,126 @@ self.log = function(component, ...items) {
|
|
|
|
|
//
|
|
|
|
|
// everything in a try-catch block
|
|
|
|
|
// so that we get an informative message if there's an error
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
|
|
// get the config
|
|
|
|
|
//
|
|
|
|
|
// self.registration.scope contains the scope this service worker is registered for
|
|
|
|
|
// so it makes sense to pull config from `config.js` file directly under that location
|
|
|
|
|
//
|
|
|
|
|
// TODO: providing config directly from browser-side control script via postMessage?
|
|
|
|
|
// TODO: `updateViaCache=imports` allows at least config.js to be updated using the cache plugin?
|
|
|
|
|
let initServiceWorker = async () => {
|
|
|
|
|
try {
|
|
|
|
|
self.importScripts(self.registration.scope + "config.js")
|
|
|
|
|
self.log('service-worker', 'config loaded.')
|
|
|
|
|
} catch (e) {
|
|
|
|
|
self.log('service-worker', 'config loading failed, using defaults')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the LibResilientPluginConstructors map
|
|
|
|
|
// the global... hack is here so that we can run tests; not the most elegant
|
|
|
|
|
// TODO: find a better way
|
|
|
|
|
var LibResilientPluginConstructors = self.LibResilientPluginConstructors || new Map()
|
|
|
|
|
|
|
|
|
|
// this is the stash for plugins that need dependencies instantiated first
|
|
|
|
|
var dependentPlugins = new Array()
|
|
|
|
|
|
|
|
|
|
// only now load the plugins (config.js could have changed the defaults)
|
|
|
|
|
while (self.LibResilientConfig.plugins.length > 0) {
|
|
|
|
|
|
|
|
|
|
// get the first plugin config from the array
|
|
|
|
|
let pluginConfig = self.LibResilientConfig.plugins.shift()
|
|
|
|
|
self.log('service-worker', `handling plugin type: ${pluginConfig.name}`)
|
|
|
|
|
|
|
|
|
|
// load the relevant plugin script (if not yet loaded)
|
|
|
|
|
if (!LibResilientPluginConstructors.has(pluginConfig.name)) {
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: loading plugin's source`)
|
|
|
|
|
self.importScripts(`./plugins/${pluginConfig.name}.js`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do we have any dependencies we should handle first?
|
|
|
|
|
if (typeof pluginConfig.uses !== "undefined") {
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: ${pluginConfig.uses.length} dependencies found`)
|
|
|
|
|
|
|
|
|
|
// move the dependency plugin configs to LibResilientConfig to be worked on next
|
|
|
|
|
for (var i=(pluginConfig.uses.length); i--; i>=0) {
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: dependency found: ${pluginConfig.uses[i].name}`)
|
|
|
|
|
// put the plugin config in front of the plugin configs array
|
|
|
|
|
self.LibResilientConfig.plugins.unshift(pluginConfig.uses[i])
|
|
|
|
|
// set each dependency plugin config to false so that we can keep track
|
|
|
|
|
// as we fill those gaps later with instantiated dependency plugins
|
|
|
|
|
pluginConfig.uses[i] = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stash the plugin config until we have all the dependencies handled
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: not instantiating until dependencies are ready`)
|
|
|
|
|
dependentPlugins.push(pluginConfig)
|
|
|
|
|
|
|
|
|
|
// move on to the next plugin config, which at this point will be
|
|
|
|
|
// the first of dependencies for the plugin whose config got stashed
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
|
|
// instantiate the plugin
|
|
|
|
|
let plugin = LibResilientPluginConstructors.get(pluginConfig.name)(self, pluginConfig)
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: instantiated`)
|
|
|
|
|
|
|
|
|
|
// do we have a stashed plugin that requires dependencies?
|
|
|
|
|
if (dependentPlugins.length === 0) {
|
|
|
|
|
// no we don't; so, this plugin goes directly to the plugin list
|
|
|
|
|
self.LibResilientPlugins.push(plugin)
|
|
|
|
|
// we're done here
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: no dependent plugins, pushing directly to LibResilientPlugins`)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// at this point clearly there is at least one element in dependentPlugins
|
|
|
|
|
// so we can safely assume that the freshly instantiated plugin is a dependency
|
|
|
|
|
//
|
|
|
|
|
// in that case let's find the first empty spot for a dependency
|
|
|
|
|
let didx = dependentPlugins[dependentPlugins.length - 1].uses.indexOf(false)
|
|
|
|
|
// assign the freshly instantiated plugin as that dependency
|
|
|
|
|
dependentPlugins[dependentPlugins.length - 1].uses[didx] = plugin
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: assigning as dependency (#${didx}) to ${dependentPlugins[dependentPlugins.length - 1].name}`)
|
|
|
|
|
|
|
|
|
|
// was this the last one?
|
|
|
|
|
if (didx >= dependentPlugins[dependentPlugins.length - 1].uses.length - 1) {
|
|
|
|
|
// yup, last one!
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: this was the last dependency of ${dependentPlugins[dependentPlugins.length - 1].name}`)
|
|
|
|
|
// we can now proceed to instantiate the last element of dependentPlugins
|
|
|
|
|
pluginConfig = dependentPlugins.pop()
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// it is not the last one, so there should be more dependency plugins to instantiate first
|
|
|
|
|
// before we can instantiate the last of element of dependentPlugins
|
|
|
|
|
// but that requires the full treatment, including checing the `uses` field for their configs
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: not yet the last dependency of ${dependentPlugins[dependentPlugins.length - 1].name}`)
|
|
|
|
|
pluginConfig = false
|
|
|
|
|
|
|
|
|
|
// if pluginConfig is not false, rinse-repeat the plugin instantiation steps
|
|
|
|
|
// since we are dealing with the last element of dependentPlugins
|
|
|
|
|
} while (pluginConfig !== false)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// inform
|
|
|
|
|
self.log('service-worker', `DEBUG: Strategy in use: ${self.LibResilientPlugins.map(p=>p.name).join(', ')}`)
|
|
|
|
|
|
|
|
|
|
} catch(e) {
|
|
|
|
|
// we only get a cryptic "Error while registering a service worker"
|
|
|
|
|
// unless we explicitly print the errors out in the console
|
|
|
|
|
console.error(e)
|
|
|
|
|
throw e
|
|
|
|
|
// get the config
|
|
|
|
|
//
|
|
|
|
|
// self.registration.scope contains the scope this service worker is registered for
|
|
|
|
|
// so it makes sense to pull config from `config.json` file directly under that location
|
|
|
|
|
//
|
|
|
|
|
// TODO: providing config directly from browser-side control script via postMessage?
|
|
|
|
|
// TODO: `updateViaCache=imports` allows at least config.json to be updated using the cache plugin?
|
|
|
|
|
console.debug('* * * LOADING CONFIG * * *')
|
|
|
|
|
try {
|
|
|
|
|
//self.importScripts(self.registration.scope + "config.json")
|
|
|
|
|
var cdata = await fetch(self.registration.scope + "config.json")
|
|
|
|
|
cdata = await cdata.json()
|
|
|
|
|
self.LibResilientConfig.plugins = cdata.plugins
|
|
|
|
|
self.LibResilientConfig.loggedComponents = cdata.loggedComponents
|
|
|
|
|
self.log('service-worker', 'config loaded.')
|
|
|
|
|
} catch (e) {
|
|
|
|
|
self.log('service-worker', 'config loading failed, using defaults')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the LibResilientPluginConstructors map
|
|
|
|
|
// the global... hack is here so that we can run tests; not the most elegant
|
|
|
|
|
// TODO: find a better way
|
|
|
|
|
self.LibResilientPluginConstructors = self.LibResilientPluginConstructors || new Map()
|
|
|
|
|
|
|
|
|
|
// this is the stash for plugins that need dependencies instantiated first
|
|
|
|
|
var dependentPlugins = new Array()
|
|
|
|
|
|
|
|
|
|
// only now load the plugins (config.json could have changed the defaults)
|
|
|
|
|
while (self.LibResilientConfig.plugins.length > 0) {
|
|
|
|
|
|
|
|
|
|
// get the first plugin config from the array
|
|
|
|
|
let pluginConfig = self.LibResilientConfig.plugins.shift()
|
|
|
|
|
self.log('service-worker', `handling plugin type: ${pluginConfig.name}`)
|
|
|
|
|
|
|
|
|
|
// load the relevant plugin script (if not yet loaded)
|
|
|
|
|
if (!LibResilientPluginConstructors.has(pluginConfig.name)) {
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: loading plugin's source`)
|
|
|
|
|
self.importScripts(`./plugins/${pluginConfig.name}.js`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do we have any dependencies we should handle first?
|
|
|
|
|
if (typeof pluginConfig.uses !== "undefined") {
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: ${pluginConfig.uses.length} dependencies found`)
|
|
|
|
|
|
|
|
|
|
// move the dependency plugin configs to LibResilientConfig to be worked on next
|
|
|
|
|
for (var i=(pluginConfig.uses.length); i--; i>=0) {
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: dependency found: ${pluginConfig.uses[i].name}`)
|
|
|
|
|
// put the plugin config in front of the plugin configs array
|
|
|
|
|
self.LibResilientConfig.plugins.unshift(pluginConfig.uses[i])
|
|
|
|
|
// set each dependency plugin config to false so that we can keep track
|
|
|
|
|
// as we fill those gaps later with instantiated dependency plugins
|
|
|
|
|
pluginConfig.uses[i] = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stash the plugin config until we have all the dependencies handled
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: not instantiating until dependencies are ready`)
|
|
|
|
|
dependentPlugins.push(pluginConfig)
|
|
|
|
|
|
|
|
|
|
// move on to the next plugin config, which at this point will be
|
|
|
|
|
// the first of dependencies for the plugin whose config got stashed
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
|
|
// instantiate the plugin
|
|
|
|
|
let plugin = LibResilientPluginConstructors.get(pluginConfig.name)(self, pluginConfig)
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: instantiated`)
|
|
|
|
|
|
|
|
|
|
// do we have a stashed plugin that requires dependencies?
|
|
|
|
|
if (dependentPlugins.length === 0) {
|
|
|
|
|
// no we don't; so, this plugin goes directly to the plugin list
|
|
|
|
|
self.LibResilientPlugins.push(plugin)
|
|
|
|
|
// we're done here
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: no dependent plugins, pushing directly to LibResilientPlugins`)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// at this point clearly there is at least one element in dependentPlugins
|
|
|
|
|
// so we can safely assume that the freshly instantiated plugin is a dependency
|
|
|
|
|
//
|
|
|
|
|
// in that case let's find the first empty spot for a dependency
|
|
|
|
|
let didx = dependentPlugins[dependentPlugins.length - 1].uses.indexOf(false)
|
|
|
|
|
// assign the freshly instantiated plugin as that dependency
|
|
|
|
|
dependentPlugins[dependentPlugins.length - 1].uses[didx] = plugin
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: assigning as dependency (#${didx}) to ${dependentPlugins[dependentPlugins.length - 1].name}`)
|
|
|
|
|
|
|
|
|
|
// was this the last one?
|
|
|
|
|
if (didx >= dependentPlugins[dependentPlugins.length - 1].uses.length - 1) {
|
|
|
|
|
// yup, last one!
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: this was the last dependency of ${dependentPlugins[dependentPlugins.length - 1].name}`)
|
|
|
|
|
// we can now proceed to instantiate the last element of dependentPlugins
|
|
|
|
|
pluginConfig = dependentPlugins.pop()
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// it is not the last one, so there should be more dependency plugins to instantiate first
|
|
|
|
|
// before we can instantiate the last of element of dependentPlugins
|
|
|
|
|
// but that requires the full treatment, including checing the `uses` field for their configs
|
|
|
|
|
self.log('service-worker', `${pluginConfig.name}: not yet the last dependency of ${dependentPlugins[dependentPlugins.length - 1].name}`)
|
|
|
|
|
pluginConfig = false
|
|
|
|
|
|
|
|
|
|
// if pluginConfig is not false, rinse-repeat the plugin instantiation steps
|
|
|
|
|
// since we are dealing with the last element of dependentPlugins
|
|
|
|
|
} while (pluginConfig !== false)
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// inform
|
|
|
|
|
self.log('service-worker', `DEBUG: Strategy in use: ${self.LibResilientPlugins.map(p=>p.name).join(', ')}`)
|
|
|
|
|
|
|
|
|
|
} catch(e) {
|
|
|
|
|
// we only get a cryptic "Error while registering a service worker"
|
|
|
|
|
// unless we explicitly print the errors out in the console
|
|
|
|
|
console.error(e)
|
|
|
|
|
throw e
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -672,7 +679,8 @@ let getResourceThroughLibResilient = (request, clientId, useStashed=true, doStas
|
|
|
|
|
|* === Setting up the event handlers === *|
|
|
|
|
|
\* ========================================================================= */
|
|
|
|
|
|
|
|
|
|
self.addEventListener('install', event => {
|
|
|
|
|
self.addEventListener('install', async (event) => {
|
|
|
|
|
event.waitUntil(initServiceWorker())
|
|
|
|
|
// TODO: Might we want to have a local cache?
|
|
|
|
|
// "COMMIT_UNKNOWN" will be replaced with commit ID
|
|
|
|
|
self.log('service-worker', "0. Installed LibResilient Service Worker (commit: COMMIT_UNKNOWN).");
|
|
|
|
|