UNPKG

dl

Version:

DreamLab Libs

491 lines (402 loc) 16.7 kB
var core = require('core'); var flat = require('flat'); var CredentialsProvider = core.credentials.CredentialsProvider; var Event = core.event.Event; var EventDispatcher = core.event.EventDispatcher; var Random = core.common.Random; var Types = core.common.Types; var PackageJson = require('../../package.json'); var RbmqMessage = core.client.rabbitmq.RbmqMessage; var QueueProduct = require('./QueueVersion').QueueProduct; var QueueVersion = require('./QueueVersion').QueueVersion; var QueueIncomingMessageProcessor = require('./QueueIncomingMessageProcessor.js').QueueIncomingMessageProcessor; // helpers var configValue = function (config, path, defaultValue) { var val = config; var pathArr = path.split('.'); for (var i = 0, l = pathArr.length; i < l; i++) { if (val.hasOwnProperty(pathArr[i])) { val = val[pathArr[i]]; } else { val = undefined; break; } } return (val !== undefined) ? val : defaultValue; }; var ensureSimpleValue = function (value, errorMessage) { if (value === undefined) { throw new Error(errorMessage); } return value; }; var ensureConfigValue = function (config, path, errorMessage) { return ensureSimpleValue(configValue(config, path), errorMessage); }; var filterUndefined = function (config) { if (!config) { return; } var keys = Object.keys(config); for (var i = 0, l = keys.length; i < l; i++) { if (config[keys[i]] === undefined) { delete config[keys[i]]; } } return config; }; var hostMapFnc = function (item) { return [item.host, item.port].join('_'); }; // end of helpers var QueueCredentials = function(credentialsProvider) { EventDispatcher.call(this); this._cp = credentialsProvider; this._credentials = null; this._parsedConfig = null; }; QueueCredentials.prototype = Object.create(EventDispatcher.prototype); QueueCredentials.prototype.getCredentialId = function() { return this._cp.getCredentialId(); }; QueueCredentials.prototype.load = function() { var that = this; function attachListeners() { that._cp.addEventListener(CredentialsProvider.Event.LOAD, that._onCredentialLoaded, that); that._cp.addEventListener(CredentialsProvider.Event.ERROR, that._onCredentialError, that); that._cp.addEventListener(CredentialsProvider.Event.TIMEOUT, that._onCredentialTimeout, that); } if (this._cp._refreshInProgress) { attachListeners(); } else { this._cp.get(function(err, data) { attachListeners(); if (!err && data && !that._credentials) { that._onCredentialLoaded({data: data}); } else { that._cp.refresh(); } }); } }; QueueCredentials.prototype._onCredentialLoaded = function(ev) { ev.data = flat.unflatten(ev.data); if (!this._credentials) { this._credentials = {}; } var reload = false; var data = JSON.parse(JSON.stringify(ev.data)); if (!data.hosts || !Types.isArray(data.hosts) || data.hosts.length === 0) { console.error('QueueCredentials/_onCredentialLoaded null or empty hosts list!'); return; } var hosts = data.hosts.map(hostMapFnc).sort(); /* usuwam klucz z konfiguracji */ delete data.hosts; /* dane kolejki */ var config = data; /* sprawdzanie hostow */ if (!this._credentials.hosts) { /* connect */ reload = true; } else if (this._credentials.hosts != hosts) { /* hosts changed */ reload = true; } //FIXME: sometime... var configChanged = false; /* sprawdzanie konfiguracji kolejki/exchange */ if (!this._credentials.config) { reload = true; } else if (JSON.stringify(this._credentials.config) != JSON.stringify(config)) { reload = true; configChanged = true; } /* wpisanie nowych wartosci */ this._credentials.hosts = hosts; this._credentials.config = config; console.log('QueueCredentials/_onCredentialLoaded: reload=%s', reload, this.getCredentialId()); if (reload) { try { this._parsedConfig = this._parseConfig(this._credentials.config); } catch (err) { console.error('QueueCredentials/_onCredentialLoaded failed to parse configuration:', err.message); return; } //FIXME: sometime... if (configChanged) { this._parsedConfig.connection.forceReconnect = true; } else { this._parsedConfig.connection.forceReconnect = false; } this.dispatchEvent(new Event(QueueCredentials.Event.LOADED)); } }; QueueCredentials.prototype._onCredentialError = function(ev) { console.error('QueueCredentials/_onCredentialsError:', ev.data); }; QueueCredentials.prototype._onCredentialTimeout = function(ev) { console.error('QueueCredentials/_onCredentialTimeout:', ev.data); }; QueueCredentials.prototype._parseConfig = function(config) { if (config.hasOwnProperty('qaas') && config.qaas.hasOwnProperty('version')) { return this['_parseConfigV' + config.qaas.version](config); } return this._parseLegacyConfig(config); }; QueueCredentials.prototype._parseMonitoringConfig = function (config) { return { key: configValue(config, 'monitoring.key', null), prefix: configValue(config, 'monitoring.prefix', null) }; }; QueueCredentials.prototype._parseLoggingConfig = function(config) { return { connection: configValue(config, 'logging.connection', true), subscribe: configValue(config, 'logging.subscribe', false), publish: configValue(config, 'logging.publish', false) }; }; QueueCredentials.prototype._parseClientProperties = function(config) { return { product: QueueProduct, version: QueueVersion, dl: PackageJson.version, 'x-onet-app': ensureSimpleValue(process.env['OPAL_IDENTITY'], 'Cannot determine OPAL_IDENTITY environment variable. Forgot to set?'), 'x-onet-segment': ensureSimpleValue(process.env['ONET_SEGMENT'], 'Cannot determine ONET_SEGMENT environment variable. Forgot to set?'), datasource: this.getCredentialId(), configVersion: ensureConfigValue(config, 'qaas.version', 'Cannot determine config version. It should never happen!'), capabilities: { exchange_exchange_bindings: true, consumer_cancel_notify: true, 'connection.blocked': true } }; }; QueueCredentials.prototype._parseConnectionConfig = function(config) { return { login: ensureConfigValue(config, 'connection.login', 'Cannot find connection.login in configuration'), password: ensureConfigValue(config, 'connection.password', 'Cannot find connection.password in configuration'), vhost: configValue(config, 'connection.vhost', QueueCredentials.DEFAULT_VHOST), heartbeat: configValue(config, 'connection.heartbeat', QueueCredentials.DEFAULT_HEARTBEAT), timeout: configValue(config, 'connection.timeout', QueueCredentials.DEFAULT_CONNECTION_TIMEOUT), noDelay: configValue(config, 'connection.noDelay', true), clientProperties: this._parseClientProperties(config) }; }; QueueCredentials.prototype._parseExchangeConfig = function(config) { if (!config) { return; } return filterUndefined({ name: ensureConfigValue(config, 'name', 'Cannot find exchange.name in configuration'), durable: configValue(config, 'durable', true), autoDelete: configValue(config, 'autoDelete', false), passive: configValue(config, 'passive', false), type: configValue(config, 'type', QueueCredentials.DEFAULT_EXCHANGE_TYPE), noDeclare: configValue(config, 'noDeclare', false), bindings: configValue(config, 'bindings', []), alternateExchange: configValue(config, 'alternateExchange'), publish: { confirm: configValue(config, 'publish.confirm', true), routingKey: configValue(config, 'publish.routingKey', QueueCredentials.DEFAULT_EXCHANGE_PUBLISH_ROUTING_KEY), deliveryMode: configValue(config, 'publish.deliveryMode', RbmqMessage.Options.DMODE_PERSISTENT), messageSizeLimit: configValue(config, 'publish.messageSizeLimit', QueueCredentials.DEFAULT_MESSAGE_SIZE_LIMIT) } }); }; QueueCredentials.prototype._parseQueueConfig = function(config) { if (!config) { return; } var result = filterUndefined({ name: ensureConfigValue(config, 'name', 'Cannot find queue.name in configuration'), durable: configValue(config, 'durable', true), autoDelete: configValue(config, 'autoDelete', false), passive: configValue(config, 'passive', false), exclusive: configValue(config, 'exclusive', false), subscribe: { ack: configValue(config, 'subscribe.ack', true), prefetchCount: configValue(config, 'subscribe.prefetchCount', 0) }, bindings: configValue(config, 'bindings', []), noDeclare: configValue(config, 'noDeclare', false), ttl: configValue(config, 'ttl'), }); if (result.exclusive) { result.name = [result.name, Random.randomString(10, '0123456789')].join('.'); } if (config.hasOwnProperty('postpone')) { result.postpone = filterUndefined({ method: configValue(config, 'postpone.method', QueueCredentials.DEFAULT_QUEUE_POSTPONE_METHOD), skip: configValue(config, 'postpone.skip', []), strategy: configValue(config, 'postpone.strategy'), factor: configValue(config, 'postpone.factor'), exchange: filterUndefined(this._parseExchangeConfig(config.postpone.exchange)) }); if (result.postpone.method == QueueIncomingMessageProcessor.POSTPONE_METHOD.DLE) { result.deadLetterExchange = configValue(result, 'postpone.exchange.name'); result.deadLetterRoutingKey = configValue(result, 'postpone.exchange.publish.routingKey'); } } return filterUndefined(result); }; QueueCredentials.prototype._parseConfigV3 = function(config) { console.log('QueueCredentials/_parseConfigV3', this.getCredentialId()); if (config.qaas.version == 3 && config.qaas.hasOwnProperty('v3')) { config = config.qaas.v3; } var result = filterUndefined({ connection: this._parseConnectionConfig(config), logging: this._parseLoggingConfig(config), monitoring: this._parseMonitoringConfig(config), exchange: this._parseExchangeConfig(config.exchange), queue: this._parseQueueConfig(config.queue) }); if (result.hasOwnProperty('exchange') && result.exchange.publish.confirm) { result.connection.clientProperties.capabilities['publisher_confirms'] = true; } return result; }; //FIXME: remove when legacy cluster is dead QueueCredentials.prototype._parseConfigV2 = function(config) { console.log('QueueCredentials/_parseConfigV2'); if (config.qaas.hasOwnProperty('v2')) { config = config.qaas.v2; } if (config.hasOwnProperty('queue') && config.queue.hasOwnProperty('postponer') && !Types.isObject(config.queue.postponer)) { if (!config.queue.hasOwnProperty('postpone')) { config.queue.postpone = {}; } config.queue.postpone.exchange = { name: 'postponer.' + config.queue.postponer }; } var result = this._parseConfigV3(config); if (result.hasOwnProperty('exchange') && config.exchange.hasOwnProperty('policy')) { result.exchange.name = [config.exchange.policy, result.exchange.name].join('.'); } if (result.hasOwnProperty('queue') && config.queue.hasOwnProperty('policy')) { result.queue.name = [config.queue.policy, result.queue.name].join('.'); if (result.queue.hasOwnProperty('postpone')) { if (Types.isObject(config.queue.postponer) && config.queue.postponer.hasOwnProperty('policy')) { result.queue.postpone.exchange.name = [config.queue.postponer.policy, result.queue.postpone.exchange.name].join('.'); } if (!config.queue.hasOwnProperty('postponer') || !config.queue.postponer.hasOwnProperty('routingKey')) { result.queue.postpone.exchange.publish.routingKey = '_postpone_' + result.queue.name + '_'; } result.queue.bindings.push({ exchange: 'postponer.postpone', routingKey: result.queue.postpone.exchange.publish.routingKey }); } } return result; }; //FIXME: remove when legacy cluster is dead QueueCredentials.prototype._parseLegacyConfig = function(config) { console.log('QueueCredentials/_parseLegacyConfig'); var result = { connection: { login: config.user, password: config.pass, vhost: config.vhost || QueueCredentials.DEFAULT_VHOST, heartbeat: config.heartbeat || QueueCredentials.DEFAULT_HEARTBEAT, clientProperties: { product: 'dl-queue-legacy', version: QueueVersion + '-' + PackageJson.version, 'x-onet-app': process.env['OPAL_IDENTITY'] || 'unauthorized-app.unknown.onetapi.pl', 'x-onet-segment': process.env['ONET_SEGMENT'] || 'UNKNOWN', datasource: this.getCredentialId(), configVersion: 'legacy' } }, logging: { connection: true, subscribe: true, publish: true } }; result.exchange = { name: config.exchange, durable: (config.exchange_durable === 0) ? false : true, autoDelete: config.exchange_autodelete ? true : false, passive: config.exchange_passive ? true : false, type: config.exchange_type || 'topic', bindings: [], publish: { confirm: true, deliveryMode: RbmqMessage.Options.DMODE_PERSISTENT } }; var queueSuffix = config.queue_suffix; var queueName = config.exchange + '_' + (queueSuffix ? queueSuffix : Random.randomString(10)); result.queue = { name: queueName, durable: (config.queue_durable === 0) ? false : true, autoDelete: config.queue_auto_delete ? true : false, passive: config.queue_passive ? true : false, exclusive: config.queue_exclusive ? true : false, subscribe: { ack: true, prefetchCount: 0 }, bindings: [] }; if (Types.isArray(config.routing_key)) { for (var i = 0, l = config.routing_key.length; i < l; i++) { result.queue.bindings.push({ exchange: config.exchange, routingKey: config.routing_key[i] }); } } else { result.queue.bindings = [{ exchange: config.exchange, routingKey: config.routing_key }]; result.exchange.publish.routingKey = config.routing_key; } if (config.prefetch_count) { result.queue.subscribe.prefetchCount = config.prefetch_count; } return result; }; QueueCredentials.prototype.getConnectionConfig = function() { var hosts = this._credentials.hosts; var config = this._parsedConfig.connection; config.hosts = hosts.map(function(hostStr) { var hostArr = hostStr.split('_'); return { host: hostArr[0], port: hostArr[1] }; }); return config; }; QueueCredentials.prototype.getMonitoringConfig = function () { return this._parsedConfig.monitoring; }; QueueCredentials.prototype.getLoggingConfig = function () { return this._parsedConfig.logging; }; QueueCredentials.prototype.getExchangeConfig = function () { return this._parsedConfig.exchange; }; QueueCredentials.prototype.getQueueConfig = function () { return this._parsedConfig.queue; }; QueueCredentials.prototype.destroy = function () { this.removeAllEventListeners(); this._cp.destroy(); }; QueueCredentials.Event = {}; QueueCredentials.Event.LOADED = 'QueueCredentials.Event.LOADED'; QueueCredentials.DEFAULT_MESSAGE_SIZE_LIMIT = 50 * 1024; QueueCredentials.DEFAULT_VHOST = '/'; QueueCredentials.DEFAULT_HEARTBEAT = 5; QueueCredentials.DEFAULT_CONNECTION_TIMEOUT = 500; QueueCredentials.DEFAULT_EXCHANGE_TYPE = 'topic'; QueueCredentials.DEFAULT_EXCHANGE_PUBLISH_ROUTING_KEY = ''; QueueCredentials.DEFAULT_QUEUE_POSTPONE_METHOD = 'reject'; exports.QueueCredentials = QueueCredentials;