UNPKG

vulcain-corejs

Version:
286 lines (284 loc) 12.7 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments)).next()); }); }; const annotations_1 = require("./../../di/annotations"); const os = require("os"); require("reflect-metadata"); const system_1 = require("./../../configurations/globals/system"); const dynamicConfiguration_1 = require("./../../configurations/dynamicConfiguration"); const applicationRequestError_1 = require("./../../errors/applicationRequestError"); const metrics_1 = require("../../metrics/metrics"); const rest = require('unirest'); /** * * * @export * @abstract * @class AbstractCommand * @template T */ let AbstractServiceCommand = class AbstractServiceCommand { /** * Creates an instance of AbstractCommand. * * @param {IContainer} container * @param {any} providerFactory */ constructor(container) { this.metrics = container.get(annotations_1.DefaultServiceNames.Metrics); this.initializeMetricsInfo(); } get container() { return this.requestContext.container; } /** * Set (or reset) apikey authorization to use for calling service. * * @protected * @param {string} apiKey - null for reset * * @memberOf AbstractServiceCommand */ useApiKey(apiKey) { if (!apiKey) this.overrideAuthorization = null; else this.overrideAuthorization = "ApiKey " + apiKey; } initializeMetricsInfo() { let dep = this.constructor["$dependency:service"]; if (!dep) { throw new Error("ServiceDependency annotation is required on command " + Object.getPrototypeOf(this).name); } this.setMetricsTags(dep.service, dep.version); } setMetricsTags(targetServiceName, targetServiceVersion) { let exists = system_1.System.manifest.dependencies.services.find(svc => svc.service === targetServiceName && svc.version === targetServiceVersion); if (!exists) { system_1.System.manifest.dependencies.services.push({ service: targetServiceName, version: targetServiceVersion }); } this.metrics.setTags("targetServiceName=" + targetServiceName, "targetServiceVersion=" + targetServiceVersion); } onCommandCompleted(duration, success) { this.metrics.timing(AbstractServiceCommand.METRICS_NAME + metrics_1.MetricsConstant.duration, duration); this.metrics.increment(AbstractServiceCommand.METRICS_NAME + metrics_1.MetricsConstant.total); if (!success) this.metrics.increment(AbstractServiceCommand.METRICS_NAME + metrics_1.MetricsConstant.failure); } /** * * * @private * @param {string} serviceName * @param {number} version * @returns */ createServiceName(serviceName, version) { if (!serviceName) throw new Error("You must provide a service name"); if (!version || !version.match(/[0-9]+\.[0-9]+/)) throw new Error("Invalid version number. Must be on the form major.minor"); if (system_1.System.isTestEnvironnment) { let alias = system_1.System.resolveAlias(serviceName, version); if (alias) return alias; } // Check if there is a service $redirect config property in shared properties // Consul = shared/$redirect/serviceName-version let name = `$redirect.${serviceName}-${version}`; let prop = dynamicConfiguration_1.DynamicConfiguration.getProperty(name); if (prop && prop.value) { if (!prop.value.serviceName && !prop.value.version) return prop.value; serviceName = prop.value.serviceName || serviceName; version = prop.value.version || version; } return (serviceName + version).replace(/[\.-]/g, '').toLowerCase() + ":8080"; } /** * get a domain element * @param serviceName - full service name * @param version - version of the service * @param id - Element id * @param schema - optional element schema * @returns A vulcain request response * * @protected * @template T * @param {string} serviceName * @param {number} version * @param {string} id * @param {string} [schema] * @returns {Promise<QueryResponse<T>>} */ getRequestAsync(serviceName, version, id, schema) { let url = schema ? `http://${this.createServiceName(serviceName, version)}/api/{schema}/get/${id}` : `http://${this.createServiceName(serviceName, version)}/api/get/${id}`; let res = this.sendRequestAsync("get", url); return res; } /** * * * @protected * @template T * @param {string} serviceName * @param {number} version * @param {string} action * @param {*} [query] * @param {number} [page] * @param {number} [maxByPage] * @param {string} [schema] * @returns {Promise<QueryResponse<T>>} */ getQueryAsync(serviceName, version, verb, query, page, maxByPage, schema) { let args = {}; args.$maxByPage = maxByPage; args.$page = page; args.$query = query && JSON.stringify(query); let url = system_1.System.createUrl(`http://${this.createServiceName(serviceName, version)}/api/${verb}`, args); let res = this.sendRequestAsync("get", url); return res; } /** * * * @protected * @param {string} serviceName * @param {number} version * @param {string} action * @param {*} data * @returns {Promise<ActionResponse<T>>} */ sendActionAsync(serviceName, version, verb, data) { let command = { params: data, correlationId: this.requestContext.correlationId }; let url = `http://${this.createServiceName(serviceName, version)}/api/${verb}`; let res = this.sendRequestAsync("post", url, (req) => req.json(command)); return res; } calculateRequestPath() { if (this.requestContext.correlationId[this.requestContext.correlationId.length - 1] === "-") this.requestContext.correlationPath += "1"; else { let parts = this.requestContext.correlationPath.split('-'); let ix = parts.length - 1; let nb = (parseInt(parts[ix]) || 0) + 1; parts[ix] = nb.toString(); this.requestContext.correlationPath = parts.join('-'); } return this.requestContext.correlationPath; } getAuthorization() { return __awaiter(this, void 0, void 0, function* () { if (this.overrideAuthorization) return this.overrideAuthorization; let token = this.requestContext.bearer; if (token) { return "Bearer " + token; } let tokens = this.requestContext.container.get("TokenService"); // Ensures jwtToken exists for user context propagation let result = this.requestContext.bearer = yield tokens.createTokenAsync(this.requestContext.user); return "Bearer " + result.token; }); } /** * Send a http request * * @protected * @param {string} http verb to use * @param {string} url * @param {(req:types.IHttpRequest) => void} [prepareRequest] Callback to configure request before sending * @returns request response */ sendRequestAsync(verb, url, prepareRequest) { return __awaiter(this, void 0, void 0, function* () { let request = rest[verb](url); // Propagate context request.header("X-VULCAIN-CORRELATION-ID", this.requestContext.correlationId); request.header("X-VULCAIN-CORRELATION-PATH", this.calculateRequestPath() + "-"); request.header("X-VULCAIN-SERVICE-NAME", system_1.System.serviceName); request.header("X-VULCAIN-SERVICE-VERSION", system_1.System.serviceVersion); request.header("X-VULCAIN-ENV", system_1.System.environment); request.header("X-VULCAIN-CONTAINER", os.hostname()); request.header("X-VULCAIN-TENANT", this.requestContext.tenant); request.header("Authorization", yield this.getAuthorization()); prepareRequest && prepareRequest(request); this.requestContext.logInfo("Calling vulcain service on " + url); return new Promise((resolve, reject) => { try { request.end((response) => { if (response.error || response.status !== 200) { let err = new Error(response.error ? response.error.message : response.body); system_1.System.log.error(this.requestContext, err, `Service request ${verb} ${url} failed with status code ${response.status}`); reject(err); return; } let vulcainResponse = response.body; if (vulcainResponse.error) { system_1.System.log.info(this.requestContext, `Service request ${verb} ${url} failed with status code ${response.status}`); reject(new applicationRequestError_1.ApplicationRequestError(vulcainResponse.error.message, vulcainResponse.error.errors, response.status)); } else { system_1.System.log.info(this.requestContext, `Service request ${verb} ${url} completed with status code ${response.status}`); resolve(vulcainResponse); } }); } catch (err) { system_1.System.log.error(this.requestContext, err, `Service request ${verb} ${url} failed`); reject(err); } }); }); } exec(kind, serviceName, version, verb, apiKey, data, page, maxByPage) { return __awaiter(this, void 0, void 0, function* () { switch (kind) { case 'action': { this.useApiKey(apiKey); let response = yield this.sendActionAsync(serviceName, version, verb, data); return response.value; } case 'query': { this.useApiKey(apiKey); let response = yield this.getQueryAsync(serviceName, version, verb, data, page, maxByPage); return { values: response.value, total: response.total, page }; } case 'get': { this.useApiKey(apiKey); let response = yield this.getRequestAsync(serviceName, version, data); return response.value; } } }); } runAsync(...args) { return this.exec(...args); } }; AbstractServiceCommand.METRICS_NAME = "service_call"; AbstractServiceCommand = __decorate([ __param(0, annotations_1.Inject(annotations_1.DefaultServiceNames.Container)), __metadata("design:paramtypes", [Object]) ], AbstractServiceCommand); exports.AbstractServiceCommand = AbstractServiceCommand; //# sourceMappingURL=abstractServiceCommand.js.map