201 lines
7.1 KiB
TypeScript
201 lines
7.1 KiB
TypeScript
/**
|
|
* @author Martin Karkowski
|
|
* @email m.karkowski@zema.de
|
|
* @create date 2020-10-12 18:53:00
|
|
* @modify date 2020-11-05 13:53:28
|
|
* @desc [description]
|
|
*/
|
|
|
|
import { inject, injectable } from "inversify";
|
|
import { DISPATCHER_INSTANCE, OBSERVABLE_FACTORY } from "../symbols/identifiers";
|
|
import { ICallOptions } from "../types/communication.interface";
|
|
import { INopeDispatcher } from "../types/nopeDispatcher.interface";
|
|
import { IFunctionOptions, INopeModuleDescription, IPropertyOptions } from "../types/nopeModule.interface";
|
|
import { INopeObservable } from "../types/nopeObservable.interface";
|
|
import { INopePromise } from "../types/nopePromise.interface";
|
|
import { NopeBaseModule } from "./BaseModule";
|
|
|
|
@injectable()
|
|
export class NopeGenericModule extends NopeBaseModule {
|
|
|
|
public dynamicInstanceMethods: { [index: string]: <T>(...args) => INopePromise<T> } = {};
|
|
public dynamicInstanceProperties: {[index: string]: INopeObservable<any>} = {};
|
|
public dynamicInstanceMethodsWithOptions: { [index: string]: <T>(options: Partial<ICallOptions>, ...args) => INopePromise<T> } = {};
|
|
|
|
|
|
protected _description: INopeModuleDescription;
|
|
|
|
/**
|
|
* Function, used to add the Attributes based on the Description.
|
|
*
|
|
* @param {INopeModuleDescription} description
|
|
* @param {('overwrite' | 'add')} [mode='overwrite']
|
|
* @memberof NopeGenericModule
|
|
*/
|
|
public fromDescription(description: INopeModuleDescription, mode:'overwrite' | 'add' = 'overwrite'){
|
|
|
|
const _this = this;
|
|
|
|
if (mode === 'overwrite'){
|
|
this.dispose();
|
|
|
|
this.author = description.author;
|
|
this.description = description.description;
|
|
this.type = description.type;
|
|
this.identifier = description.identifier;
|
|
}
|
|
|
|
if (this.author == null){
|
|
this.author = description.author;
|
|
}
|
|
|
|
if (this.description == null){
|
|
this.description = description.description;
|
|
}
|
|
|
|
if (this.version == null){
|
|
this.version = description.version;
|
|
}
|
|
|
|
if (this.identifier == null){
|
|
this.identifier = description.identifier;
|
|
}
|
|
|
|
for (const name in description.functions){
|
|
const options = description.functions[name];
|
|
const func = (...args) => {
|
|
return _this._dispatcher.performCall(options.id, args, options);
|
|
};
|
|
const funcWithCustomOptions = (_options:Partial<ICallOptions>, ...args) => {
|
|
return _this._dispatcher.performCall(options.id, args, Object.assign({}, options, _options ));
|
|
}
|
|
|
|
if (this.dynamicInstanceMethods[name]){
|
|
throw Error('Name alread used. Not able to use the method name twice')
|
|
}
|
|
(this.dynamicInstanceMethods as any)[name] = func;
|
|
if (this.dynamicInstanceMethodsWithOptions[name]){
|
|
throw Error('Name alread used. Not able to use the method name twice')
|
|
}
|
|
(this.dynamicInstanceMethodsWithOptions as any)[name] = funcWithCustomOptions;
|
|
// If the Function isnt dynamic, register it on the Object itself.
|
|
if (!options.isDynamic) {
|
|
if (this[name]){
|
|
throw Error('Name alread used. Not able to use the method name twice')
|
|
}
|
|
this[name] = func;
|
|
}
|
|
|
|
this._registeredFunctions.set(name, {
|
|
func,
|
|
options
|
|
});
|
|
}
|
|
|
|
for (const name in description.properties){
|
|
const options = description.properties[name];
|
|
|
|
// Add only elements, that are subscribed.
|
|
// Properties, which are only publishing
|
|
// should throw an error, if data is published
|
|
// in a remote. This is done to maintain
|
|
// consistency.
|
|
// let mode = prop.mode;
|
|
|
|
if (this.dynamicInstanceProperties[name]){
|
|
throw Error('Name alread used. Not able to use the method name twice')
|
|
}
|
|
|
|
// Make shure it isnt published.
|
|
// options.preventSendingToRegistery = true;
|
|
|
|
// Register the Observable:
|
|
this.dynamicInstanceProperties[name] = this._dispatcher.registerObservable(
|
|
// Assign a new Observable.
|
|
this._observableFactory(),
|
|
// Use the provided Properties:
|
|
options
|
|
);
|
|
|
|
if (!options.isDynamic) {
|
|
if (this[name]){
|
|
throw Error('Name alread used. Not able to use the method name twice')
|
|
}
|
|
// Use the Same Element.
|
|
this[name] = this.dynamicInstanceProperties[name];
|
|
}
|
|
|
|
this._registeredProperties.set(name, {
|
|
observable: this.dynamicInstanceProperties[name],
|
|
options
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates an instance of NopeGenericModule.
|
|
* @param {INopeDispatcher} _dispatcher
|
|
* @param {() => INopeObservable<any>} _observableFactory
|
|
* @memberof NopeGenericModule
|
|
*/
|
|
constructor(
|
|
@inject(DISPATCHER_INSTANCE) _dispatcher: INopeDispatcher,
|
|
@inject(OBSERVABLE_FACTORY) protected _observableFactory: () => INopeObservable<any>
|
|
) {
|
|
super(_dispatcher);
|
|
}
|
|
|
|
public async listFunctions(): Promise<{ func: (...args: any[]) => Promise<any>; options: IFunctionOptions; }[]> {
|
|
const _this =this;
|
|
return Object.getOwnPropertyNames(this.dynamicInstanceMethods).map(name => {
|
|
return {
|
|
func: _this.dynamicInstanceMethods[name],
|
|
options: null
|
|
}
|
|
});
|
|
}
|
|
|
|
public async registerProperty<T, K = any, S = T, G = T>(name: string, observable: INopeObservable<T, S, G>, options: IPropertyOptions<K>): Promise<void> {
|
|
throw Error('Function Should not be called on remote!');
|
|
}
|
|
|
|
public async registerMethod(name: string, func: (...args: any[]) => Promise<any>, options: IFunctionOptions): Promise<void> {
|
|
throw Error('Function Should not be called on remote!');
|
|
}
|
|
|
|
public async unregisterFunction(name: string): Promise<void> {
|
|
throw Error('Function Should not be called on remote!');
|
|
}
|
|
|
|
public async unregisterProperty<T, K = any, S = T, G = T>(name: string): Promise<void> {
|
|
throw Error('Function Should not be called on remote!');
|
|
}
|
|
|
|
public async init(): Promise<void> {
|
|
try {
|
|
await super.init();
|
|
} catch (e) {
|
|
throw Error('Call fromDescription before using');
|
|
}
|
|
}
|
|
|
|
public async dispose(){
|
|
for (const name in this.dynamicInstanceProperties){
|
|
this.dynamicInstanceProperties[name].dispose();
|
|
// Remove Reference
|
|
delete this[name];
|
|
}
|
|
|
|
this._registeredFunctions.clear();
|
|
|
|
this.dynamicInstanceProperties = {};
|
|
|
|
for (const name in this.dynamicInstanceMethods) {
|
|
delete this[name];
|
|
delete this.dynamicInstanceMethods[name];
|
|
}
|
|
|
|
this._registeredProperties.clear();
|
|
}
|
|
} |