vulcain-corejs
Version:
Vulcain micro-service framework
216 lines • 7.96 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const rx = require("rxjs");
const dynamicProperty_1 = require("./properties/dynamicProperty");
const PrioritizedSourceValue_1 = require("./sources/PrioritizedSourceValue");
const chainedPropertyValue_1 = require("./properties/chainedPropertyValue");
const fileConfigurationSource_1 = require("./sources/fileConfigurationSource");
const system_1 = require("../globals/system");
const environmentVariableSource_1 = require("./sources/environmentVariableSource");
const files_1 = require("../utils/files");
class ConfigurationManager {
constructor(pollingIntervalInSeconds = 60, sourceTimeoutInMs = 1500) {
this.pollingIntervalInSeconds = pollingIntervalInSeconds;
this.sourceTimeoutInMs = sourceTimeoutInMs;
this._dynamicProperties = new Map();
this._environmentVariables = new environmentVariableSource_1.EnvironmentVariableSource();
}
get properties() {
return this._dynamicProperties;
}
get propertyChanged() {
if (!this._propertyChanged) {
this._propertyChanged = new rx.ReplaySubject(1);
}
return this._propertyChanged;
}
getValueInSources(name) {
if (!this._values) {
this._values = new PrioritizedSourceValue_1.PrioritizedSourceValue();
}
let val = this._values.get(name);
return val;
}
createDynamicProperty(name, defaultValue) {
system_1.Service.registerPropertyAsDependency(name, defaultValue);
let dp = new dynamicProperty_1.DynamicProperty(this, name, defaultValue);
if (name) {
dp.set(this.getValueInSources(name));
}
return dp;
}
createChainedDynamicProperty(name, properties, defaultValue) {
system_1.Service.registerPropertyAsDependency(name, defaultValue);
properties = properties && properties.filter(n => !!n); // remove null property
if (!properties || properties.length === 0)
return this.createDynamicProperty(name, defaultValue);
let dp = new chainedPropertyValue_1.ChainedDynamicProperty(this, name, properties, defaultValue);
dp.set(this.getValueInSources(name));
return dp;
}
getValueFromEnvironmentVariable(name) {
let val = this._environmentVariables.get(name);
return val;
}
getProperty(name) {
let prop = this._dynamicProperties.get(name);
if (!prop) {
let v = this._environmentVariables.get(name);
if (v !== undefined)
prop = this.createDynamicProperty(name, v);
}
return prop;
}
/**
* Initialize source(s) and return only when all sources are initialized
* @param sources List of sources
* @returns {Promise<T>}
*/
async startPolling(sources = [], pollSources = true) {
let localSources = [];
let remoteSources = [];
if (!Array.isArray(sources)) {
sources = [sources];
}
sources.push(new fileConfigurationSource_1.FileConfigurationSource(files_1.Files.findConfigurationFile(), fileConfigurationSource_1.ConfigurationDataType.VulcainConfig));
for (let source of sources) {
// Local properties has loaded first (less priority)
if (source.readProperties) {
localSources.push(source);
await source.readProperties();
}
else {
let s = source;
if (remoteSources.indexOf(s) < 0) {
remoteSources.push(s);
}
}
}
this._values = new PrioritizedSourceValue_1.PrioritizedSourceValue(localSources, remoteSources);
// Run initialization
let tries = 2;
while (tries > 0) {
if (await this.polling(3000, false)) {
// All sources are OK
if (pollSources)
this.repeatPolling();
this.isRunning = true;
return;
}
tries--;
if (tries)
system_1.Service.log.info(null, () => "CONFIG: Some dynamic properties sources failed. Retry polling.");
}
if (!system_1.Service.isDevelopment) {
throw new Error("CONFIG: Cannot read properties from sources. Program is stopped.");
}
else {
system_1.Service.log.info(null, () => "CONFIG: Cannot read properties from sources.");
}
}
/**
* for test only
*/
async forcePolling(src, reset) {
if (reset)
this._values = null;
if (src) {
if (!this._values) {
this._values = new PrioritizedSourceValue_1.PrioritizedSourceValue([], [src]);
}
else {
this._values.remoteSources.push(src);
}
}
await this.polling(3000, false);
}
/**
* Pull properties for all sources
*
* @private
* @param {any} [timeout]
* @returns
*
* @memberOf ConfigurationManager
*/
async polling(timeout, pollSources = true) {
let ok = true;
try {
let list = this._values.remoteSources;
if (this.disposed || !list)
return;
let promises = [];
list.forEach(src => {
promises.push(
// pollProperties cannot failed
src.pollProperties(timeout || this.sourceTimeoutInMs));
});
let results = await Promise.all(promises);
// Ignore null result
results.forEach(res => {
if (!res) {
ok = false;
}
else
this.onPropertiesChanged(res);
});
}
catch (e) {
ok = false;
system_1.Service.log.error(null, e, () => "CONFIG: Error when polling sources");
}
// Restart
if (pollSources)
this.repeatPolling();
return ok;
}
onPropertiesChanged(data) {
if (!data.values)
return;
for (let d of data.values) {
let dp = this._dynamicProperties.get(d.key);
if (!dp) {
dp = this.createDynamicProperty(d.key);
}
else if (dp.updateValue) {
dp.updateValue(d);
}
}
}
onPropertyChanged(dp) {
this._propertyChanged && this._propertyChanged.next(dp);
}
repeatPolling() {
if (!this.disposed && this._values.remoteSources.length > 0)
setTimeout(this.polling.bind(this), this.pollingIntervalInSeconds * 1000);
}
/**
/// Reset configuration and properties.
/// All current properties will be invalid and all current sources will be lost.
/// </summary>
/// <param name="pollingIntervalInSeconds"></param>
/// <param name="sourceTimeoutInMs"></param>
*/
reset(pollingIntervalInSeconds, sourceTimeoutInMs) {
if (pollingIntervalInSeconds)
this.pollingIntervalInSeconds = pollingIntervalInSeconds;
if (sourceTimeoutInMs)
this.sourceTimeoutInMs = sourceTimeoutInMs;
//this._propertyChanged.dispose();
this._propertyChanged = null;
let tmp = this._dynamicProperties;
if (tmp) {
for (let prop of tmp.values()) {
if (prop.dispose)
prop.dispose();
}
tmp.clear();
}
}
dispose() {
this.reset();
this.disposed = true;
}
}
exports.ConfigurationManager = ConfigurationManager;
//# sourceMappingURL=configurationManager.js.map