@creditkarma/consul-client
Version:
A client for Hashicorp Consul written in TypeScript
200 lines • 8.32 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Catalog = void 0;
const logger = require("../logger");
const Observer_1 = require("../Observer");
const Utils = require("../utils");
const ConsulClient_1 = require("./ConsulClient");
class Catalog {
constructor(consulAddresses = Utils.defaultAddresses(), baseOptions = {}, maxRetries = 5) {
this.consulAddresses = consulAddresses;
this.baseOptions = {
responseType: 'json',
...baseOptions,
};
this.client = new ConsulClient_1.ConsulClient(this.consulAddresses);
this.watchMap = new Map();
this.maxRetries = maxRetries;
}
registerEntity(service, requestOptions = {}) {
const extendedOptions = Utils.deepMerge(this.baseOptions, requestOptions);
return this.client
.send({
type: "RegisterEntityRequest",
apiVersion: 'v1',
section: 'catalog',
payload: service,
}, extendedOptions)
.then((res) => {
switch (res.statusCode) {
case 200:
return Promise.resolve(res.body);
default:
return Promise.reject(new Error(res.statusMessage));
}
});
}
listNodes(requestOptions = {}) {
const extendedOptions = Utils.deepMerge(this.baseOptions, requestOptions);
return this.client
.send({
type: "ListNodesRequest",
apiVersion: 'v1',
section: 'catalog',
}, extendedOptions)
.then((res) => {
switch (res.statusCode) {
case 200:
return Promise.resolve(res.body);
default:
return Promise.reject(new Error(res.statusMessage));
}
});
}
listServices(requestOptions = {}) {
const extendedOptions = Utils.deepMerge(this.baseOptions, requestOptions);
return this.client
.send({
type: "ListServicesRequest",
apiVersion: 'v1',
section: 'catalog',
}, extendedOptions)
.then((res) => {
switch (res.statusCode) {
case 200:
return Promise.resolve(res.body);
default:
return Promise.reject(new Error(res.statusMessage));
}
});
}
listNodesForService(serviceName, requestOptions = {}) {
const extendedOptions = Utils.deepMerge(this.baseOptions, requestOptions);
const queryMap = Utils.splitQueryMap(serviceName);
const trimmedServiceName = serviceName.split('?')[0];
return this.client
.send({
type: "ListServiceNodesRequest",
apiVersion: 'v1',
section: 'catalog',
serviceName: trimmedServiceName,
dc: queryMap.dc,
service: queryMap.service,
tag: queryMap.tag,
near: queryMap.near,
'node-meta': queryMap['node-meta'],
}, extendedOptions)
.then((res) => {
switch (res.statusCode) {
case 200:
return Promise.resolve(res.body);
default:
return Promise.reject(new Error(res.statusMessage));
}
});
}
resolveAddress(serviceName, requestOptions = {}) {
return this.listNodesForService(serviceName, requestOptions).then((res) => {
if (res.length > 0) {
const ID = Math.floor(Math.random() * res.length);
const pickedNode = res[ID];
const address = pickedNode.Service.Address &&
pickedNode.Service.Address !== ''
? pickedNode.Service.Address
: pickedNode.Node.Address;
const port = pickedNode.Service.Port || 80;
return `${address}:${port}`;
}
else {
throw new Error(`No service found with name[${serviceName}]`);
}
});
}
ignoreAddress(serviceName) {
const observer = this.watchMap.get(serviceName);
if (observer !== undefined) {
observer.destroy();
this.watchMap.delete(serviceName);
}
}
watchAddress(serviceName, requestOptions = {}) {
const extendedOptions = Utils.deepMerge(this.baseOptions, requestOptions);
const queryMap = Utils.splitQueryMap(serviceName);
let numRetries = 0;
const observer = new Observer_1.Observer((sink) => {
const _watch = (index) => {
this.client
.send({
type: "ListServiceNodesRequest",
apiVersion: 'v1',
section: 'catalog',
serviceName,
index,
dc: queryMap.dc,
service: queryMap.service,
tag: queryMap.tag,
near: queryMap.near,
'node-meta': queryMap['node-meta'],
}, extendedOptions)
.then((res) => {
if (this.watchMap.has(serviceName)) {
switch (res.statusCode) {
case 200:
const metadata = res.body;
const ID = Math.floor(Math.random() * metadata.length);
const pickedNode = metadata[ID];
const address = pickedNode.Service.Address &&
pickedNode.Service.Address !== ''
? pickedNode.Service.Address
: pickedNode.Node.Address;
const port = pickedNode.Service.Port || 80;
const modifyIndex = pickedNode.Service.ModifyIndex;
numRetries = 0;
if (modifyIndex !== index) {
if (sink(undefined, `${address}:${port}`)) {
_watch(modifyIndex);
}
}
else {
setTimeout(() => _watch(index), 5000);
}
break;
case 404:
logger.error(`Unable to find address for service[${serviceName}]`);
if (numRetries < this.maxRetries) {
setTimeout(_watch, 5000);
numRetries += 1;
}
break;
default:
logger.error(`Error retrieving address for service[${serviceName}]: ${res.statusMessage}.`);
if (numRetries < this.maxRetries) {
setTimeout(_watch, 5000);
numRetries += 1;
}
else {
sink(new Error(`Error retrieving address for service[${serviceName}]: ${res.statusMessage}.`));
}
break;
}
}
})
.catch((err) => {
logger.error(`Error retrieving address for service[${serviceName}]: ${err.message}.`);
if (numRetries < this.maxRetries) {
setTimeout(_watch, 5000);
numRetries += 1;
}
else {
sink(new Error(`Error retrieving address for service[${serviceName}]: ${err.message}.`));
}
});
};
_watch();
});
this.watchMap.set(serviceName, observer);
return observer;
}
}
exports.Catalog = Catalog;
//# sourceMappingURL=Catalog.js.map