UNPKG

vulcain-corejs

Version:
238 lines (236 loc) 11.6 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 messageBus_1 = require('./messageBus'); const annotations_1 = require('../di/annotations'); const common_1 = require('./common'); const os = require('os'); const requestContext_1 = require('../servers/requestContext'); const eventHandlerFactory_1 = require('./eventHandlerFactory'); const conventions_1 = require('../utils/conventions'); const system_1 = require('./../configurations/globals/system'); const commandRuntimeError_1 = require('./../errors/commandRuntimeError'); const guid = require('node-uuid'); (function (EventNotificationMode) { EventNotificationMode[EventNotificationMode["always"] = 0] = "always"; EventNotificationMode[EventNotificationMode["successOnly"] = 1] = "successOnly"; EventNotificationMode[EventNotificationMode["never"] = 2] = "never"; })(exports.EventNotificationMode || (exports.EventNotificationMode = {})); var EventNotificationMode = exports.EventNotificationMode; class CommandManager { constructor(container) { this.container = container; this._initialized = false; this._hostname = os.hostname(); this._serviceId = process.env[conventions_1.Conventions.instance.ENV_SERVICE_NAME] + "-" + process.env[conventions_1.Conventions.instance.ENV_SERVICE_VERSION]; if (!this._serviceId) throw new Error("VULCAIN_SERVICE_NAME and VULCAIN_SERVICE_VERSION must be defined."); } /** * Get the current domain model * @returns {Domain} */ get domain() { if (!this._domain) { this._domain = this.container.get(annotations_1.DefaultServiceNames.Domain); } return this._domain; } get serviceId() { return this._serviceId; } startMessageBus(hasAsyncTasks) { this.messageBus = new messageBus_1.MessageBus(this, hasAsyncTasks); this.subscribeToEvents(); } createResponse(ctx, command, error) { let res = { tenant: ctx.tenant, source: this._hostname, startedAt: command.startedAt, service: command.service, schema: command.schema, inputSchema: command.inputSchema, action: command.action, userContext: command.userContext, domain: command.domain, status: error ? "Error" : command.status, correlationId: command.correlationId, taskId: command.taskId }; if (error) res.error = { message: error.message, errors: error.errors }; return res; } validateRequestData(info, command) { return __awaiter(this, void 0, void 0, function* () { let errors; let inputSchema = info.metadata.inputSchema; if (inputSchema && inputSchema !== "none") { let schema = inputSchema && this.domain.getSchema(inputSchema); if (schema) { command.inputSchema = schema.name; // Custom binding if any command.params = schema && schema.bind(command.params); errors = schema.validate(command.params); if (errors && !Array.isArray(errors)) errors = [errors]; } if (!errors || errors.length === 0) { // Search if a method naming validate<schema>[Async] exists let methodName = 'validate' + inputSchema; let altMethodName = methodName + 'Async'; errors = info.handler[methodName] && info.handler[methodName](command.params, command.action); if (!errors) errors = info.handler[altMethodName] && (yield info.handler[altMethodName](command.params, command.action)); if (errors && !Array.isArray(errors)) errors = [errors]; } } return errors; }); } getInfoHandler(command, container) { if (!this._serviceDescriptors) { this._serviceDescriptors = this.container.get(annotations_1.DefaultServiceNames.ServiceDescriptors); } let info = this._serviceDescriptors.getHandlerInfo(container, command.schema, command.action); return info; } runAsync(command, ctx) { return __awaiter(this, void 0, Promise, function* () { let info = this.getInfoHandler(command, ctx.container); if (info.kind !== "action") throw new Error("Query handler must be requested with GET."); let eventMode = info.metadata.eventMode || EventNotificationMode.successOnly; system_1.System.log.write(ctx, { RunAction: command }); try { let errors = yield this.validateRequestData(info, command); if (errors && errors.length > 0) return this.createResponse(ctx, command, { message: "Validation errors", errors: errors }); command.schema = info.metadata.schema; command.correlationId = ctx.correlationId; command.correlationPath = ctx.correlationPath; command.startedAt = system_1.System.nowAsString(); command.service = this._serviceId; command.userContext = ctx.user || {}; // Register asynchronous task if (!info.metadata.async) { info.handler.requestContext = ctx; info.handler.command = command; let result = yield info.handler[info.method](command.params); if (result instanceof common_1.HttpResponse) { return result; // skip normal process } command.status = "Success"; let res = this.createResponse(ctx, command); res.value = common_1.HandlerFactory.obfuscateSensibleData(this.domain, this.container, result); res.completedAt = system_1.System.nowAsString(); if (eventMode === EventNotificationMode.always || eventMode === EventNotificationMode.successOnly) { this.messageBus.sendEvent(res); } return res; } else { // Pending this.messageBus.pushTask(command); return this.createResponse(ctx, command); } } catch (e) { let error = (e instanceof commandRuntimeError_1.CommandRuntimeError) ? e.error : e; return this.createResponse(ctx, command, error); } }); } consumeTaskAsync(command) { return __awaiter(this, void 0, void 0, function* () { let ctx = new requestContext_1.RequestContext(this.container, requestContext_1.Pipeline.HttpRequest); ctx.correlationId = command.correlationId || guid.v4(); ctx.correlationPath = "event-"; system_1.System.log.write(ctx, { runEvent: command }); let info = this.getInfoHandler(command, ctx.container); let eventMode = info.metadata.eventMode || EventNotificationMode.always; let res; try { ctx.user = command.userContext; ctx.tenant = command.userContext.tenant; info.handler.requestContext = ctx; info.handler.command = command; let result = yield info.handler[info.method](command.params); if (result instanceof common_1.HttpResponse) { throw new Error("Custom Http Response is not valid in an async action"); } command.status = "Success"; res = this.createResponse(ctx, command); res.value = common_1.HandlerFactory.obfuscateSensibleData(this.domain, this.container, result); res.commandMode = "async"; res.completedAt = system_1.System.nowAsString(); if (eventMode === EventNotificationMode.always || eventMode === EventNotificationMode.successOnly) { this.messageBus.sendEvent(res); } } catch (e) { let error = (e instanceof commandRuntimeError_1.CommandRuntimeError) ? e.error : e; res = this.createResponse(ctx, command, { message: error.message }); res.commandMode = "async"; res.completedAt = system_1.System.nowAsString(); if (eventMode === EventNotificationMode.always) { this.messageBus.sendEvent(res); } system_1.System.log.error(ctx, e, `Error when processing async action : ${JSON.stringify(command)}`); } finally { ctx.dispose(); } }); } subscribeToEvents() { if (!this._initialized) { this._initialized = true; for (let item of CommandManager.eventHandlersFactory.allHandlers()) { this.bindEventHandler(item.metadata); } } } bindEventHandler(metadata) { let events = this.messageBus.getEventsQueue(metadata.subscribeToDomain || this.domain.name); events = events.filter((e) => (metadata.subscribeToSchema === "*" || e.schema === metadata.subscribeToSchema)); if (metadata.filter) events = metadata.filter(events); events.subscribe((evt) => { let handlers = CommandManager.eventHandlersFactory.getFilteredHandlers(evt.domain, evt.schema, evt.action); for (let info of handlers) { let handler; let ctx = new requestContext_1.RequestContext(this.container, requestContext_1.Pipeline.EventNotification); ctx.correlationId = evt.correlationId || guid.v4(); ctx.correlationPath = "-"; try { ctx.user = evt.userContext || {}; handler = ctx.container.resolve(info.handler); handler.requestContext = ctx; handler.event = evt; } catch (e) { system_1.System.log.error(ctx, e, `Unable to create handler ${info.handler.name}`); } try { handler[info.methodName](evt); } catch (e) { let error = (e instanceof commandRuntimeError_1.CommandRuntimeError) ? e.error.toString() : (e.message || e.toString()); system_1.System.log.error(ctx, error, `Error with event handler ${info.handler.name} event : ${evt}`); } } }); } } CommandManager.eventHandlersFactory = new eventHandlerFactory_1.EventHandlerFactory(); exports.CommandManager = CommandManager; //# sourceMappingURL=actions.js.map