nope/lib/module/GenericModule.ts

193 lines
6.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-10-13 16:22:04 +00:00
* @modify date 2020-10-13 18:19:43
2020-10-13 13:18:25 +00:00
* @desc [description]
*/
import { inject, injectable } from "inversify";
import { DISPATCHER_INSTANCE, OBSERVABLE_FACTORY } from "../symbols/identifiers";
import { INopeDispatcher } from "../types/nopeDispatcher.interface";
2020-10-13 16:22:04 +00:00
import { IFunctionOptions, INopeModuleDescription, IPropertyOptions } from "../types/nopeModule.interface";
2020-10-13 13:18:25 +00:00
import { INopeObservable } from "../types/nopeObservable.interface";
import { NopeBaseModule } from "./BaseModule";
export interface ICallableObject { [index: string]: <T>(...args) => Promise<T> }
@injectable()
export class NopeGenericModule extends NopeBaseModule {
dynamicInstanceMethods: ICallableObject = {};
dynamicInstanceProperties: {[index: string]: INopeObservable<any>} = {};
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 = async (...args) => {
return await _this._dispatcher.performCall(options.id, args, 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 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.
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]){
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
});
}
}
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-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> {
throw Error('Function Should not be called on remote!');
}
public async registerFunction(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();
}
}