@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
255 lines • 12 kB
JavaScript
"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