UNPKG

@creditkarma/consul-client

Version:

A client for Hashicorp Consul written in TypeScript

200 lines 8.32 kB
"use strict"; 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