UNPKG

nope-js-node

Version:

NoPE Runtime for Nodejs. For Browser-Support please use nope-browser

854 lines (853 loc) 40 kB
"use strict"; /** * @author Martin Karkowski * @email m.karkowski@zema.de */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NopeInstanceManager = void 0; const async_1 = require("../../helpers/async"); const idMethods_1 = require("../../helpers/idMethods"); const mergedData_1 = require("../../helpers/mergedData"); const hash_1 = require("../../helpers/hash"); const objectMethods_1 = require("../../helpers/objectMethods"); const path_1 = require("../../helpers/path"); const getLogger_1 = require("../../logger/getLogger"); const index_browser_1 = require("../../logger/index.browser"); const index_1 = require("../../module/index"); const observables_1 = require("../../observables"); const ConnectivityManager_1 = require("../ConnectivityManager"); const NopeRpcManager_1 = require("../RpcManager/NopeRpcManager"); const gc_1 = require("../../helpers/gc"); /** * Please checkout the Docu of {@link INopeInstanceManager} */ class NopeInstanceManager { /** * Create the Instance Manager. */ constructor(options, _generateEmitter, _generateObservable, _defaultSelector, _id = null, _connectivityManager = null, _rpcManager = null, _core = null) { this.options = options; this._generateEmitter = _generateEmitter; this._generateObservable = _generateObservable; this._defaultSelector = _defaultSelector; this._id = _id; this._connectivityManager = _connectivityManager; this._rpcManager = _rpcManager; this._core = _core; this._communicator = options.communicator; if (_id == null) { this._id = (0, idMethods_1.generateId)(); } if (_connectivityManager == null) { // Creating a new Status-Manager. this._connectivityManager = new ConnectivityManager_1.NopeConnectivityManager(options, _generateObservable, this._id); } if (_rpcManager == null) { // Creating a new Status-Manager. this._rpcManager = new NopeRpcManager_1.NopeRpcManager(options, _generateObservable, this._defaultSelector, this._id); } this._logger = (0, getLogger_1.defineNopeLogger)(options.logger, `core.instance-manager`); // Flag to show if the system is ready or not. this.ready = this._generateObservable(); this.ready.setContent(false); this.constructorServices = this._generateObservable(); this.constructorServices.setContent([]); // Define teh constructors const _this = this; this._mappingOfRemoteDispatchersAndGenerators = new Map(); this.constructors = new mergedData_1.MapBasedMergeData(this._mappingOfRemoteDispatchersAndGenerators, "+", "+"); this._mappingOfRemoteDispatchersAndInstances = new Map(); this.instances = new mergedData_1.MapBasedMergeData(this._mappingOfRemoteDispatchersAndInstances, "instances/+", "instances/+/identifier"); this.internalInstances = new observables_1.NopeObservable(); this.internalInstances.setContent([]); const ctorStart = `nope${objectMethods_1.SPLITCHAR}core${objectMethods_1.SPLITCHAR}constructor${objectMethods_1.SPLITCHAR}`; // We will subscribe to some generators. this._rpcManager.services.data.subscribe((_) => { // Clear the Mapping of the Generators _this._mappingOfRemoteDispatchersAndGenerators.clear(); const constructorServices = new Set(); for (const [dispatcher, services,] of _this._rpcManager.services.originalData.entries()) { // Filter the Generators based on the existing services const generators = services.services .filter((item) => { if (item === null || item === void 0 ? void 0 : item.id.startsWith(ctorStart)) { constructorServices.add(item.id); return true; } return false; }) .map((item) => { return item.id.slice(ctorStart.length); }); // If the Dispatcher has a generator we will add it. if (generators.length) { _this._mappingOfRemoteDispatchersAndGenerators.set(dispatcher, generators); } } // Update the Generators _this.constructorServices.setContent(Array.from(constructorServices)); _this.constructors.update(); }); if (this._logger) { this._logger.info("core.instance-manager online"); } this.reset(); this._init().catch((error) => { if (_this._logger) { _this._logger.error("Failed to intialize the Dispatcher", error); } }); (0, gc_1.registerGarbageCallback)(this, this.dispose.bind(this)); } /** * Update the Available Instances * * @protected * @memberof NopeInstanceManager */ async _sendAvailableInstances() { const _this = this; // Update the Instances provided by this module. await this._communicator.emit("instancesChanged", { dispatcher: this._id, // We will send the descriptions. instances: Array.from(this._internalInstances).map((identifier) => { // Generate the Module Description for every identifier: return _this._instances.get(identifier).instance.toDescription(); }), }); // Update the Instances this.internalInstances.setContent(Array.from(this._internalInstances)); } /** * Internal Function, used to initialize the Dispatcher. * It subscribes to the "Messages" of the communicator. * * @protected * @memberof NopeInstanceManager */ async _init() { const _this = this; // Wait until the Element is connected. await this._communicator.connected.waitFor(); await this._connectivityManager.ready.waitFor(); await this._rpcManager.ready.waitFor(); this.registerInternalWrapperGenerator("*", async (dispather, description, options) => { const mod = new index_1.NopeGenericWrapper(dispather, _this._generateEmitter, _this._generateObservable, options.linkProperties, options.linkEvents); await mod.fromDescription(description, "overwrite"); return mod; }); await this._communicator.on("bonjour", (msg) => { if (msg.dispatcherId !== _this._id) { // If there are dispatchers online, // We will emit our available services. _this ._sendAvailableInstances() .then((_) => { }) .catch((e) => { var _a; if ((_a = _this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.ERROR)) { // If there is a Logger: _this._logger.error(`Dispatcher "${_this._id}" failed to emit available instances`); } }); } }); // We will use our status-manager to listen to changes. this._connectivityManager.dispatchers.onChange.subscribe((changes) => { if (changes.added.length) { // If there are dispatchers online, // We will emit our available services. _this._sendAvailableInstances().catch((e) => { if (_this._logger) { _this._logger.error("Failed to emit the available instance"); _this._logger.error(e); } }); } if (changes.removed.length) { // Remove the dispatchers. changes.removed.map((id) => { _this.removeDispatcher(id); }); } }); // Listen to newly created instances. await this._communicator.on("instancesChanged", (message) => { var _a; // Store the instances: _this._mappingOfRemoteDispatchersAndInstances.set(message.dispatcher, message); // Update the Mapping: _this.instances.update(); if ((_a = _this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { // If there is a Logger: _this._logger.debug('Remote Dispatcher "' + message.dispatcher + '" updated its available instances'); } }); if (this._logger) { this._logger.info("core.instance-manager", this._id, "initialized"); } this.ready.setContent(true); } /** * Helper to get the corresponding Service name * @param {string} name name * @param {"constructor" | "dispose"} type The desired type of the requested service name * @returns {string} the name. */ getServiceName(name, type) { switch (type) { case "constructor": return `nope${objectMethods_1.SPLITCHAR}core${objectMethods_1.SPLITCHAR}constructor${objectMethods_1.SPLITCHAR}${name}`; case "dispose": return `nope${objectMethods_1.SPLITCHAR}core${objectMethods_1.SPLITCHAR}destructor${objectMethods_1.SPLITCHAR}${name}`; default: throw Error("The given type is not correct."); } } /** * Function, that will extract the information of the instance and the * the providing dispatcher. * * @author M.Karkowski * @param {string} identifier The identifier of instance * @return {*} {(INopeModuleDescription & { dispatcher: IDispatcherInfo })} * @memberof nopeDispatcher */ _getInstanceInfo(identifier) { // First check if the instance exists. if (!this.instanceExists(identifier, false)) { return undefined; } // Define the return type const ret = {}; // First we check if we are taking care of an internal instance, if so // we will use this instance to enrich the description, otherwise, we // will look in the external instances. if (this._instances.has(identifier)) { ret.description = this._instances .get(identifier) .instance.toDescription(); } else { // Now extract teh for (const item of this._mappingOfRemoteDispatchersAndInstances.values()) { const instances = item.instances; for (const instance of instances) { if (instance.identifier == identifier) { ret.description = instance; break; } } } } // Additionally add some information about the used dispatcher. ret.dispatcher = this.getManagerOfInstance(identifier); return ret; } /** * Helper to remove a dispatcher. * * @author M.Karkowski * @param {string} dispatcher * @memberof NopeRpcIn */ removeDispatcher(dispatcher) { // Delete the Generators of the Instances. this._mappingOfRemoteDispatchersAndInstances.delete(dispatcher); this.instances.update(); // Now we need to delete every Instance of the dispatcher. // All open calls will be handeled by the RpcManager. // TODO: // this.cancelRunningTasksOfDispatcher( // dispatcher, // new Error( // "Dispatcher has been removed! Tasks cannot be executed any more." // ) // ); } // See interface description async registerConstructor(identifier, cb) { var _a; const _this = this; if ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('Adding instance generator for "' + identifier + '" to external Generators. Other Elements can now create instances of this type.'); } const _cb = await this._rpcManager.registerService(async (data) => { // Check if an instance exists or not. // if not => create an instance an store it. if (!_this._instances.has(data.identifier)) { const hashable = [data.identifier, data.params, data.type]; const hash = (0, hash_1.generateHash)(hashable); // It might happen, that an instance is requested multiple times. // therefore we have to make shure, we wont create them multiple times: // We will test it by using the "_internalInstances" set if (!_this._initializingInstance.has(data.identifier)) { // Mark the Instance as available. _this._initializingInstance.set(data.identifier, hash); try { // Create an Instance const _instance = await cb(_this._core, data.identifier); _instance.identifier = data.identifier; // Make shure the Data is expressed as Array. if (!Array.isArray(data.params)) { data.params = [data.params]; } // Initialize the instance with the parameters. await _instance.init(...data.params); // A Function is registered, taking care of removing // an instances, if it isnt needed any more. await _this._rpcManager.registerService(async (_data) => { var _a; if ((_a = _this._instances.get(data.identifier)) === null || _a === void 0 ? void 0 : _a.usedBy) { // Get the Index of the dispatcher, which is using // the element const idx = _this._instances .get(data.identifier) .usedBy.indexOf(_data.dispatcherId); if (idx > -1) { _this._instances .get(data.identifier) .usedBy.splice(idx, 1); } if (_this._instances.get(data.identifier).usedBy.length == 0) { // Unmark as internal instance _this._internalInstances.delete(data.identifier); // Remove the Instance. await _instance.dispose(); // Delete the Entry. _this._instances.delete(data.identifier); // Remove the Function itself _this._rpcManager.unregisterService(_this.getServiceName(data.identifier, "dispose")); // Emit the instances again await _this._sendAvailableInstances(); } } }, { id: _this.getServiceName(data.identifier, "dispose"), schema: { description: `Service, which will destructor for the instance "${data.identifier}". This function will be called internal only.`, type: "function", }, }); // Store the Instance. _this._instances.set(data.identifier, { instance: _instance, usedBy: [data.dispatcherId], }); _this._internalInstances.add(data.identifier); // Update the available instances: await _this._sendAvailableInstances(); // Make shure, we remove this instance.hash _this._initializingInstance.delete(data.identifier); } catch (e) { // Make shure, we remove this instance.hash _this._initializingInstance.delete(data.identifier); // Rerise the error throw e; } } else if (_this._initializingInstance.get(data.identifier) != hash) { throw Error("Providing different Parameters for the same Identifier"); } else { // Check if the Instance is ready. let firstHint = true; await (0, async_1.waitFor)(() => { if (firstHint) { _this._logger.warn(`Parallel request for the same Instance "${data.identifier}" => Waiting until the Instance has been initialized`); firstHint = false; } return _this._instances.has(data.identifier); }, { testFirst: true, delay: 100, }); } } else { // If an Element exists => Add the Element. _this._instances.get(data.identifier).usedBy.push(data.dispatcherId); } // Define the Response. const response = { description: _this._instances .get(data.identifier) .instance.toDescription(), type: data.type, }; // Send the Response return response; }, { // We will add the Name to our service. id: this.getServiceName(identifier, "constructor"), // We dont want to add a prefix addNopeServiceIdPrefix: false, schema: { description: `Service, which will create an construtor for the type "${identifier}".`, type: "function", }, }); // Store the Generator. this._registeredConstructors.set(identifier, _cb); // TODO: Send an update. } // See interface description async unregisterConstructor(identifier) { var _a; if (this._registeredConstructors.has(identifier)) { if ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('Removing instance generator for "' + identifier + '" from external Generators. Other Elements cant create instances of this type anymore.'); } // We will just unregister the service from our // system. Therefore we just use the rpcManager await this._rpcManager.unregisterService(this._registeredConstructors.get(identifier)); this._registeredConstructors.delete(identifier); } } // See interface description registerInternalWrapperGenerator(identifier, cb) { var _a; if ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('Adding instance generator for "' + identifier + '" as internal Generator. This Generator wont be used externally.'); } this._internalWrapperGenerators.set(identifier, cb); } // See interface description unregisterInternalWrapperGenerator(identifier) { var _a; if ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('Rmoving instance generator for "' + identifier + '" from internal Generator. The sytem cant create elements of this type any more.'); } this._internalWrapperGenerators.delete(identifier); } // See interface description instanceExists(identifier, externalOnly = true) { if (!this.instances.simplified.has(identifier)) { return false; } if (externalOnly) { const manager = this.getManagerOfInstance(identifier); return manager.id !== this._id; } return true; } // See interface description getManagerOfInstance(identifier) { // First we will check if the instance is available internally. if (this._internalInstances.has(identifier)) { return this._connectivityManager.info; } // If that isnt the case, we will check all dispatchers and search the instance. for (const [dispatcher, msg,] of this._mappingOfRemoteDispatchersAndInstances.entries()) { for (const instance of msg.instances) { if (instance.identifier == identifier) { return this._connectivityManager.getStatus(dispatcher); } } } return undefined; } // See interface description getInstanceDescription(instanceIdentifier) { if (this._instances.has(instanceIdentifier)) { return this._instances.get(instanceIdentifier).instance.toDescription(); } for (const { instances, } of this._mappingOfRemoteDispatchersAndInstances.values()) { for (const instance of instances) { if (instance.identifier === instanceIdentifier) { return instance; } } } return false; } // See interface description constructorExists(typeIdentifier) { return this.constructors.data.getContent().includes(typeIdentifier); } async generateWrapper(description) { var _a, _b, _c; // Define the Default Description // which will lead to an error. const _defDescription = { dispatcherId: this._id, identifier: "error", params: [], type: "unkown", }; // Assign the provided Description const _description = Object.assign(_defDescription, description, { dispatcherId: this._id, }); // Check if the description is complete if (_defDescription.type === "unkown" || _description.identifier === "error") { throw Error('Please Provide at least a "type" and "identifier" in the paremeters'); } // Use the varified Name (removes the invalid chars.) _defDescription.identifier = this.options.forceUsingValidVarNames ? (0, path_1.varifyPath)(_defDescription.identifier) : _defDescription.identifier; if ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('Requesting an wrapper of type: "' + _defDescription.type + '" with the identifier: "' + _defDescription.identifier + '"'); } try { let _type = _description.type; if (!this._internalWrapperGenerators.has(_type)) { // No default type is present for a remote // => assing the default type which is "*"" _type = "*"; } if (this._internalWrapperGenerators.has(_type)) { if ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('No instance with the identifiert: "' + _defDescription.identifier + '" found, but an internal generator is available. Using the internal one for creating the instance and requesting the "real" instance externally'); } // Now test if there is allready an instance with this name and type. // If so, we check if we have the correct type etc. Additionally we // try to extract its dispatcher-id and will use that as selector // to allow the function be called. const _instanceDetails = this._getInstanceInfo(_description.identifier); if (_instanceDetails !== undefined && (_instanceDetails === null || _instanceDetails === void 0 ? void 0 : _instanceDetails.description.type) !== _description.type) { throw Error("There exists an Instance named: '" + _description.identifier + "' but it uses a different type. Requested type: '" + _description.type + "', given type: '" + (_instanceDetails === null || _instanceDetails === void 0 ? void 0 : _instanceDetails.description.type) + "'"); } else if (_instanceDetails === undefined) { throw Error(`No instance known with the idenfitier '${_description.identifier}'`); } const definedInstance = _instanceDetails.description; // Create the Wrapper for our instance. const wrapper = (await this._internalWrapperGenerators.get(_type)(this._core, definedInstance, { linkEvents: true, linkProperties: true, })); if ((_c = this._logger) === null || _c === void 0 ? void 0 : _c.enabledFor(index_browser_1.DEBUG)) { this._logger.debug(`Created a Wrapper for the instance "${definedInstance.identifier}"`); } // Make shure, that the wrapper is handled correctly. (0, gc_1.registerGarbageCallback)(wrapper, wrapper.dispose.bind(wrapper)); return wrapper; } throw Error("No internal generator Available!"); } catch (e) { if (this._logger) { this._logger.error("During creating an Instance, the following error Occurd"); this._logger.error(e); } throw e; } } // See interface description async createInstance(description, options = {}) { var _a, _b, _c, _d; const _this = this; // Define the Default Description // which will lead to an error. const _defDescription = { dispatcherId: this._id, identifier: "error", params: [], type: "unkown", }; // Assign the provided Description const _description = Object.assign(_defDescription, description, { dispatcherId: this._id, }); // Check if the description is complete if (_defDescription.type === "unkown" || _description.identifier === "error") { throw Error('Please Provide at least a "type" and "identifier" in the paremeters'); } // Use the varified Name (removes the invalid chars.) _defDescription.identifier = this.options.forceUsingValidVarNames ? (0, path_1.varifyPath)(_defDescription.identifier) : _defDescription.identifier; if ((_a = this._logger) === null || _a === void 0 ? void 0 : _a.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('Requesting an Instance of type: "' + _defDescription.type + '" with the identifier: "' + _defDescription.identifier + '"'); } try { let _type = _description.type; if (!this._internalWrapperGenerators.has(_type)) { // No default type is present for a remote // => assing the default type which is "*"" _type = "*"; } if (!this.constructorExists(_description.type)) { throw Error('Generator "' + _description.type + '" isnt present in the network!'); } if (this._internalWrapperGenerators.has(_type)) { if ((_b = this._logger) === null || _b === void 0 ? void 0 : _b.enabledFor(index_browser_1.DEBUG)) { this._logger.debug('No instance with the identifiert: "' + _defDescription.identifier + '" found, but an internal generator is available. Using the internal one for creating the instance and requesting the "real" instance externally'); } // Now test if there is allready an instance with this name and type. // If so, we check if we have the correct type etc. Additionally we // try to extract its dispatcher-id and will use that as selector // to allow the function be called. const _instanceDetails = this._getInstanceInfo(_description.identifier); if (_instanceDetails !== undefined && (_instanceDetails === null || _instanceDetails === void 0 ? void 0 : _instanceDetails.description.type) !== _description.type) { throw Error("There exists an Instance named: '" + _description.identifier + "' but it uses a different type. Requested type: '" + _description.type + "', given type: '" + (_instanceDetails === null || _instanceDetails === void 0 ? void 0 : _instanceDetails.description.type) + "'"); } const usedDispatcher = _instanceDetails === null || _instanceDetails === void 0 ? void 0 : _instanceDetails.dispatcher.id; if (usedDispatcher && options.assignmentValid) { // If we have an dispatcher, which was been used to create the instance, // we have to check, the selected Dispatcher Matches our criteria. if (!(await options.assignmentValid(_instanceDetails.description, _instanceDetails.dispatcher))) { throw Error("Assignment is invalid."); } } const definedInstance = await this._rpcManager.performCall( // Extract our Service Name: this.getServiceName(_description.type, "constructor"), // We will use our Description as Parameter. [_description], // Additionally we share the options: options); if ((_c = this._logger) === null || _c === void 0 ? void 0 : _c.enabledFor(index_browser_1.DEBUG)) { this._logger.debug(`Received a description for the instance "${definedInstance.description.identifier}"`); } // Create the Wrapper for our instance. const wrapper = (await this._internalWrapperGenerators.get(_type)(this._core, definedInstance.description, { linkEvents: typeof options.linkEvents === "boolean" ? options.linkEvents : true, linkProperties: typeof options.linkProperties === "boolean" ? options.linkProperties : true, })); if ((_d = this._logger) === null || _d === void 0 ? void 0 : _d.enabledFor(index_browser_1.DEBUG)) { this._logger.debug(`Created a Wrapper for the instance "${definedInstance.description.identifier}"`); } const originalDispose = wrapper.dispose; let called = false; wrapper.dispose = async () => { if (!called) { // Remember, that we have called the method. called = true; // Now lets delete the instance. await _this.deleteInstance(_description.identifier, false, false); // Apply the original Callback. await originalDispose.apply(wrapper); } }; // Make shure, that the wrapper is handled correctly. (0, gc_1.registerGarbageCallback)(wrapper, wrapper.dispose.bind(wrapper)); return wrapper; } throw Error("No internal generator Available!"); } catch (e) { if (this._logger) { this._logger.error("During creating an Instance, the following error Occurd"); this._logger.error(e); } throw e; } } // See interface description async registerInstance(instance) { // Store the Instances. this._instances.set(instance.identifier, { instance, usedBy: [], manual: true, }); this._internalInstances.add(instance.identifier); await this._sendAvailableInstances(); return instance; } // See interface description async deleteInstance(instance, preventSendingUpdate = false, callInstanceDispose = true) { // Block to find the instance. // Based on the property (string or instance) // the corresponding instance object has to be select. let _instance; let _identifier; if (typeof instance === "string") { _instance = this._instances.get(instance); _identifier = instance; } else { for (const data of this._instances.values()) { if (instance == data.instance) { _instance = data; _identifier = data.instance.identifier; break; } } } try { const params = { dispatcherId: this._id, identifier: _identifier, }; // Call the corresponding Dispose Function for the "real" instance // All other elements are just accessors. await this._rpcManager.performCall( // Extract our Service Name: this.getServiceName(_identifier, "dispose"), // We will use our Description as Parameter. [params]); } catch (e) { // Only if it is an internal // Instance, we do not want to // throw that error, otherwise // we want that error to be // present. if (_instance) { } else { throw e; } } // if the instance has been found => delete the instance. if (_instance) { _instance.usedBy.pop(); if (_instance.usedBy.length === 0) { // Delete the Identifier this._instances.delete(_instance.instance.identifier); // Check if an update should be emitted or not. if (!preventSendingUpdate) { // Update the Instances provided by this module. await this._sendAvailableInstances(); } if (callInstanceDispose) { // Dispose the Handler; await _instance.instance.dispose(); } } return true; } else { } return false; } // See interface description async getInstancesOfType(type) { const indentifier = this.instances.data .getContent() .filter((item) => { return item.type == type; }) .map((item) => { return item.identifier; }); const promises = []; for (const identifier of indentifier) { promises.push(this.createInstance({ identifier, type, params: [], })); } // Wait to generate all Instances. const result = await Promise.all(promises); return result; } // See interface description reset() { this._mappingOfRemoteDispatchersAndGenerators.clear(); this._mappingOfRemoteDispatchersAndInstances.clear(); this.constructors.update(); this.instances.update(); this._internalWrapperGenerators = new Map(); this._registeredConstructors = new Map(); // If Instances Exists => Delete them. if (this._instances) { const _this = this; // Dispose all Instances. for (const [name, instance] of this._instances.entries()) { // Remove the Instance. this.deleteInstance(name, true).catch((e) => { if (_this._logger) { _this._logger.error('Failed Removing Instance "' + name + '"'); _this._logger.error(e); } }); } } this._instances = new Map(); this._externalInstances = new Map(); this._internalInstances = new Set(); this._initializingInstance = new Map(); this._externalInstancesNames = new Set(); // Reset the instances this.internalInstances.setContent([]); if (this._communicator.connected.getContent()) { const _this = this; // Update the Instances this._sendAvailableInstances().catch((e) => { if (_this._logger) { _this._logger.error("Failed to emit the available instance"); _this._logger.error(e); } }); } } /** * Describes the Data. * @returns */ toDescription() { const ret = { constructors: { all: this.constructors.data.getContent(), internal: Array.from(this._registeredConstructors.keys()), }, instances: { all: this.instances.data.getContent(), internal: Array.from(this._internalInstances.keys()), }, }; return ret; } // See interface description async dispose() { const promises = []; for (const [id, data] of this._instances.entries()) { if (!data.manual) { promises.push(data.instance.dispose()); } } await Promise.all(promises); this.instances.dispose(); } } exports.NopeInstanceManager = NopeInstanceManager;