Fixing lazy Instance Removing.
This commit is contained in:
parent
fe55fdf973
commit
d1df3a60ea
@ -1,5 +1,5 @@
|
||||
import { getSingleton } from "../helpers/singletonMethod";
|
||||
import { nopeObservable } from "../observables/nopeObservable";
|
||||
import { NopeObservable } from "../observables/nopeObservable";
|
||||
import { INopeRpcDispatcherOptions } from "../types/communication.interface";
|
||||
import { nopeDispatcher } from "./nopeDispatcher";
|
||||
|
||||
@ -10,7 +10,7 @@ import { nopeDispatcher } from "./nopeDispatcher";
|
||||
export function getRpcDispatcher(options: INopeRpcDispatcherOptions) {
|
||||
|
||||
const container = getSingleton('nopeBackendDispatcher.instance', () => {
|
||||
return new nopeDispatcher(options, () => new nopeObservable());
|
||||
return new nopeDispatcher(options, () => new NopeObservable());
|
||||
});
|
||||
|
||||
return container.instance
|
||||
|
@ -2,12 +2,12 @@
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2020-08-25 23:27:28
|
||||
* @modify date 2020-10-13 12:46:56
|
||||
* @modify date 2020-10-14 18:18:08
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
import { getSingleton } from "../helpers/singletonMethod";
|
||||
import { nopeObservable } from "../observables/nopeObservable";
|
||||
import { NopeObservable } from "../observables/nopeObservable";
|
||||
import { INopeRpcDispatcherOptions } from "../types/communication.interface";
|
||||
import { getRpcDispatcher } from "./getDispatcher";
|
||||
import { IExportFunctionToDispatcherParameters, IExportMethodToDispatcherParameters, IExportPropertyToDispatcherParameters } from "./nopeDispatcherDecorators";
|
||||
@ -26,7 +26,7 @@ export function getLinkedDispatcher(options: INopeRpcDispatcherOptions) {
|
||||
}>(),
|
||||
parameters: new Map<string, {
|
||||
uri: string,
|
||||
item: nopeObservable<any>,
|
||||
item: NopeObservable<any>,
|
||||
options: IExportPropertyToDispatcherParameters
|
||||
}>(),
|
||||
functions: new Map<string, {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2020-10-12 18:52:00
|
||||
* @modify date 2020-10-13 13:02:32
|
||||
* @modify date 2020-10-15 09:20:41
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
@ -10,7 +10,7 @@ import { inject, injectable } from 'inversify';
|
||||
import { Logger } from "winston";
|
||||
import { generateId } from '../helpers/idMethods';
|
||||
import { DISPATCHER_OPTIONS, OBSERVABLE_FACTORY } from '../symbols/identifiers';
|
||||
import { IAvailableInstanceGenerators, IAvailableServicesMsg, IAvailableTopicsMsg, ICallOptions, ICommunicationInterface, IExternalEventMsg, IInstanceCreation, IInstanceDescription, INopeRpcDispatcherOptions, IRequestTaskMsg, IResponseTaskMsg } from '../types/communication.interface';
|
||||
import { IAvailableInstanceGenerators, IAvailableServicesMsg, IAvailableTopicsMsg, ICallOptions, ICommunicationInterface, IExternalEventMsg, IInstanceCreation, IInstanceDescription, IInstanceRemoval, INopeRpcDispatcherOptions, IRequestTaskMsg, IResponseTaskMsg } from '../types/communication.interface';
|
||||
import { IGenerateRemoteInstanceCallback, IGenerateRemoteInstanceForOtherDispatcherCallback, INopeDispatcher } from '../types/nopeDispatcher.interface';
|
||||
import { INopeModule } from '../types/nopeModule.interface';
|
||||
import { INopeObservable, IPipe } from '../types/nopeObservable.interface';
|
||||
@ -38,8 +38,8 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
protected _definedFunctions: Map<string, (...args) => Promise<any>>;
|
||||
protected _remotlyCalledFunctions: Set<string>;
|
||||
protected _communicatorCallbacks: Map<string, {
|
||||
registeredId: string,
|
||||
type: 'request' | 'response'
|
||||
registeredId: string,
|
||||
type: 'request' | 'response',
|
||||
cb: (data) => any
|
||||
}>;
|
||||
protected _communicator: ICommunicationInterface;
|
||||
@ -119,7 +119,6 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
this._init();
|
||||
}
|
||||
|
||||
|
||||
provideInstanceGeneratorForExternalDispatchers<I extends INopeModule>(identifier: string, cb: IGenerateRemoteInstanceForOtherDispatcherCallback<I>) {
|
||||
const _this = this;
|
||||
const _cb = this.registerFunction(async (data: IInstanceCreation) => {
|
||||
@ -133,19 +132,50 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
// Initialize the instance with the parameters.
|
||||
await _instance.init(...data.params);
|
||||
|
||||
_this.registerFunction(() => _instance.dispose(), {
|
||||
deleteAfterCalling: true,
|
||||
// A Function is registered, taking care of removing
|
||||
// an instances, if it isnt needed any more.
|
||||
_this.registerFunction(async (_data: IInstanceRemoval) => {
|
||||
if (_this._instances.get(data.identifier)?.usedBy) {
|
||||
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) {
|
||||
// Remove the Instance.
|
||||
await _instance.dispose();
|
||||
|
||||
// Delete the Entry.
|
||||
_this._instances.delete(data.identifier);
|
||||
|
||||
// Remove the Function itself
|
||||
_this.unregisterFunction('instance_dispose_' + data.identifier)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
deleteAfterCalling: false,
|
||||
id: 'instance_dispose_' + data.identifier
|
||||
});
|
||||
|
||||
// Store the Instance.
|
||||
_this._instances.set(data.identifier, _instance);
|
||||
_this._instances.set(data.identifier, {
|
||||
instance: _instance,
|
||||
usedBy: [ data.dispatcherID ]
|
||||
});
|
||||
} else {
|
||||
// If an Element exists => Add the Element.
|
||||
_this._instances.get(data.identifier).usedBy.push(data.dispatcherID);
|
||||
}
|
||||
|
||||
// Define the Response.
|
||||
const response: IInstanceDescription = {
|
||||
description: _this._instances.get(data.identifier).toDescription(),
|
||||
description: _this._instances.get(data.identifier).instance.toDescription(),
|
||||
type: data.type,
|
||||
}
|
||||
|
||||
// Send the Response
|
||||
return response
|
||||
}, {
|
||||
id: 'generateInstance_' + identifier,
|
||||
@ -169,22 +199,47 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
|
||||
protected _internalGenerators: Map<string, IGenerateRemoteInstanceCallback<INopeModule>>;
|
||||
protected _externalGenerators: Map<string, IGenerateRemoteInstanceCallback<INopeModule>>;
|
||||
protected _instances: Map<string, INopeModule>;
|
||||
protected _instances: Map<string, {
|
||||
instance: INopeModule,
|
||||
usedBy: Array<string>,
|
||||
}>;
|
||||
|
||||
public async generateInstance<I extends INopeModule>(description: IInstanceCreation): Promise<I> {
|
||||
if (this._instances.has(description.identifier)) {
|
||||
return this._instances.get(description.identifier) as I;
|
||||
public async generateInstance<I extends INopeModule>(description: Partial<IInstanceCreation>): Promise<I> {
|
||||
|
||||
const _defDescription: IInstanceCreation = {
|
||||
dispatcherID: this.id,
|
||||
identifier: 'error',
|
||||
params: [],
|
||||
type: 'unkown'
|
||||
}
|
||||
|
||||
const _description = Object.assign(_defDescription, description, { dispatcherID: this.id }) as IInstanceCreation;
|
||||
if (_defDescription.type === 'unkown' || _description.identifier === 'error') {
|
||||
throw Error('Please Provide at least a "type" and "identifier" in the paremeters');
|
||||
}
|
||||
|
||||
if (this._instances.has(_description.identifier)) {
|
||||
// Add the Dispatcher to the Element:
|
||||
this._instances.get(_description.identifier).usedBy.push(_description.dispatcherID);
|
||||
|
||||
// Return the Instance.
|
||||
return this._instances.get(_description.identifier).instance as I;
|
||||
}
|
||||
|
||||
try {
|
||||
if (this._internalGenerators.has(description.type)) {
|
||||
const result = await this.performCall<IInstanceDescription>('generateInstance_' + description.type, [description], {
|
||||
if (this._internalGenerators.has(_description.type)) {
|
||||
const result = await this.performCall<IInstanceDescription>('generateInstance_' + _description.type, [_description], {
|
||||
paramsHasNoCallback: true,
|
||||
});
|
||||
|
||||
const instance = await this._internalGenerators.get(description.type)(this, result.description) as I;
|
||||
// Create the Instance
|
||||
const instance = await this._internalGenerators.get(_description.type)(this, result.description) as I;
|
||||
|
||||
this._instances.set(description.identifier, instance);
|
||||
// Store the Instances.
|
||||
this._instances.set(_description.identifier, {
|
||||
instance,
|
||||
usedBy: [_description.dispatcherID]
|
||||
});
|
||||
|
||||
return instance;
|
||||
}
|
||||
@ -200,12 +255,50 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
throw new Error("No Dynamic Interface provided");
|
||||
}
|
||||
|
||||
public async deleteInstance<I extends INopeModule>(instance: I): Promise<boolean> {
|
||||
// Remove the Item:
|
||||
this._instances.delete(instance.identifier);
|
||||
// Dispose the Instance.
|
||||
await instance.dispose();
|
||||
return true;
|
||||
public async deleteInstance<I extends INopeModule>(instance: I | string): Promise<boolean> {
|
||||
|
||||
// Block to find the instance.
|
||||
// Based on the property (string or instance)
|
||||
// the corresponding instance object has to be select.
|
||||
let _instance: { instance: INopeModule; usedBy: Array<string>; };
|
||||
if (typeof instance === 'string'){
|
||||
_instance = this._instances.get(instance);
|
||||
} else {
|
||||
for (const data of this._instances.values()){
|
||||
if (instance == data.instance){
|
||||
_instance = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the instance has been found => delete the instance.
|
||||
if (_instance) {
|
||||
|
||||
_instance.usedBy.pop();
|
||||
|
||||
if (_instance.usedBy.length === 0){
|
||||
const params: IInstanceRemoval = {
|
||||
dispatcherID: this.id,
|
||||
identifier: _instance.instance.identifier
|
||||
}
|
||||
|
||||
// Call the corresponding Dispose Function for the "real" instance
|
||||
// All other elements are just accessors.
|
||||
await this.performCall('instance_dispose_' + _instance.instance.identifier, [params]);
|
||||
|
||||
// Delete the Identifier
|
||||
this._instances.delete(_instance.instance.identifier);
|
||||
|
||||
// Dispose the Handler;
|
||||
await _instance.instance.dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -529,7 +622,6 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function, used to subscribe to results.
|
||||
*
|
||||
@ -1202,12 +1294,16 @@ export class nopeDispatcher implements INopeDispatcher {
|
||||
|
||||
// Dispose all Instances.
|
||||
for (const [name, instance] of this._instances.entries()) {
|
||||
instance.dispose().catch(e => {
|
||||
// Remove the Instance.
|
||||
this.deleteInstance(name).catch(e => {
|
||||
if (_this._logger) {
|
||||
_this._logger.error('Failed Removing Instance "' + name + '"');
|
||||
_this._logger.error(e)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
this._instances = new Map();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { getSingleton } from "../helpers/singletonMethod";
|
||||
import { nopeObservable } from "../observables/nopeObservable";
|
||||
import { NopeObservable } from "../observables/nopeObservable";
|
||||
|
||||
// Symbols for the Property Registery:
|
||||
const _registeredDispatcherMethods_ = Symbol('_registeredDispatcherMethods_');
|
||||
@ -37,7 +37,7 @@ const container = getSingleton('nopeBackendDispatcher.container', () => {
|
||||
}>(),
|
||||
parameters: new Map<string, {
|
||||
uri: string,
|
||||
item: nopeObservable<any>,
|
||||
item: NopeObservable<any>,
|
||||
options: IExportPropertyToDispatcherParameters
|
||||
}>(),
|
||||
functions: new Map<string, {
|
||||
|
@ -2,7 +2,7 @@
|
||||
* @author Martin Karkowski
|
||||
* @email m.karkowski@zema.de
|
||||
* @create date 2020-10-12 18:31:54
|
||||
* @modify date 2020-10-13 12:44:45
|
||||
* @modify date 2020-10-14 07:52:52
|
||||
* @desc [description]
|
||||
*/
|
||||
|
||||
@ -194,9 +194,14 @@ export interface IInstanceDescription {
|
||||
export interface IInstanceCreation {
|
||||
type: string,
|
||||
identifier: string,
|
||||
params: any
|
||||
params: any,
|
||||
dispatcherID: string,
|
||||
}
|
||||
|
||||
export interface IInstanceRemoval {
|
||||
identifier: string,
|
||||
dispatcherID: string,
|
||||
}
|
||||
|
||||
export type IAvailableTopicsMsg = {
|
||||
/**
|
||||
|
@ -96,6 +96,10 @@ export class HelloWorldModule extends NopeBaseModule implements IHelloWorlModule
|
||||
topic: 'testProp'
|
||||
})
|
||||
}
|
||||
|
||||
async dispose(){
|
||||
console.log('Deleting Module')
|
||||
}
|
||||
}
|
||||
|
||||
const communicator = new EventLayer(
|
||||
@ -103,13 +107,14 @@ const communicator = new EventLayer(
|
||||
'generic'
|
||||
);
|
||||
|
||||
const local = new nopeDispatcher({ communicator }, () => new NopeObservable());
|
||||
const remote = getLinkedDispatcher({ communicator });
|
||||
const remote_01 = new nopeDispatcher({ communicator }, () => new NopeObservable());
|
||||
const remote_02 = new nopeDispatcher({ communicator }, () => new NopeObservable());
|
||||
const srv = getLinkedDispatcher({ communicator });
|
||||
|
||||
|
||||
const main = async () => {
|
||||
|
||||
remote.provideInstanceGeneratorForExternalDispatchers('helloworld', async (dispather, identifier) => {
|
||||
srv.provideInstanceGeneratorForExternalDispatchers('helloworld', async (dispather, identifier) => {
|
||||
const mod = new HelloWorldModule(dispather);
|
||||
mod.identifier = identifier;
|
||||
|
||||
@ -117,7 +122,7 @@ const main = async () => {
|
||||
return mod;
|
||||
});
|
||||
|
||||
local.registerInternalInstanceGenerator('helloworld', async (dispather, description) => {
|
||||
remote_01.registerInternalInstanceGenerator('helloworld', async (dispather, description) => {
|
||||
const mod = new NopeGenericModule(dispather, () => new NopeObservable());
|
||||
await mod.fromDescription(description, 'overwrite');
|
||||
await mod.init();
|
||||
@ -126,10 +131,25 @@ const main = async () => {
|
||||
return mod;
|
||||
});
|
||||
|
||||
const instance_01 = await local.generateInstance<IHelloWorlModule>({
|
||||
remote_02.registerInternalInstanceGenerator('helloworld', async (dispather, description) => {
|
||||
const mod = new NopeGenericModule(dispather, () => new NopeObservable());
|
||||
await mod.fromDescription(description, 'overwrite');
|
||||
await mod.init();
|
||||
|
||||
console.log('Created HelloWorldModule-Wrapper with name', description.identifier);
|
||||
return mod;
|
||||
});
|
||||
|
||||
const instance_01 = await remote_01.generateInstance<IHelloWorlModule>({
|
||||
identifier: 'instance_01',
|
||||
params: ['hello', 'world'],
|
||||
type: 'helloworld'
|
||||
type: 'helloworld',
|
||||
});
|
||||
|
||||
const copy_of_instance_01 = await remote_01.generateInstance<IHelloWorlModule>({
|
||||
identifier: 'instance_01',
|
||||
params: ['hello', 'world'],
|
||||
type: 'helloworld',
|
||||
});
|
||||
|
||||
// await instance_01.init();
|
||||
@ -149,6 +169,22 @@ const main = async () => {
|
||||
console.log('Got Update by subscribing');
|
||||
console.log('Updating Variable by updateTestProp Function');
|
||||
await instance_01.updateTestProp();
|
||||
|
||||
|
||||
console.log('Creating new instance on other remote');
|
||||
const instance_02 = await remote_02.generateInstance<IHelloWorlModule>({
|
||||
identifier: 'instance_01',
|
||||
params: ['hello', 'world'],
|
||||
type: 'helloworld',
|
||||
});
|
||||
|
||||
console.log('Delte Copies etc');
|
||||
|
||||
remote_01.deleteInstance(instance_01);
|
||||
remote_01.deleteInstance(copy_of_instance_01);
|
||||
console.log('Delete Instance 2')
|
||||
remote_02.deleteInstance(instance_02);
|
||||
|
||||
|
||||
await sleep(100);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user