vulcain-corejs
Version:
Vulcain micro-service framework
142 lines (140 loc) • 5.75 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments)).next());
});
};
const system_1 = require("./../globals/system");
const configurationSource_1 = require("./configurationSource");
const Consul = require('consul');
class ConsulConfigurationSource {
constructor(globalKeys, serviceKey, consulAddress) {
// Local cache
this._changes = new Map();
this._allkeys = new Set();
try {
if (!globalKeys) {
let env = system_1.System.environment;
globalKeys = `vulcain/${env}/configurations/shared`;
}
this.globalKeys = globalKeys;
if (!serviceKey) {
let env = system_1.System.environment;
let serviceName = system_1.System.serviceName;
if (serviceName)
serviceKey = `vulcain/${env}/configurations/${serviceName}`;
}
this.serviceKey = serviceKey;
this.consul = Consul({ host: consulAddress || "local-storage" });
}
catch (err) {
system_1.System.log.error(null, err, "CONFIG: Error when using consul configuration source");
this.consul = null;
}
}
/**
* get configurations from consul
* First time retrieve all then watch for changes and
* store them locally for the next polling.
*/
pollPropertiesAsync(timeoutInMs) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (!this._initialized && this.consul) {
if (timeoutInMs > 0)
this.consul.timeout = timeoutInMs;
this._initialized = true;
// First time, retrieve all
this._changes = new Map();
this._allkeys.clear();
let data = yield this.getAsync(this.globalKeys);
data && this.merge(this.globalKeys, data);
if (this.serviceKey) {
data = yield this.getAsync(this.serviceKey);
data && this.merge(this.serviceKey, data);
}
this.watchDefinitionsChanges();
}
let result = new configurationSource_1.PollResult(this, this._changes);
if (this._changes.size > 0)
this._changes = new Map();
return result;
}
catch (e) {
system_1.System.log.error(null, e, "CONFIG: Consul configuration source.");
this._initialized = true;
return new configurationSource_1.PollResult(this);
}
});
}
getAsync(key) {
return new Promise((resolve, reject) => {
try {
this.consul.kv.get({ key: key, recurse: true }, (err, data) => {
if (err)
reject(err);
else {
resolve(data);
}
});
}
catch (e) {
reject(e);
}
});
}
merge(prefix, data) {
let max = 0;
// Add new or existing keys
data.filter(d => !d.Key.endsWith('/')).forEach(v => {
let k = v.Key.substr(prefix.length + 1).replace('/', '.');
if (v.Value) {
try {
let item = JSON.parse(v.Value);
this._changes.set(k, item);
this._allkeys.add(k);
}
catch (e) {
system_1.System.log.info(null, "CONFIG: Consul configuration source : Invalid json value for property " + k);
}
}
if (v.ModifyIndex > max)
max = v.ModifyIndex;
});
// Remove deleted keys
let keys = Array.from(this._allkeys.keys());
for (let key of keys) {
if (!this._changes.has(key)) {
this._changes.set(key, null);
this._allkeys.delete(key);
}
}
return max;
}
watchDefinitionsChanges() {
this.globalWatch = this.watchChanges(this.globalKeys);
if (this.serviceKey)
this.serviceWatch = this.watchChanges(this.serviceKey);
}
watchChanges(key) {
let self = this;
let watch = this.consul.watch({ method: this.consul.kv.get, options: { key: key, recurse: true } });
// TODO modifyIndex
watch.on('change', function (data, res) {
data && system_1.System.log.info(null, "CONFIG: Detecting changes on configuration properties for consul key " + key);
data && self.merge(key, data);
});
watch.on('error', function (err) {
system_1.System.log.error(null, err, "CONFIG: Error when watching configurations for " + key);
self.globalWatch.end();
self.serviceWatch && self.serviceWatch.end();
self._initialized = false;
});
return watch;
}
}
exports.ConsulConfigurationSource = ConsulConfigurationSource;
//# sourceMappingURL=consulConfigurationSource.js.map