@logzio-node-toolbox/consul
Advanced tools
Comparing version 0.0.4 to 0.0.5
import retry from 'async-retry'; | ||
import ConsulLibrary from 'consul'; | ||
import deepMerge from 'deepmerge'; | ||
import 'core-js/modules/esnext.promise.all-settled'; | ||
import 'core-js/modules/esnext.weak-map.delete-all'; | ||
class Consul { | ||
constructor({ port, host = 'localhost', baseUrl = null } = {}) { | ||
constructor({ | ||
port, | ||
host = 'localhost', | ||
baseUrl = null | ||
} = {}) { | ||
if (!port) throw new Error('consul must have port'); | ||
this.consulInstance = new ConsulLibrary({ host, port, promisify: true }); | ||
this.consulInstance = new ConsulLibrary({ | ||
host, | ||
port, | ||
promisify: true | ||
}); | ||
this.keyPrefix = baseUrl ? `${baseUrl.replace(/\/*$/, '')}/` : ''; | ||
this.connectionParams = { | ||
host, | ||
port, | ||
port | ||
}; | ||
this.openWatchersToClose = []; | ||
this.registerParams = { | ||
id: null, | ||
timeoutId: null, | ||
serviceName: null, | ||
serviceName: null | ||
}; | ||
} | ||
async validateConnected({ fail = true, timeout = 5000, retries = 6, factor = 2, onRetry = null }) { | ||
async validateConnected({ | ||
fail = true, | ||
timeout = 5000, | ||
retries = 6, | ||
factor = 2, | ||
onRetry = null | ||
}) { | ||
try { | ||
await retry(async () => this.consulInstance.agent.check.list({ timeout }), { factor, retries, onRetry }); | ||
await retry(async () => this.consulInstance.agent.check.list({ | ||
timeout | ||
}), { | ||
factor, | ||
retries, | ||
onRetry | ||
}); | ||
} catch (err) { | ||
@@ -35,5 +52,7 @@ if (fail) throw new Error(`CONSUL: failed to connect to consul after ${retries + 1} attempts with message: ${err.message}`); | ||
parseValue({ Value = null, Key = null } = {}) { | ||
parseValue({ | ||
Value = null, | ||
Key = null | ||
} = {}) { | ||
if (!Key || !Value) return undefined; | ||
let value; | ||
@@ -49,3 +68,3 @@ | ||
key: Key, | ||
value, | ||
value | ||
}; | ||
@@ -72,25 +91,27 @@ } | ||
const configValues = await this.get(key); | ||
const currentValues = configValues ? configValues.value : {}; | ||
const newValues = deepMerge(currentValues, values); | ||
await this.set(key, newValues); | ||
return newValues; | ||
} | ||
watch({ key, onChange, onError, backoffFactor = 100, backoffMax = 30000, maxAttempts = 10000 } = {}) { | ||
watch({ | ||
key, | ||
onChange, | ||
onError, | ||
backoffFactor = 100, | ||
backoffMax = 30000, | ||
maxAttempts = 10000 | ||
} = {}) { | ||
if (!key || !onChange) return; | ||
const options = { | ||
method: this.consulInstance.kv.get, | ||
options: { key: this.buildKey(key) }, | ||
options: { | ||
key: this.buildKey(key) | ||
}, | ||
backoffFactor, | ||
backoffMax, | ||
maxAttempts, | ||
maxAttempts | ||
}; | ||
const watcher = this.consulInstance.watch(options); | ||
watcher.on('change', data => data && onChange(this.parseValue(data))); | ||
@@ -101,7 +122,14 @@ watcher.on('error', err => err && onError(err)); | ||
async register({ meta, checks, address, hostname, serviceName, port, interval = null, onErorr } = {}) { | ||
async register({ | ||
meta, | ||
checks, | ||
address, | ||
hostname, | ||
serviceName, | ||
port, | ||
interval = null, | ||
onErorr | ||
} = {}) { | ||
if (!serviceName || !hostname) throw new Error('must provide serviceName and hostname to service discovery'); | ||
if (this.registerParams.id) return; | ||
const options = { | ||
@@ -113,3 +141,3 @@ id: hostname, | ||
meta, | ||
checks, | ||
checks | ||
}; | ||
@@ -119,8 +147,8 @@ | ||
const list = await retry(async () => this.consulInstance.agent.service.list(), this.retry); | ||
const isRegistered = Object.entries(list).some(([id, { | ||
Service | ||
}]) => id === hostname && Service === serviceName); | ||
const isRegistered = Object.entries(list).some(([id, { Service }]) => id === hostname && Service === serviceName); | ||
if (!isRegistered) { | ||
await retry(async () => this.consulInstance.agent.service.register(options), this.retry); | ||
this.registerParams.id = hostname; | ||
@@ -133,3 +161,2 @@ } | ||
await invokeRegister(); | ||
if (interval) this.registerParams.timeoutId = setTimeout(startRegisterInterval, interval); | ||
@@ -142,3 +169,2 @@ } catch (err) { | ||
await invokeRegister(); | ||
startRegisterInterval(); | ||
@@ -152,39 +178,96 @@ } | ||
} | ||
this.openWatchersToClose.forEach(watcher => watcher.end()); | ||
} | ||
} | ||
function _classPrivateFieldGet(receiver, privateMap) { | ||
var descriptor = privateMap.get(receiver); | ||
if (!descriptor) { | ||
throw new TypeError("attempted to get private field on non-instance"); | ||
} | ||
if (descriptor.get) { | ||
return descriptor.get.call(receiver); | ||
} | ||
return descriptor.value; | ||
} | ||
function _classPrivateFieldSet(receiver, privateMap, value) { | ||
var descriptor = privateMap.get(receiver); | ||
if (!descriptor) { | ||
throw new TypeError("attempted to set private field on non-instance"); | ||
} | ||
if (descriptor.set) { | ||
descriptor.set.call(receiver, value); | ||
} else { | ||
if (!descriptor.writable) { | ||
throw new TypeError("attempted to set read only private field"); | ||
} | ||
descriptor.value = value; | ||
} | ||
return value; | ||
} | ||
var _paths = new WeakMap(); | ||
var _mergedValues = new WeakMap(); | ||
class MultiConsul extends Consul { | ||
#paths; | ||
constructor({ | ||
paths = [], | ||
...consulOptions | ||
} = {}) { | ||
super(consulOptions); | ||
#mergedValues; | ||
constructor({ paths = [], ...consulOptions } = {}) { | ||
super(consulOptions); | ||
this.#paths = paths; | ||
_paths.set(this, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_mergedValues.set(this, { | ||
writable: true, | ||
value: null | ||
}); | ||
_classPrivateFieldSet(this, _paths, paths); | ||
let p = 1; | ||
this.values = paths.reduce((acc, path) => { | ||
acc[path] = { p, value: {} }; | ||
acc[this.buildKey(path)] = { | ||
p, | ||
value: {} | ||
}; | ||
p++; | ||
return acc; | ||
}, {}); | ||
this.#mergedValues; | ||
} | ||
_mergeAll() { | ||
const values = Object.values(this.values) | ||
.sort((a, b) => a.p - b.p) | ||
.map(({ value }) => value); | ||
const values = Object.values(this.values).sort((a, b) => a.p - b.p).map(({ | ||
value | ||
}) => value); | ||
this.#mergedValues = deepMerge.all(values); | ||
return this.#mergedValues; | ||
_classPrivateFieldSet(this, _mergedValues, deepMerge.all(values)); | ||
return _classPrivateFieldGet(this, _mergedValues); | ||
} | ||
async load() { | ||
const data = await Promise.allSettled(this.#paths.map(path => this.get(path))); | ||
data.forEach(({ value: { value, key } = {} }) => { | ||
if (key && value) this.values[key].value = value; | ||
const data = await Promise.allSettled(_classPrivateFieldGet(this, _paths).map(path => this.get(path))); | ||
data.forEach(({ | ||
value: { | ||
value, | ||
key | ||
} = {} | ||
}) => { | ||
if (value && key) this.values[key].value = value; | ||
}); | ||
return this._mergeAll(); | ||
@@ -194,8 +277,10 @@ } | ||
async getAll() { | ||
if (!this.#mergedValues) await this.load(); | ||
return this.#mergedValues; | ||
if (!_classPrivateFieldGet(this, _mergedValues)) await this.load(); | ||
return _classPrivateFieldGet(this, _mergedValues); | ||
} | ||
async _onOneChange({ key, value }) { | ||
async _onOneChange({ | ||
key, | ||
value | ||
}) { | ||
this.values[key].value = value; | ||
@@ -205,16 +290,28 @@ return this._mergeAll(); | ||
async watchAll({ onChange, onError }) { | ||
this.#paths.forEach(path => | ||
this.watch({ | ||
key: path, | ||
onError, | ||
onChange: async ({ key, value }) => { | ||
await this._onOneChange({ key, value }); | ||
onChange({ key, changedValue: value, value: this.#mergedValues }); | ||
}, | ||
}), | ||
); | ||
async watchAll({ | ||
onChange, | ||
onError | ||
}) { | ||
_classPrivateFieldGet(this, _paths).forEach(path => this.watch({ | ||
key: path, | ||
onError, | ||
onChange: async ({ | ||
key, | ||
value | ||
}) => { | ||
await this._onOneChange({ | ||
key, | ||
value | ||
}); | ||
onChange({ | ||
key, | ||
changedValue: value, | ||
value: _classPrivateFieldGet(this, _mergedValues) | ||
}); | ||
} | ||
})); | ||
} | ||
} | ||
export { Consul, MultiConsul }; |
@@ -8,2 +8,4 @@ 'use strict'; | ||
var deepMerge = require('deepmerge'); | ||
require('core-js/modules/esnext.promise.all-settled'); | ||
require('core-js/modules/esnext.weak-map.delete-all'); | ||
@@ -17,26 +19,41 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
class Consul { | ||
constructor({ port, host = 'localhost', baseUrl = null } = {}) { | ||
constructor({ | ||
port, | ||
host = 'localhost', | ||
baseUrl = null | ||
} = {}) { | ||
if (!port) throw new Error('consul must have port'); | ||
this.consulInstance = new ConsulLibrary__default['default']({ host, port, promisify: true }); | ||
this.consulInstance = new ConsulLibrary__default['default']({ | ||
host, | ||
port, | ||
promisify: true | ||
}); | ||
this.keyPrefix = baseUrl ? `${baseUrl.replace(/\/*$/, '')}/` : ''; | ||
this.connectionParams = { | ||
host, | ||
port, | ||
port | ||
}; | ||
this.openWatchersToClose = []; | ||
this.registerParams = { | ||
id: null, | ||
timeoutId: null, | ||
serviceName: null, | ||
serviceName: null | ||
}; | ||
} | ||
async validateConnected({ fail = true, timeout = 5000, retries = 6, factor = 2, onRetry = null }) { | ||
async validateConnected({ | ||
fail = true, | ||
timeout = 5000, | ||
retries = 6, | ||
factor = 2, | ||
onRetry = null | ||
}) { | ||
try { | ||
await retry__default['default'](async () => this.consulInstance.agent.check.list({ timeout }), { factor, retries, onRetry }); | ||
await retry__default['default'](async () => this.consulInstance.agent.check.list({ | ||
timeout | ||
}), { | ||
factor, | ||
retries, | ||
onRetry | ||
}); | ||
} catch (err) { | ||
@@ -47,5 +64,7 @@ if (fail) throw new Error(`CONSUL: failed to connect to consul after ${retries + 1} attempts with message: ${err.message}`); | ||
parseValue({ Value = null, Key = null } = {}) { | ||
parseValue({ | ||
Value = null, | ||
Key = null | ||
} = {}) { | ||
if (!Key || !Value) return undefined; | ||
let value; | ||
@@ -61,3 +80,3 @@ | ||
key: Key, | ||
value, | ||
value | ||
}; | ||
@@ -84,25 +103,27 @@ } | ||
const configValues = await this.get(key); | ||
const currentValues = configValues ? configValues.value : {}; | ||
const newValues = deepMerge__default['default'](currentValues, values); | ||
await this.set(key, newValues); | ||
return newValues; | ||
} | ||
watch({ key, onChange, onError, backoffFactor = 100, backoffMax = 30000, maxAttempts = 10000 } = {}) { | ||
watch({ | ||
key, | ||
onChange, | ||
onError, | ||
backoffFactor = 100, | ||
backoffMax = 30000, | ||
maxAttempts = 10000 | ||
} = {}) { | ||
if (!key || !onChange) return; | ||
const options = { | ||
method: this.consulInstance.kv.get, | ||
options: { key: this.buildKey(key) }, | ||
options: { | ||
key: this.buildKey(key) | ||
}, | ||
backoffFactor, | ||
backoffMax, | ||
maxAttempts, | ||
maxAttempts | ||
}; | ||
const watcher = this.consulInstance.watch(options); | ||
watcher.on('change', data => data && onChange(this.parseValue(data))); | ||
@@ -113,7 +134,14 @@ watcher.on('error', err => err && onError(err)); | ||
async register({ meta, checks, address, hostname, serviceName, port, interval = null, onErorr } = {}) { | ||
async register({ | ||
meta, | ||
checks, | ||
address, | ||
hostname, | ||
serviceName, | ||
port, | ||
interval = null, | ||
onErorr | ||
} = {}) { | ||
if (!serviceName || !hostname) throw new Error('must provide serviceName and hostname to service discovery'); | ||
if (this.registerParams.id) return; | ||
const options = { | ||
@@ -125,3 +153,3 @@ id: hostname, | ||
meta, | ||
checks, | ||
checks | ||
}; | ||
@@ -131,8 +159,8 @@ | ||
const list = await retry__default['default'](async () => this.consulInstance.agent.service.list(), this.retry); | ||
const isRegistered = Object.entries(list).some(([id, { | ||
Service | ||
}]) => id === hostname && Service === serviceName); | ||
const isRegistered = Object.entries(list).some(([id, { Service }]) => id === hostname && Service === serviceName); | ||
if (!isRegistered) { | ||
await retry__default['default'](async () => this.consulInstance.agent.service.register(options), this.retry); | ||
this.registerParams.id = hostname; | ||
@@ -145,3 +173,2 @@ } | ||
await invokeRegister(); | ||
if (interval) this.registerParams.timeoutId = setTimeout(startRegisterInterval, interval); | ||
@@ -154,3 +181,2 @@ } catch (err) { | ||
await invokeRegister(); | ||
startRegisterInterval(); | ||
@@ -164,39 +190,96 @@ } | ||
} | ||
this.openWatchersToClose.forEach(watcher => watcher.end()); | ||
} | ||
} | ||
function _classPrivateFieldGet(receiver, privateMap) { | ||
var descriptor = privateMap.get(receiver); | ||
if (!descriptor) { | ||
throw new TypeError("attempted to get private field on non-instance"); | ||
} | ||
if (descriptor.get) { | ||
return descriptor.get.call(receiver); | ||
} | ||
return descriptor.value; | ||
} | ||
function _classPrivateFieldSet(receiver, privateMap, value) { | ||
var descriptor = privateMap.get(receiver); | ||
if (!descriptor) { | ||
throw new TypeError("attempted to set private field on non-instance"); | ||
} | ||
if (descriptor.set) { | ||
descriptor.set.call(receiver, value); | ||
} else { | ||
if (!descriptor.writable) { | ||
throw new TypeError("attempted to set read only private field"); | ||
} | ||
descriptor.value = value; | ||
} | ||
return value; | ||
} | ||
var _paths = new WeakMap(); | ||
var _mergedValues = new WeakMap(); | ||
class MultiConsul extends Consul { | ||
#paths; | ||
constructor({ | ||
paths = [], | ||
...consulOptions | ||
} = {}) { | ||
super(consulOptions); | ||
#mergedValues; | ||
constructor({ paths = [], ...consulOptions } = {}) { | ||
super(consulOptions); | ||
this.#paths = paths; | ||
_paths.set(this, { | ||
writable: true, | ||
value: void 0 | ||
}); | ||
_mergedValues.set(this, { | ||
writable: true, | ||
value: null | ||
}); | ||
_classPrivateFieldSet(this, _paths, paths); | ||
let p = 1; | ||
this.values = paths.reduce((acc, path) => { | ||
acc[path] = { p, value: {} }; | ||
acc[this.buildKey(path)] = { | ||
p, | ||
value: {} | ||
}; | ||
p++; | ||
return acc; | ||
}, {}); | ||
this.#mergedValues; | ||
} | ||
_mergeAll() { | ||
const values = Object.values(this.values) | ||
.sort((a, b) => a.p - b.p) | ||
.map(({ value }) => value); | ||
const values = Object.values(this.values).sort((a, b) => a.p - b.p).map(({ | ||
value | ||
}) => value); | ||
this.#mergedValues = deepMerge__default['default'].all(values); | ||
return this.#mergedValues; | ||
_classPrivateFieldSet(this, _mergedValues, deepMerge__default['default'].all(values)); | ||
return _classPrivateFieldGet(this, _mergedValues); | ||
} | ||
async load() { | ||
const data = await Promise.allSettled(this.#paths.map(path => this.get(path))); | ||
data.forEach(({ value: { value, key } = {} }) => { | ||
if (key && value) this.values[key].value = value; | ||
const data = await Promise.allSettled(_classPrivateFieldGet(this, _paths).map(path => this.get(path))); | ||
data.forEach(({ | ||
value: { | ||
value, | ||
key | ||
} = {} | ||
}) => { | ||
if (value && key) this.values[key].value = value; | ||
}); | ||
return this._mergeAll(); | ||
@@ -206,8 +289,10 @@ } | ||
async getAll() { | ||
if (!this.#mergedValues) await this.load(); | ||
return this.#mergedValues; | ||
if (!_classPrivateFieldGet(this, _mergedValues)) await this.load(); | ||
return _classPrivateFieldGet(this, _mergedValues); | ||
} | ||
async _onOneChange({ key, value }) { | ||
async _onOneChange({ | ||
key, | ||
value | ||
}) { | ||
this.values[key].value = value; | ||
@@ -217,14 +302,26 @@ return this._mergeAll(); | ||
async watchAll({ onChange, onError }) { | ||
this.#paths.forEach(path => | ||
this.watch({ | ||
key: path, | ||
onError, | ||
onChange: async ({ key, value }) => { | ||
await this._onOneChange({ key, value }); | ||
onChange({ key, changedValue: value, value: this.#mergedValues }); | ||
}, | ||
}), | ||
); | ||
async watchAll({ | ||
onChange, | ||
onError | ||
}) { | ||
_classPrivateFieldGet(this, _paths).forEach(path => this.watch({ | ||
key: path, | ||
onError, | ||
onChange: async ({ | ||
key, | ||
value | ||
}) => { | ||
await this._onOneChange({ | ||
key, | ||
value | ||
}); | ||
onChange({ | ||
key, | ||
changedValue: value, | ||
value: _classPrivateFieldGet(this, _mergedValues) | ||
}); | ||
} | ||
})); | ||
} | ||
} | ||
@@ -231,0 +328,0 @@ |
{ | ||
"name": "@logzio-node-toolbox/consul", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "Consul easy use for json configs and service discovery", | ||
"main": "dist/index.js", | ||
"module": "dist/index.es.js", | ||
"files": ["dist"], | ||
"exports": { | ||
"import": "./dist/index.es.js", | ||
"require": "./dist/index.js" | ||
}, | ||
"types": "dist/index.d.ts", | ||
"type": "module", | ||
"files": ["dist"], | ||
"license": "MIT", | ||
@@ -26,2 +29,3 @@ "author": "Nir winkler <madvinking@gmail.com>", | ||
"dependencies": { | ||
"core-js": "3.6.5", | ||
"async-retry": "1.3.1", | ||
@@ -28,0 +32,0 @@ "consul": "0.37.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20190
588
4
+ Addedcore-js@3.6.5
+ Addedcore-js@3.6.5(transitive)