kopia lustrzana https://gitlab.com/rysiekpl/libresilient
preparing for fully revertable config deployment: executeConfig() (ref. #48)
rodzic
b159976478
commit
4bf42c1c93
|
@ -337,15 +337,6 @@ describe('service-worker', async () => {
|
|||
|
||||
window.test_id = 0
|
||||
|
||||
it("should set-up LibResilientPlugins", async () => {
|
||||
// we cannot import the same module multiple times:
|
||||
// https://github.com/denoland/deno/issues/6946
|
||||
//
|
||||
// ...so we have to use a query-param hack, sigh
|
||||
await import("../../service-worker.js?" + window.test_id);
|
||||
assert(self.LibResilientPlugins instanceof Array)
|
||||
})
|
||||
|
||||
it("should use default LibResilientConfig values when config.json is missing", async () => {
|
||||
|
||||
let mock_response_data = {
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
* LibResilient Service Worker.
|
||||
*/
|
||||
|
||||
// initialize the LibResilientPlugins array
|
||||
if (!Array.isArray(self.LibResilientPlugins)) {
|
||||
self.LibResilientPlugins = new Array()
|
||||
}
|
||||
|
||||
// initialize the LibResilientConfig array
|
||||
//
|
||||
// this also sets some sane defaults,
|
||||
|
@ -277,6 +272,118 @@ let getConfigJSON = async (cresponse) => {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* execute on the configuration
|
||||
*
|
||||
* load plugin modules, making constructors available
|
||||
* cycle through the plugin config instantiating plugins and their dependencies
|
||||
*/
|
||||
let executeConfig = (pluginsConfig) => {
|
||||
|
||||
// clean version of LibResilientPlugins
|
||||
// NOTICE: this assumes LibResilientPlugins is not ever used *befure* this runs
|
||||
// NOTICE: this assumption seems to hold currently, but noting for clarity
|
||||
self.LibResilientPlugins = new Array()
|
||||
|
||||
// this is the stash for plugins that need dependencies instantiated first
|
||||
let dependentPlugins = new Array()
|
||||
|
||||
// only now load the plugins (config.json could have changed the defaults)
|
||||
while (pluginsConfig.length > 0) {
|
||||
|
||||
// get the first plugin config from the array
|
||||
let pluginConfig = pluginsConfig.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}/index.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 (let 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
|
||||
pluginsConfig.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 {
|
||||
|
||||
// if the plugin is not enabled, no instantiation for it nor for its dependencies
|
||||
// if the pluginConfig does not have an "enabled" field, it should be assumed to be "true"
|
||||
if ( ( "enabled" in pluginConfig ) && ( pluginConfig.enabled != true ) ) {
|
||||
self.log('service-worker', `skipping ${pluginConfig.name} instantiation: plugin not enabled (dependencies will also not be instantiated)`)
|
||||
pluginConfig = dependentPlugins.pop()
|
||||
if (pluginConfig !== undefined) {
|
||||
let didx = pluginConfig.uses.indexOf(false)
|
||||
pluginConfig.uses.splice(didx, 1)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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) && (pluginConfig !== undefined) )
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// flag signifying the SW has been initialized already
|
||||
var initDone = false
|
||||
|
||||
|
@ -363,106 +470,14 @@ let initServiceWorker = async () => {
|
|||
// TODO: find a better way
|
||||
self.LibResilientPluginConstructors = self.LibResilientPluginConstructors || new Map()
|
||||
|
||||
// copy of the plugins config
|
||||
// we need to work on it so that self.LibResilientConfig.plugins remains unmodified
|
||||
// point backup of LibResilientPluginConstructors, in case we need to roll back
|
||||
// TODO: handle in a more elegant way
|
||||
let lrpcBackup = new Map(self.LibResilientPluginConstructors)
|
||||
|
||||
// working on a copy of the plugins config so that
|
||||
// self.LibResilientConfig.plugins remains unmodified
|
||||
// in case we need it later (for example, when re-loading the config)
|
||||
var pluginsConfig = [...self.LibResilientConfig.plugins]
|
||||
|
||||
// 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 (pluginsConfig.length > 0) {
|
||||
|
||||
// get the first plugin config from the array
|
||||
let pluginConfig = pluginsConfig.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}/index.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
|
||||
pluginsConfig.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 {
|
||||
|
||||
// if the plugin is not enabled, no instantiation for it nor for its dependencies
|
||||
// if the pluginConfig does not have an "enabled" field, it should be assumed to be "true"
|
||||
if ( ( "enabled" in pluginConfig ) && ( pluginConfig.enabled != true ) ) {
|
||||
self.log('service-worker', `skipping ${pluginConfig.name} instantiation: plugin not enabled (dependencies will also not be instantiated)`)
|
||||
pluginConfig = dependentPlugins.pop()
|
||||
if (pluginConfig !== undefined) {
|
||||
let didx = pluginConfig.uses.indexOf(false)
|
||||
pluginConfig.uses.splice(didx, 1)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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) && (pluginConfig !== undefined) )
|
||||
|
||||
}
|
||||
executeConfig([...self.LibResilientConfig.plugins])
|
||||
|
||||
// inform
|
||||
self.log('service-worker', `service worker initialized.\nstrategy in use: ${self.LibResilientPlugins.map(p=>p.name).join(', ')}`)
|
||||
|
|
Ładowanie…
Reference in New Issue