UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

255 lines • 12 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EngineRouter = void 0; exports.subscribable = subscribable; exports.cancelable = cancelable; const express_1 = __importDefault(require("express")); const inversify_1 = require("inversify"); const lodash_1 = __importDefault(require("lodash")); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const CancellationToken_1 = require("../Api/CancellationToken"); const Contracts_1 = require("../Contracts"); const ArgumentParser_1 = require("../Tools/ArgumentParser"); const EventAggregator_1 = require("../Tools/EventAggregator"); const Middlewares_1 = require("../Tools/Http/Middlewares"); const index_1 = require("../Tools/Http/index"); const Iam_1 = require("../Tools/Iam"); const ServiceFacade_1 = require("./ServiceFacade"); const WorkerFacade_1 = require("./WorkerFacade"); // If this decorates a service method, proxy calls to the method will create a subscription function subscribable() { return function (target, propertyKey, descriptor) { Reflect.defineMetadata('subscribable', true, target, propertyKey); return descriptor; }; } // If this decorates a service method, proxy calls to the method will create and link a cancellation token function cancelable() { return function (target, propertyKey, descriptor) { Reflect.defineMetadata('cancelable', true, target, propertyKey); return descriptor; }; } let EngineRouter = class EngineRouter { engineApiRouter; extensionRouter; workerFacade; serviceFacade; logger; globalContainer; routerContainer; engineApiRoutes = []; extensionRoutes = []; proxies = []; socketControllers = []; eventTopicsListening = []; loggerNamespace = 'engine:engine_router'; constructor(workerFacade, serviceFacade, globalContainer, namespace) { this.workerFacade = workerFacade; this.serviceFacade = serviceFacade; this.globalContainer = globalContainer; this.routerContainer = new inversify_1.Container(); this.routerContainer.bind(Contracts_1.IocRegistrationKeys.internal.Container).toConstantValue(this.routerContainer); (0, Iam_1.createIdentityServiceIocRegistrations)(this.routerContainer); this.loggerNamespace = namespace; } onNotificationPublishedCallback = (topic, message) => { }; async init() { const isWorker = process.env.isFork === 'true'; this.proxies = (this.initProxies() ?? []).filter(distinctProxies); if (!isWorker) { await this.workerFacade.init((0, ArgumentParser_1.getStartupArgs)() ?? {}); this.engineApiRoutes = this.initHttpRoutes() ?? []; this.extensionRoutes = (await this.getExtensionRoutes()) ?? []; this.socketControllers = this.initSocketController() ?? []; this.buildIoc(); } this.eventTopicsListening = this.initEventTopicsListening() ?? []; if (!isWorker) { this.logger = new processcube_engine_sdk_1.Logger(this.loggerNamespace, { isMainThread: true }); await this.initMainThreadRouting(); await this.initMainThreadSocketNotificationBindings(); } else { this.logger = new processcube_engine_sdk_1.Logger(this.loggerNamespace, { isMainThread: false }); this.initWorkerRouting(); } } getChildProcess() { return this.workerFacade.getChildProcess(); } async dispose() { try { const discoveredDisposableBinding = this.routerContainer.getAll(Contracts_1.disposableDiscoveryTag); for (const disposableBinding of discoveredDisposableBinding) { await disposableBinding.dispose(); } } catch (error) { // Occurs, if nothing disposable is stored in the container, in which case there's nothing to do here. } if (this.workerFacade) { await this.workerFacade.dispose(); } } onNotificationPublished(callback) { this.onNotificationPublishedCallback = callback; } async getExtensionRoutes() { return []; } getController(controller) { return this.routerContainer.get(controller.toString()); } buildIoc() { this.buildProxies(); this.buildControllers(); } buildProxies() { this.proxies.forEach((proxyConf) => { let proxy = {}; if (proxyConf.getGlobally) { proxy = this.globalContainer.get(proxyConf.proxyKey); } else { Object.getOwnPropertyNames(proxyConf.target.prototype).forEach((prop) => { const isSubscribable = Reflect.getMetadata('subscribable', proxyConf.target.prototype, prop); let bindFunction = this.workerFacade.callFunction; if (isSubscribable) { bindFunction = this.workerFacade.subscribe; } proxy[prop] = lodash_1.default.bind(bindFunction, this.workerFacade, `${proxyConf.proxyKey}:${prop}`); }); } if (proxyConf.provideGlobally) { this.globalContainer.bind(proxyConf.proxyKey).toConstantValue(proxy); } this.routerContainer.bind(proxyConf.proxyKey).toConstantValue(proxy); }); } buildControllers() { const distinctControllers = this.engineApiRoutes .concat(this.extensionRoutes) .map((basicRoute) => basicRoute.controllerClass) .concat(this.socketControllers) .filter(distinct); distinctControllers.forEach((controller) => { this.routerContainer.bind(controller.name).to(controller).inSingletonScope(); if (controller.prototype.dispose) { this.routerContainer.bind(Contracts_1.disposableDiscoveryTag).toConstantValue(this.routerContainer.get(controller.name)); } }); } async initMainThreadRouting() { this.workerFacade.subscribeToWorkerShutdown(async (exitCode, signal) => { this.logger.info('Shutting down...', { exitCode: exitCode, signal: signal }); const server = this.globalContainer.get(Contracts_1.IocRegistrationKeys.internal.EngineServer); await server.close(); process.exit(exitCode ?? 0); }); this.engineApiRouter = express_1.default.Router(); this.extensionRouter = express_1.default.Router(); const identityService = this.globalContainer.get(Contracts_1.IocRegistrationKeys.internal.IdentityService); this.extensionRouter.use((0, Middlewares_1.createIsPublicRouteMiddleware)(this.extensionRoutes)); this.extensionRouter.use((0, Middlewares_1.createResolveIdentityMiddleware)(identityService)); this.eventTopicsListening.forEach((topic) => { EventAggregator_1.EventAggregator.subscribe(topic, (message) => { this.workerFacade.publishEventNotification(topic, message); }); }); this.engineApiRoutes.forEach((route) => { this.registerEngineApiRoute(route); }); this.extensionRoutes.forEach((route) => { this.registerExtensionRoute(route); }); this.logger.trace('Initialized main thread routing.'); } registerEngineApiRoute(routeConfiguration) { this.registerHttpRoute(this.engineApiRouter, routeConfiguration); } registerExtensionRoute(routeConfiguration) { this.registerHttpRoute(this.extensionRouter, routeConfiguration); } registerHttpRoute(routerToUse, routeConfiguration) { const controller = this.routerContainer.get(routeConfiguration.controllerClass.name); const controllerMethodName = routeConfiguration.controllerMethod.name.toString(); const controllerMethod = controller[controllerMethodName].bind(controller); const wrapperFunction = async (req, res) => { let cancellationToken; if (routeConfiguration.isCancelable) { cancellationToken = new CancellationToken_1.CancellationToken(req); } const result = await controllerMethod(req, res, cancellationToken); if (cancellationToken) { cancellationToken.dispose(); } return result; }; if (routeConfiguration.isDeprecated) { const deprecateSilently = routeConfiguration.deprecateSilently ?? false; const deprecationMessage = typeof routeConfiguration.isDeprecated === 'string' ? routeConfiguration.isDeprecated : undefined; routerToUse[routeConfiguration.method ?? 'get'](routeConfiguration.route, (0, index_1.deprecate)(deprecateSilently, deprecationMessage), wrapperFunction); } else { routerToUse[routeConfiguration.method ?? 'get'](routeConfiguration.route, wrapperFunction); } } async initMainThreadSocketNotificationBindings() { if (this.socketControllers.length === 0) { return; } this.socketControllers.forEach((socketController) => { const instance = this.routerContainer.get(socketController.name); instance.registerPublishCallback((socketPath, message) => { this.onNotificationPublishedCallback(socketPath, message); }); }); } initWorkerRouting() { this.proxies.forEach((proxyConf) => { if (proxyConf.getGlobally) { return; } const targetInstance = this.globalContainer.get(proxyConf.targetKey); Object.getOwnPropertyNames(proxyConf.target.prototype).forEach((prop) => { if (targetInstance[prop]) { const isCancelable = Reflect.getMetadata('cancelable', proxyConf.target.prototype, prop); this.serviceFacade.registerServiceFunction(`${proxyConf.proxyKey}:${prop}`, targetInstance[prop].bind(targetInstance), isCancelable); } }); }); this.logger.trace('Initialized worker thread routing.'); } }; exports.EngineRouter = EngineRouter; exports.EngineRouter = EngineRouter = __decorate([ (0, inversify_1.injectable)(), __param(0, (0, inversify_1.unmanaged)()), __param(1, (0, inversify_1.unmanaged)()), __param(2, (0, inversify_1.unmanaged)()), __param(3, (0, inversify_1.unmanaged)()), __metadata("design:paramtypes", [WorkerFacade_1.WorkerFacade, ServiceFacade_1.ServiceFacade, inversify_1.Container, String]) ], EngineRouter); function distinct(value, index, self) { return self.findIndex((comp) => comp === value) === index; } function distinctProxies(value, index, self) { return self.findIndex((comp) => comp.proxyKey === value.proxyKey) === index; } //# sourceMappingURL=EngineRouter.js.map