src/utils.js
/*
* OS.js - JavaScript Cloud/Web Desktop Platform
*
* Copyright (c) Anders Evenrud <andersevenrud@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Anders Evenrud <andersevenrud@gmail.com>
* @licence Simplified BSD License
*/
import {Graph, Node} from 'async-dependency-graph';
export const resolveTreeByKey = (tree, key, defaultValue) => {
let result;
try {
result = key
.split(/\./g)
.reduce((result, key) => result[key], Object.assign({}, tree));
} catch (e) { /* noop */ }
return typeof result === 'undefined' ? defaultValue : result;
};
const each = (list, method) => Promise.all(list.map(p => {
try {
return p.provider[method]();
} catch (e) {
return Promise.reject(e);
}
}))
.catch(err => console.warn(err));
export const providerHandler = (core) => {
let instances = {};
let providers = [];
let registry = [];
const createGraph = (list, method) => {
const graph = new Graph();
const provides = list.map(p => typeof p.provider.provides === 'function' ? p.provider.provides() : []);
const dependsOnIndex = wants => provides.findIndex(arr => arr.some(a => wants.indexOf(a) !== -1));
list.forEach((p, i) => {
graph.addNode(new Node(String(i), () => {
try {
return Promise.resolve(p.provider[method]());
} catch (e) {
return Promise.reject(e);
}
}));
});
list.forEach((p, i) => {
const dependsOptions = p.options.depends instanceof Array
? p.options.depends
: [];
const dependsInstance = typeof p.provider.depends === 'function'
? p.provider.depends()
: [];
const depends = [...dependsOptions, ...dependsInstance];
if (depends.length > 0) {
const dindex = dependsOnIndex(depends);
if (dindex !== -1) {
graph.addDependency(String(i), String(dindex));
}
}
});
return graph.traverse()
.catch(e => console.warn(e));
};
const handle = list => createGraph(list, 'init')
.then(() => createGraph(list, 'start'));
const has = name => registry.findIndex(p => p.name === name) !== -1;
const destroy = () => {
const result = each(providers, 'destroy');
instances = {};
registry = [];
return result;
};
const init = (before) =>
handle(before
? providers.filter(p => p.options.before)
: providers.filter(p => !p.options.before));
const register = (ref, options) => {
try {
providers.push({
provider: new ref(core, options.args),
options
});
} catch (e) {
console.error('Provider register error', e);
}
};
const bind = (name, singleton, callback) => {
core.logger.info('Provider binding', name);
registry.push({
singleton,
name,
make(...args) {
return callback(...args);
}
});
};
const make = (name, ...args) => {
const found = registry.find(p => p.name === name);
if (!found) {
throw new Error(`Provider '${name}' not found`);
}
if (!found.singleton) {
return found.make(...args);
}
if (!instances[name]) {
if (found) {
instances[name] = found.make(...args);
}
}
return instances[name];
};
return {register, init, bind, has, make, destroy};
};