dl
Version:
DreamLab Libs
211 lines (160 loc) • 6.39 kB
JavaScript
var core = require('core');
var path = require('path');
var Event = core.event.Event;
var EventDispatcher = core.event.EventDispatcher;
var Types = core.common.Types;
var ZooKeeperDataProvider = require('../dataprovider/ZooKeeperDataProvider.js').ZooKeeperDataProvider;
var instances = {};
var dataProvider = null;
var dataProviderInitialized = false;
var dataProviderCallbacks = [];
var ConfigServiceClient = function (application, segment) {
return ConfigServiceClient.getInstance(application, segment);
};
ConfigServiceClient.getInstance = function (application, segment) {
// segment '' is good as well as any other :)
application = application || ConfigServiceClient._getMyIdentity();
segment = (segment !== undefined) ? segment : ConfigServiceClient._getMySegment();
if (!application || (segment === undefined)) {
//TODO: jakas walidacja _application / _segment
throw new Error('Cannot determine application or segment');
}
var instanceId = application + '_' + segment;
if (!instances.hasOwnProperty(instanceId)) {
instances[instanceId] = ConfigServiceClient.createInstance(application, segment);
}
return instances[instanceId];
};
ConfigServiceClient._getMyIdentity = function () {
if (process.env['OPAL_IDENTITY']) {
var L = process.env['OPAL_IDENTITY'].split('.').reverse();
return [L[2], L[3]].join('/');
}
};
ConfigServiceClient._getMySegment = function () {
return process.env['ONET_SEGMENT'];
};
ConfigServiceClient.createInstance = function (application, segment) {
var obj = Object.create(ConfigServiceClient.prototype);
EventDispatcher.call(obj);
obj._initialized = false;
obj._application = application;
obj._segment = segment;
obj._suffix = ConfigServiceClient.SUFFIX;
obj.data = null;
obj.dataTimestamp = null;
obj.stat = null;
obj._refreshTimer = null;
obj._refreshTimeout = ConfigServiceClient.DEFAULT_RETRY_WATCH_TIMEOUT;
obj._watchCreated = false;
obj._watchers = [];
if (!dataProvider) {
dataProvider = new ZooKeeperDataProvider({
credential: ConfigServiceClient.DS_ALIAS,
identity: ConfigServiceClient.DS_AUTH
});
}
obj._dataProvider = dataProvider;
return obj;
};
ConfigServiceClient.prototype = Object.create(EventDispatcher.prototype);
ConfigServiceClient.prototype._getKey = function(suffix) {
suffix = (suffix === undefined) ? this._suffix : suffix;
if (this._segment) {
return path.join(ConfigServiceClient.APPS_ROOT_PATH, this._application, 'segments', this._segment, suffix);
} else {
return path.join(ConfigServiceClient.APPS_ROOT_PATH, this._application, suffix);
}
};
ConfigServiceClient.prototype.start = function() {
if (this._initialized) {
console.warn('ConfigServiceClient/start', this._application, 'already started');
return;
}
if (!dataProviderInitialized) {
dataProvider.init(function() {
console.log('ConfigServiceClient/ready');
}, function() {
console.log('ConfigServiceClient/reload');
for (var i = 0, l = dataProviderCallbacks.length; i < l; i++) {
dataProviderCallbacks[i]();
}
});
dataProviderInitialized = true;
}
var appIdentity = ConfigServiceClient._getMyIdentity();
var appService = appIdentity.split('/')[0];
dataProvider.addAuth('digest', 'srv/' + appService + ':');
dataProvider.addAuth('digest', 'app/' + appIdentity + ':');
dataProviderCallbacks.push(this._watchForData.bind(this));
if (dataProvider.isConnected()) {
this._watchForData();
}
this._initialized = true;
};
ConfigServiceClient.prototype._watchForData = function() {
var key = this._getKey();
var that = this;
if (this._watchCreated) {
console.log('ConfigServiceClient/watch already created for', key);
return;
}
console.log('ConfigServiceClient/creating watch for', key);
dataProvider.watch(key, function(err, data, stat) {
if (err) {
console.error('ConfigServiceClient/error creating watch for', key, ':', err);
that._scheduleRetryWatch();
that._watchCreated = false;
that.dispatchEvent(new Event(ConfigServiceClient.Event.ERROR, err));
return;
} else {
that._resetRetryWatch();
that._watchCreated = true;
}
if (Types.isString(data)) {
that.data = JSON.parse(data);
} else {
that.data = data;
}
that.dataTimestamp = Date.now();
that.stat = stat;
console.log('ConfigServiceClient/watch for', key, 'data fetched');
that.dispatchEvent(new Event(ConfigServiceClient.Event.LOADED));
});
};
ConfigServiceClient.prototype._resetRetryWatch = function() {
if (this._refreshTimer) {
clearTimeout(this._refreshTimer);
}
this._refreshTimer = null;
this._refreshTimeout = ConfigServiceClient.DEFAULT_RETRY_WATCH_TIMEOUT;
};
ConfigServiceClient.prototype._scheduleRetryWatch = function() {
var that = this;
this._refreshTimeout *= 1.05;
this._refreshTimer = setTimeout(function() {
that._refreshTimer = null;
that._watchForData();
}, this._refreshTimeout);
};
ConfigServiceClient.prototype.getData = function(noThrow) {
if (!this.data && !noThrow) {
throw new Error('Config data not yet loaded');
}
return JSON.parse(JSON.stringify(this.data));
};
ConfigServiceClient.prototype.getDataTimestamp = function(noThrow) {
if ((!this.dataTimestamp || !this.data) && !noThrow) {
throw new Error('Config data not yet loaded');
}
return this.dataTimestamp;
};
ConfigServiceClient.DS_ALIAS = 'configservice.zookeeper-a2.configuration.onetapi.pl';
ConfigServiceClient.DS_AUTH = 'client.configservice.zookeeper.configuration.onetapi.pl';
ConfigServiceClient.APPS_ROOT_PATH = '/onetapi.pl/';
ConfigServiceClient.SUFFIX = 'settings.json';
ConfigServiceClient.DEFAULT_RETRY_WATCH_TIMEOUT = 476;
ConfigServiceClient.Event = {};
ConfigServiceClient.Event.LOADED = 'ConfigServiceClient.Event.LOADED';
ConfigServiceClient.Event.ERROR = 'ConfigServiceClient.Event.ERROR';
exports.ConfigServiceClient = ConfigServiceClient;