nope/lib/module/GenericModule.ts

218 lines
7.4 KiB
TypeScript
Raw Normal View History

2020-10-13 13:18:25 +00:00
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-10-12 18:53:00
2020-11-24 14:14:56 +00:00
* @modify date 2020-11-23 08:12:29
2020-10-13 13:18:25 +00:00
* @desc [description]
*/
import { inject, injectable } from "inversify";
import { DISPATCHER_INSTANCE, OBSERVABLE_FACTORY } from "../symbols/identifiers";
2020-11-09 08:46:06 +00:00
import { ICallOptions } from "../types/nope/nopeCommunication.interface";
2020-11-06 08:10:30 +00:00
import { INopeDispatcher } from "../types/nope/nopeDispatcher.interface";
import { IFunctionOptions, INopeModuleDescription, IPropertyOptions } from "../types/nope/nopeModule.interface";
import { INopeObservable } from "../types/nope/nopeObservable.interface";
import { INopePromise } from "../types/nope/nopePromise.interface";
2020-10-13 13:18:25 +00:00
import { NopeBaseModule } from "./BaseModule";
@injectable()
export class NopeGenericModule extends NopeBaseModule {
2020-11-24 14:14:56 +00:00
private _type = "";
/**
*
* Return the Class Identifier.
*/
public get type(): string {
return this._type;
}
/**
* Return the Class Identifier.
*/
public set type(value: string) {
this._type = value;
}
2020-11-04 16:33:36 +00:00
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> } = {};
2020-10-13 13:18:25 +00:00
protected _description: INopeModuleDescription;
/**
* Function, used to add the Attributes based on the Description.
*
* @param {INopeModuleDescription} description
* @param {('overwrite' | 'add')} [mode='overwrite']
* @memberof NopeGenericModule
*/
2020-11-24 14:14:56 +00:00
public fromDescription(description: INopeModuleDescription, mode:"overwrite" | "add" = "overwrite"): void{
2020-10-13 13:18:25 +00:00
const _this = this;
2020-11-24 14:14:56 +00:00
if (mode === "overwrite"){
2020-10-13 13:18:25 +00:00
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];
2020-11-04 16:33:36 +00:00
const func = (...args) => {
return _this._dispatcher.performCall(options.id, args, options);
2020-10-13 13:18:25 +00:00
};
2020-11-04 16:33:36 +00:00
const funcWithCustomOptions = (_options:Partial<ICallOptions>, ...args) => {
return _this._dispatcher.performCall(options.id, args, Object.assign({}, options, _options ));
2020-11-24 14:14:56 +00:00
};
2020-10-13 13:18:25 +00:00
if (this.dynamicInstanceMethods[name]){
2020-11-24 14:14:56 +00:00
throw Error("Name alread used. Not able to use the method name twice");
2020-10-13 13:18:25 +00:00
}
(this.dynamicInstanceMethods as any)[name] = func;
2020-11-04 16:33:36 +00:00
if (this.dynamicInstanceMethodsWithOptions[name]){
2020-11-24 14:14:56 +00:00
throw Error("Name alread used. Not able to use the method name twice");
2020-11-04 16:33:36 +00:00
}
(this.dynamicInstanceMethodsWithOptions as any)[name] = funcWithCustomOptions;
2020-10-13 13:18:25 +00:00
// If the Function isnt dynamic, register it on the Object itself.
if (!options.isDynamic) {
if (this[name]){
2020-11-24 14:14:56 +00:00
throw Error("Name alread used. Not able to use the method name twice");
2020-10-13 13:18:25 +00:00
}
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]){
2020-11-24 14:14:56 +00:00
throw Error("Name alread used. Not able to use the method name twice");
2020-10-13 13:18:25 +00:00
}
// Make shure it isnt published.
2020-10-13 16:22:04 +00:00
// options.preventSendingToRegistery = true;
2020-10-13 13:18:25 +00:00
// 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]){
2020-11-24 14:14:56 +00:00
throw Error("Name alread used. Not able to use the method name twice");
2020-10-13 13:18:25 +00:00
}
// Use the Same Element.
this[name] = this.dynamicInstanceProperties[name];
}
this._registeredProperties.set(name, {
observable: this.dynamicInstanceProperties[name],
options
});
}
}
2020-10-13 16:22:04 +00:00
/**
* Creates an instance of NopeGenericModule.
* @param {INopeDispatcher} _dispatcher
* @param {() => INopeObservable<any>} _observableFactory
* @memberof NopeGenericModule
*/
2020-10-13 13:18:25 +00:00
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
2020-11-24 14:14:56 +00:00
};
2020-10-13 16:22:04 +00:00
});
2020-10-13 13:18:25 +00:00
}
public async registerProperty<T, K = any, S = T, G = T>(name: string, observable: INopeObservable<T, S, G>, options: IPropertyOptions<K>): Promise<void> {
2020-11-24 14:14:56 +00:00
throw Error("Function Should not be called on remote!");
2020-10-13 13:18:25 +00:00
}
2020-11-05 17:02:29 +00:00
public async registerMethod(name: string, func: (...args: any[]) => Promise<any>, options: IFunctionOptions): Promise<void> {
2020-11-24 14:14:56 +00:00
throw Error("Function Should not be called on remote!");
2020-10-13 13:18:25 +00:00
}
public async unregisterFunction(name: string): Promise<void> {
2020-11-24 14:14:56 +00:00
throw Error("Function Should not be called on remote!");
2020-10-13 13:18:25 +00:00
}
2020-11-06 08:10:30 +00:00
public async unregisterProperty(name: string): Promise<void> {
2020-11-24 14:14:56 +00:00
throw Error("Function Should not be called on remote!");
2020-10-13 13:18:25 +00:00
}
public async init(): Promise<void> {
try {
await super.init();
} catch (e) {
2020-11-24 14:14:56 +00:00
throw Error("Call fromDescription before using");
2020-10-13 13:18:25 +00:00
}
}
2020-11-24 14:14:56 +00:00
public async dispose(): Promise<void> {
2020-10-13 13:18:25 +00:00
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();
}
}