nope-js-node
Version:
NoPE Runtime for Nodejs. For Browser-Support please use nope-browser
854 lines (853 loc) • 40 kB
JavaScript
"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;