UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

224 lines • 11.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = loadExtensionsFromDir; exports.unloadAllExtensions = unloadAllExtensions; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const vm_1 = __importDefault(require("vm")); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const Contracts_1 = require("../Contracts"); const Configurator_1 = __importDefault(require("./Configurator")); const Environment_1 = require("./Environment"); const index_1 = require("./ExtensionModules/index"); let logger; const extensionsToLoad = Configurator_1.default.extensions().include; const extensionsToIgnore = Configurator_1.default.extensions().exclude; async function loadExtensionsFromDir(container, extensionsDir) { logger = new processcube_engine_sdk_1.Logger('extension'); const normalizedPath = path_1.default.normalize(extensionsDir); const absolutePath = path_1.default.resolve(normalizedPath); if (!fs_1.default.existsSync(absolutePath)) { logger.warn(`Failure in extension: Unable to load extensions: Path ${absolutePath} does not exist.`); return; } if (extensionsToLoad != null && extensionsToLoad.length === 0) { logger.warn(`Engine Setting "extensions.include" is set to an empty Array. No extensions will be loaded.`); return; } if (extensionsToLoad && extensionsToLoad.length > 0) { logger.info(`The following extensions have been configured with the 'include' list and will be loaded: ${extensionsToLoad.join(', ')}`); } if (extensionsToIgnore && extensionsToIgnore.length > 0) { logger.info(`The following extensions have been configured with the 'exclude' list and will NOT be loaded: ${extensionsToIgnore.join(', ')}`); } const extensionPaths = getExtensionPathsFromDir(absolutePath); if (!extensionPaths || extensionPaths.length === 0) { logger.info(`No extensions found in ${absolutePath}.`); return; } const engine = createEngineObject(container); index_1.customServiceTask.initialize(container); index_1.customHttpRoute.initialize(container); index_1.eventMiddlewares.initialize(container); index_1.triggerEvents.initialize(container); index_1.getEvents.initialize(container); index_1.userTaskAssignment.initialize(container); const extensionInfoService = container.get(Contracts_1.IocRegistrationKeys.internal.ExtensionInfoService); await loadExtensions(extensionPaths, absolutePath, engine, extensionInfoService); } async function unloadAllExtensions() { (0, Environment_1.clearOnReadyCallbacks)(); } function getExtensionPathsFromDir(absolutePath) { const absolutePathStats = fs_1.default.statSync(absolutePath); if (!absolutePathStats.isDirectory()) { logger.warn(`Unable to load extensions: Path ${absolutePath} is not a directory.`); return []; } const extensionPaths = fs_1.default .readdirSync(absolutePath, { withFileTypes: true }) .filter((item) => item.isDirectory()) .map((item) => path_1.default.join(absolutePath, item.name)); return extensionPaths; } async function loadExtensions(extensionPaths, basePath, engine, extensionInfoService) { logger.info(`Loading ${extensionPaths.length} extensions from ${basePath}.`); for (const extensionPath of extensionPaths) { try { const extension = await requireExtensionFromPath(extensionPath); const extensionIsWhitelisted = extensionsToLoad == null || extensionsToLoad.includes(extension.name); const extensionIsBlacklisted = extensionsToIgnore != null && extensionsToIgnore.includes(extension.name); if (!extensionIsWhitelisted || extensionIsBlacklisted) { logger.warn(`Ignoring Extension "${extension.name}" as per include/exclude settings.`); continue; } logger.debug(`Loading extension ${extension.name}...`); await loadExtension(extension, engine); extensionInfoService.addLoadedExtension({ name: extension.name, version: extension.version }); logger.info(`Loaded extension ${extension.name} version ${extension.version}.`); } catch (error) { logger.error(`Failure in extension: Error while loading extension from ${extensionPath}.`, { extensionPath: extensionPath, err: error, }); error.category = 'extension'; error.message = `Failure in extension: ${error.message}`; throw error; } } logger.info(`Loaded ${extensionInfoService.getLoadedExtensions().length} of ${extensionPaths.length} extensions from ${basePath}.`); } async function requireExtensionFromPath(extensionPath) { const packageJsonContent = getPackageJsonContent(extensionPath); const mainPath = path_1.default.join(extensionPath, packageJsonContent.main); const exports = await vm_1.default.runInNewContext('require(mainPath)', { require: require, mainPath: mainPath, }); const extension = { exports: exports, name: packageJsonContent.name, version: packageJsonContent.version, path: mainPath, }; return extension; } function getPackageJsonContent(extensionPath) { const packageJsonPath = path_1.default.join(extensionPath, 'package.json'); const packageFileContent = fs_1.default.readFileSync(packageJsonPath, 'utf8'); if (!packageFileContent) { throw new Error(`${packageJsonPath} not found.`); } const packageJsonContent = JSON.parse(packageFileContent); const missingRequiredProperties = []; if (packageJsonContent?.name == null) { missingRequiredProperties.push('name'); } if (packageJsonContent?.main == null) { missingRequiredProperties.push('main'); } if (packageJsonContent?.version == null) { missingRequiredProperties.push('version'); } if (missingRequiredProperties.length > 0) { throw new Error(`package.json of extension ${packageJsonPath} is missing the following required properties: ${missingRequiredProperties.join(', ')}.`); } return packageJsonContent; } async function loadExtension(extension, engine) { if (!extension.exports?.onLoad) { logger.warn(`Extension at ${extension.path} exports no onLoad function.`); } else { await extension.exports.onLoad(engine); } } let engineIsReady = false; function createEngineObject(container) { const processTokenService = container.get(Contracts_1.IocRegistrationKeys.core.services.ProcessTokenService); (0, Environment_1.registerOnReadyCallback)(() => { engineIsReady = true; }); return { getConfig: (key) => Configurator_1.default.get(key), onBeforeResuming: Environment_1.registerOnBeforeResumingCallback, onReady: Environment_1.registerOnReadyCallback, registerEventMiddleware: index_1.eventMiddlewares.registerEventMiddleware, removeEventMiddleware: index_1.eventMiddlewares.removeEventMiddleware, registerMessageEventMiddleware: index_1.eventMiddlewares.registerMessageEventMiddleware, registerSignalEventMiddleware: index_1.eventMiddlewares.registerSignalEventMiddleware, triggerMessageEvent: index_1.triggerEvents.triggerMessageEvent, triggerMessageStartEvent: index_1.triggerEvents.triggerMessageStartEvent, triggerSignalEvent: index_1.triggerEvents.triggerSignalEvent, triggerSignalStartEvent: index_1.triggerEvents.triggerSignalStartEvent, getMessageEvents: index_1.getEvents.getMessageEvents, getSignalEvents: index_1.getEvents.getSignalEvents, registerCustomServiceTask: index_1.customServiceTask.registerCustomServiceTask, removeCustomServiceTask: index_1.customServiceTask.removeCustomServiceTask, registerUserTaskAssignmentResolver: index_1.userTaskAssignment.registerUserTaskAssignmentResolver, registerHttpRoute: index_1.customHttpRoute.registerHttpRoute, executeRuntimeExpression: processTokenService.executeRuntimeExpression.bind(processTokenService), get iam() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.IamExtensionAdapter); }, get applicationInfo() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.ApplicationInfoExtensionAdapter); }, get correlations() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.CorrelationExtensionAdapter); }, get cronjobs() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.CronjobExtensionAdapter); }, get dataObjectInstances() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.DataObjectInstanceExtensionAdapter); }, get untypedTasks() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.UntypedTaskExtensionAdapter); }, get events() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.EventExtensionAdapter); }, get externalTasks() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.ExternalTaskExtensionAdapter); }, get flowNodeInstances() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.FlowNodeInstanceExtensionAdapter); }, get manualTasks() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.ManualTaskExtensionAdapter); }, get notification() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.NotificationExtensionAdapter); }, get processDefinitions() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.ProcessDefinitionExtensionAdapter); }, get processInstances() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.ProcessInstanceExtensionAdapter); }, get processModels() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.ProcessModelExtensionAdapter); }, get userTasks() { return getExtensionAdapter(container, Contracts_1.IocRegistrationKeys.extension.adapter.UserTaskExtensionAdapter); }, }; } const extensionAdapterCache = {}; function getExtensionAdapter(container, containerKey) { if (!engineIsReady) { throw new processcube_engine_sdk_1.BadRequestError('The engine is not ready yet.', 'extension'); } if (extensionAdapterCache[containerKey]) { return extensionAdapterCache[containerKey]; } const extensionAdapter = container.get(containerKey); extensionAdapterCache[containerKey] = extensionAdapter; return extensionAdapter; } //# sourceMappingURL=ExtensionLoader.js.map