UNPKG

vulcain-corejs

Version:
248 lines (246 loc) 10.9 kB
"use strict"; 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 http = require("http"); const actions_1 = require("../pipeline/actions"); const query_1 = require("../pipeline/query"); const requestContext_1 = require("./requestContext"); const annotations_1 = require("../di/annotations"); const metrics_1 = require("../metrics/metrics"); const system_1 = require("./../configurations/globals/system"); const response_1 = require("../pipeline/response"); const guid = require('uuid'); class VulcainHeaderNames { } VulcainHeaderNames.X_VULCAIN_TENANT = "x-vulcain-tenant"; VulcainHeaderNames.X_VULCAIN_CORRELATION_ID = "x-vulcain-correlation-id"; VulcainHeaderNames.X_VULCAIN_TRACE_ID = "x-vulcain-trace-id"; VulcainHeaderNames.X_VULCAIN_PARENT_ID = "x-vulcain-parent-id"; VulcainHeaderNames.X_VULCAIN_SERVICE_NAME = "x-vulcain-service-name"; VulcainHeaderNames.X_VULCAIN_SERVICE_VERSION = "x-vulcain-service-version"; VulcainHeaderNames.X_VULCAIN_ENV = "x-vulcain-env"; VulcainHeaderNames.X_VULCAIN_CONTAINER = "x-vulcain-container"; VulcainHeaderNames.X_VULCAIN_PUBLICPATH = "x-vulcain-publicpath"; exports.VulcainHeaderNames = VulcainHeaderNames; class AbstractAdapter { constructor(domainName, container) { this.domainName = domainName; this.container = container; this.commandManager = new actions_1.CommandManager(container); this.queryManager = new query_1.QueryManager(container); this.testUser = container.get(annotations_1.DefaultServiceNames.TestUser, true); this.domain = container.get(annotations_1.DefaultServiceNames.Domain); this.metrics = container.get(annotations_1.DefaultServiceNames.Metrics); let descriptors = this.container.get(annotations_1.DefaultServiceNames.ServiceDescriptors); let hasAsyncTasks = descriptors.getDescriptions().hasAsyncTasks; this.commandManager.startMessageBus(hasAsyncTasks); } startRequest(request) { let ctx = this.createRequestContext(request); let logger = this.container.get(annotations_1.DefaultServiceNames.Logger); logger.logAction(ctx, "RR"); return ctx; } createRequestContext(request) { let ctx = new requestContext_1.RequestContext(this.container, requestContext_1.Pipeline.HttpRequest); // Initialize headers & hostname this.initializeRequestContext(ctx, request); ctx.correlationId = ctx.headers[VulcainHeaderNames.X_VULCAIN_CORRELATION_ID] || guid.v4(); ctx.parentId = ctx.headers[VulcainHeaderNames.X_VULCAIN_PARENT_ID]; let tenantPolicy = ctx.container.get(annotations_1.DefaultServiceNames.TenantPolicy); ctx.tenant = tenantPolicy.resolveTenant(ctx, request); return ctx; } endRequest(response, ctx, e) { let value = response.value; let hasError = false; let prefix; if (response instanceof response_1.HttpResponse) { value = response.content; hasError = response.statusCode && response.statusCode >= 400; } if (value) { hasError = hasError || value.error; if (value.schema) { prefix = value.schema.toLowerCase() + "_" + value.action.toLowerCase(); } else if (value.action) { prefix = value.action.toLowerCase(); } else { value = null; // custom value - don't log it } } else { hasError = true; } const duration = ctx.durationInMicroseconds * 1000; // Duration prefix && this.metrics.timing(prefix + metrics_1.MetricsConstant.duration, duration); this.metrics.timing(metrics_1.MetricsConstant.allRequestsDuration, duration); // Failure if (hasError) { prefix && this.metrics.increment(prefix + metrics_1.MetricsConstant.failure); this.metrics.increment(metrics_1.MetricsConstant.allRequestsFailure); } // Always remove userContext if (value) { value.userContext = undefined; } // Remove result value for trace let trace = Object.assign({}, value); trace.value = undefined; let logger = this.container.get(annotations_1.DefaultServiceNames.Logger); if (e) { logger.error(ctx, e); } logger.logAction(ctx, "ER", trace.action, trace && JSON.stringify(trace)); // Normalize return value if (value) { value.source = undefined; value.inputSchema = undefined; value.startedAt = undefined; value.completedAt = undefined; } } populateFromQuery(request) { let params = {}; let count = 0; ; Object.keys(request.query).forEach(name => { switch (name) { case "$action": case "$schema": case "$page": case "$maxByPage": break; case "$query": params = JSON.parse(request.query[name]); break; default: count++; params[name] = request.query[name]; } }); return { params, count }; } populateWithActionSchema(action, request, defaultAction) { let a; let s; if (request.params.schemaAction) { if (request.params.schemaAction.indexOf('.') >= 0) { let parts = request.params.schemaAction.split('.'); s = parts[0]; a = parts[1]; } else { a = request.params.schemaAction; } } else { a = request.query.$action; s = request.query.$schema; } action.action = action.action || a || defaultAction; action.schema = action.schema || s; } normalizeCommand(request) { let action = request.body; // Body contains only data -> create a new action object if (!action.action && !action.params && !action.schema) { action = { params: action }; } action.domain = this.domainName; this.populateWithActionSchema(action, request); action.params = action.params || {}; return action; } executeQueryRequest(request, ctx) { return __awaiter(this, void 0, void 0, function* () { if (request.user) { ctx.user = request.user; } let query = { domain: this.domainName }; try { this.populateWithActionSchema(query, request, "all"); if (query.action === "get") { if (!request.params.id) { return new response_1.BadRequestResponse("Id is required"); } let requestArgs = this.populateFromQuery(request); if (requestArgs.count === 0) { query.params = request.params.id; } else { query.params = requestArgs.params; query.params.id = request.params.id; } } else { query.maxByPage = (request.query.$maxByPage && parseInt(request.query.$maxByPage)) || 100; query.page = (request.query.$page && parseInt(request.query.$page)) || 0; query.params = this.populateFromQuery(request).params; } } catch (e) { let result = query; result.error = { message: e.message || e, errors: e.errors }; this.endRequest(result, ctx, e); return new response_1.HttpResponse(result, e.statusCode); } return yield this.executeRequest(this.queryManager, query, ctx); }); } executeActionRequest(request, ctx, command) { if (request.user) { ctx.user = request.user; } command = command || this.normalizeCommand(request); return this.executeRequest(this.commandManager, command, ctx); } executeRequest(manager, command, ctx) { return __awaiter(this, void 0, void 0, function* () { if (!command || !command.domain) { return new response_1.BadRequestResponse("domain is required."); } if (command.domain.toLowerCase() !== this.domainName.toLowerCase()) { return new response_1.BadRequestResponse("this service doesn't belong to domain " + this.domainName); } try { // Check if handler exists let info = manager.getInfoHandler(command); system_1.System.log.info(ctx, `Initialize request context with user=${ctx.user ? ctx.user.name : "<null>"}, scopes=${ctx.user ? ctx.user.scopes : "[]"}, tenant=${ctx.tenant}`); // Verify authorization if (!ctx.hasScope(info.metadata.scope)) { system_1.System.log.info(ctx, `user=${ctx.user ? ctx.user.name : "<null>"}, scopes=${ctx.user ? ctx.user.scopes : "[]"} - Unauthorized for handler scope=${info.metadata.scope} `); return new response_1.HttpResponse({ error: { message: http.STATUS_CODES[403] } }, 403); } // Process handler let result = yield manager.runAsync(command, ctx); if (result && command.correlationId) { result.addHeader(VulcainHeaderNames.X_VULCAIN_CORRELATION_ID, command.correlationId); } // Response this.endRequest(result, ctx); return result; } catch (e) { let result = command; result.error = { message: e.message || e, errors: e.errors }; this.endRequest(result, ctx, e); return new response_1.HttpResponse(result, e.statusCode || 500); } finally { ctx && ctx.dispose(); } }); } } exports.AbstractAdapter = AbstractAdapter; //# sourceMappingURL=abstractAdapter.js.map