From 881456b2ca0409eed5e32578223c7809c66ca3dd Mon Sep 17 00:00:00 2001 From: Martin Karkowski Date: Sat, 29 Oct 2022 07:52:14 +0200 Subject: [PATCH] # 1.4.4 - Modified: - Renamed the decorator `exportFunctionAsNopeService` -> `exportAsNopeService` and the Interface `IexportFunctionAsNopeServiceParameters` -> `IexportAsNopeServiceParameters` - `NopeInstanceManager` and `GenericWrapper`: Now receives a factory to generate the a `NopeEventEmitter`: - This affects a lot packages. - `NopeModule`: - renamed `listFunctions` to `listMethods` - renamed `functions` is now called `methods` - The Description format is being updated (`functions` is now called `methods`) - Fixes: - `NopeModule`: - Now disposes Emitters as Properties as well - `getIdentifierOf` checks event emitters as well now. - `GenericWrapper`: - Now automatically registers emitters as well. - Added: - `NopeModule`: Added the method `listEvents` (to show the available Emitters registered as Properties.) --- CHANGELOG.md | 21 ++++ lib/analyzers/typescript/defaults/names.ts | 2 +- lib/cli/cli.ts | 5 +- lib/decorators/container.ts | 4 +- lib/decorators/functionDecorators.ts | 6 +- lib/decorators/index.ts | 4 +- .../ConnectivityManager.spec.ts | 2 +- lib/dispatcher/Core/NopeCore.spec.ts | 9 ++ lib/dispatcher/Core/NopeCore.ts | 8 +- .../InstanceManager/InstanceManager.ts | 19 +-- lib/dispatcher/getDispatcher.ts | 8 +- lib/dispatcher/getLinkedDispatcher.ts | 4 +- lib/dispatcher/index.ts | 4 +- lib/dispatcher/nopeDispatcher.injectable.ts | 11 +- lib/dispatcher/nopeDispatcher.ts | 4 +- lib/loader/generateNopeBasicPackage.ts | 16 +++ lib/loader/nopePackageLoader.ts | 6 +- lib/module/BaseModule.ts | 112 ++++++++++++++---- lib/module/GenericWrapper.injectable.ts | 8 +- lib/module/GenericWrapper.ts | 81 ++++++++++--- lib/symbols/identifiers.ts | 2 + lib/types/nope/nopeDispatcher.interface.ts | 15 ++- .../nope/nopeInstanceManager.interface.ts | 10 +- lib/types/nope/nopeModule.interface.ts | 4 +- lib/types/nope/nopePackageLoader.interface.ts | 4 +- 25 files changed, 277 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eb5ab1..ea6f616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -293,3 +293,24 @@ Inital commit, which is working with the browser - adapted `NopePubSub`: - renamed parameter `mqttBasedPatternSubscriptions` to `mqttPatternBasedSubscriptions` - `helpers/path` -> in `_getLeastCommonPathSegment` we only iterate over the avaible keys. + +# 1.4.4 + - Modified: + - Renamed the decorator `exportFunctionAsNopeService` -> `exportAsNopeService` and the Interface `IexportFunctionAsNopeServiceParameters` -> `IexportAsNopeServiceParameters` + - `NopeInstanceManager` and `GenericWrapper`: Now receives a factory to generate the a `NopeEventEmitter`: + - This affects a lot packages. + - `NopeModule`: + - renamed `listFunctions` to `listMethods` + - renamed `functions` is now called `methods` + - The Description format is being updated (`functions` is now called `methods`) + - Fixes: + - `NopeModule`: + - Now disposes Emitters as Properties as well + - `getIdentifierOf` checks event emitters as well now. + - `GenericWrapper`: + - Now automatically registers emitters as well. + - Added: + - `NopeModule`: Added the method `listEvents` (to show the available Emitters registered as Properties.) + + + \ No newline at end of file diff --git a/lib/analyzers/typescript/defaults/names.ts b/lib/analyzers/typescript/defaults/names.ts index a06b7db..158a92d 100644 --- a/lib/analyzers/typescript/defaults/names.ts +++ b/lib/analyzers/typescript/defaults/names.ts @@ -7,4 +7,4 @@ export const NAME_GENERICMODULE = "NopeGenericModule"; export const NAME_METHOD_DEC = "nopeMethod"; export const NAME_EMITTER_DEC = "nopeEmitter"; export const NAME_PROP_DEC = "nopeProperty"; -export const NAME_FUNC_DEC = "exportFunctionAsNopeService"; +export const NAME_FUNC_DEC = "exportAsNopeService"; diff --git a/lib/cli/cli.ts b/lib/cli/cli.ts index 09d8226..bf834ad 100644 --- a/lib/cli/cli.ts +++ b/lib/cli/cli.ts @@ -476,7 +476,7 @@ export async function interact( type: "search-list", message: "Select the instance", name: "service", - choices: Object.keys(instanceDescription.functions).sort(), + choices: Object.keys(instanceDescription.methods).sort(), }, ]) ).service; @@ -492,8 +492,7 @@ export async function interact( logger.info("Accessor Generated"); // Now we know, which service we are trying to call. if ( - instanceDescription.functions[service].schema?.inputs?.length == - 0 + instanceDescription.methods[service].schema?.inputs?.length == 0 ) { try { // Now we execute the service diff --git a/lib/decorators/container.ts b/lib/decorators/container.ts index 9278170..37c8372 100644 --- a/lib/decorators/container.ts +++ b/lib/decorators/container.ts @@ -7,7 +7,7 @@ import { getSingleton } from "../helpers/singletonMethod"; import { IFunctionOptions, INopeModule } from "../types"; -export type IexportFunctionAsNopeServiceParameters = IFunctionOptions; +export type IexportAsNopeServiceParameters = IFunctionOptions; /** * Return the central loger. This logger is a singleton (see {@link getSingleton}) @@ -22,7 +22,7 @@ export function getCentralDecoratedContainer(): { { uri: string; callback: (...args) => Promise; - options: IexportFunctionAsNopeServiceParameters; + options: IexportAsNopeServiceParameters; } >; classes: Map; diff --git a/lib/decorators/functionDecorators.ts b/lib/decorators/functionDecorators.ts index e98c2fc..b2cbe20 100644 --- a/lib/decorators/functionDecorators.ts +++ b/lib/decorators/functionDecorators.ts @@ -6,7 +6,7 @@ import { getCentralDecoratedContainer, - IexportFunctionAsNopeServiceParameters, + IexportAsNopeServiceParameters, } from "./container"; const CONTAINER = getCentralDecoratedContainer(); @@ -23,9 +23,9 @@ export type callable = { * @param func The Function * @param options The Options. */ -export function exportFunctionAsNopeService( +export function exportAsNopeService( func: T, - options: IexportFunctionAsNopeServiceParameters + options: IexportAsNopeServiceParameters ) { // Only add the element if it doesnt exists. if (!CONTAINER.services.has(options.id)) { diff --git a/lib/decorators/index.ts b/lib/decorators/index.ts index 6d4de1e..a763695 100644 --- a/lib/decorators/index.ts +++ b/lib/decorators/index.ts @@ -5,7 +5,7 @@ export { getCentralDecoratedContainer, - IexportFunctionAsNopeServiceParameters, + IexportAsNopeServiceParameters, } from "./container"; -export { exportFunctionAsNopeService } from "./functionDecorators"; +export { exportAsNopeService } from "./functionDecorators"; export { nopeEmitter, nopeMethod, nopeProperty } from "./moduleDecorators"; diff --git a/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts b/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts index 966e42b..f3024de 100644 --- a/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts +++ b/lib/dispatcher/ConnectivityManager/ConnectivityManager.spec.ts @@ -196,7 +196,7 @@ describe("NopeConnectivityManager", function () { // Dispose our Delay. first.dispose(true); - expect(end - adapted).to.be.equal(0, "There should not be an delta."); + expect(end - adapted < 1).to.be.true("There should not be an delta."); }); it("master", async () => { diff --git a/lib/dispatcher/Core/NopeCore.spec.ts b/lib/dispatcher/Core/NopeCore.spec.ts index b5c1e65..5c30cfc 100644 --- a/lib/dispatcher/Core/NopeCore.spec.ts +++ b/lib/dispatcher/Core/NopeCore.spec.ts @@ -10,6 +10,7 @@ import { expect } from "chai"; import { beforeEach, describe, it } from "mocha"; import "reflect-metadata"; import { getLayer } from "../../communication/getLayer.nodejs"; +import { NopeEventEmitter } from "../../eventEmitter"; import { NopeObservable } from "../../observables/nopeObservable"; import { NopeCore } from "./NopeCore"; @@ -20,6 +21,7 @@ describe("NopeCore", function () { communicator: getLayer("event", "", false), logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "first" ); @@ -38,6 +40,7 @@ describe("NopeCore", function () { communicator: getLayer("event", "", false), logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "first" ); @@ -58,6 +61,7 @@ describe("NopeCore", function () { communicator, logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "second" ); @@ -74,6 +78,7 @@ describe("NopeCore", function () { communicator, logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "first" ); @@ -83,6 +88,7 @@ describe("NopeCore", function () { communicator, logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "second" ); @@ -114,6 +120,7 @@ describe("NopeCore", function () { communicator, logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "second" ); @@ -130,6 +137,7 @@ describe("NopeCore", function () { communicator, logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "first" ); @@ -139,6 +147,7 @@ describe("NopeCore", function () { communicator, logger: false, }, + () => new NopeEventEmitter(), () => new NopeObservable(), "second" ); diff --git a/lib/dispatcher/Core/NopeCore.ts b/lib/dispatcher/Core/NopeCore.ts index b64c851..48ea2f5 100644 --- a/lib/dispatcher/Core/NopeCore.ts +++ b/lib/dispatcher/Core/NopeCore.ts @@ -16,13 +16,17 @@ import { INopeConnectivityManager, INopeCore, INopeDispatcherOptions, + INopeEventEmitter, INopeInstanceManager, INopeObservable, INopeRpcManager, IPubSubSystem, } from "../../types/nope"; import { NopeConnectivityManager } from "../ConnectivityManager"; -import { NopeInstanceManager } from "../InstanceManager"; +import { + generateAssignmentChecker, + NopeInstanceManager, +} from "../InstanceManager"; import { generateSelector, NopeRpcManager } from "../RpcManager"; export class NopeCore implements INopeCore { @@ -39,6 +43,7 @@ export class NopeCore implements INopeCore { constructor( public options: INopeDispatcherOptions, + protected generateEmitter: () => INopeEventEmitter, protected generateObservable: () => INopeObservable, public readonly id: string = null ) { @@ -85,6 +90,7 @@ export class NopeCore implements INopeCore { // Create our Instance Manager this.instanceManager = new NopeInstanceManager( options, + generateEmitter, generateObservable, defaultSelector, this.id, diff --git a/lib/dispatcher/InstanceManager/InstanceManager.ts b/lib/dispatcher/InstanceManager/InstanceManager.ts index ac596d3..5359fe6 100644 --- a/lib/dispatcher/InstanceManager/InstanceManager.ts +++ b/lib/dispatcher/InstanceManager/InstanceManager.ts @@ -24,6 +24,7 @@ import { INopeConnectivityManager, INopeCore, INopeDispatcherOptions, + INopeEventEmitter, INopeModule, INopeModuleDescription, INopeObservable, @@ -161,10 +162,11 @@ export class NopeInstanceManager implements INopeInstanceManager { */ constructor( public options: INopeDispatcherOptions, + protected _generateEmitter: () => INopeEventEmitter, protected _generateObservable: () => INopeObservable, protected _defaultSelector: ValidSelectorFunction, protected readonly _id: string = null, - protected _statusManager: INopeConnectivityManager = null, + protected _connectivityManager: INopeConnectivityManager = null, protected _rpcManager: INopeRpcManager = null, protected _core: INopeCore = null ) { @@ -174,9 +176,9 @@ export class NopeInstanceManager implements INopeInstanceManager { this._id = generateId(); } - if (_statusManager == null) { + if (_connectivityManager == null) { // Creating a new Status-Manager. - this._statusManager = new NopeConnectivityManager( + this._connectivityManager = new NopeConnectivityManager( options, _generateObservable, this._id @@ -295,7 +297,7 @@ export class NopeInstanceManager implements INopeInstanceManager { // Wait until the Element is connected. await this._communicator.connected.waitFor(); - await this._statusManager.ready.waitFor(); + await this._connectivityManager.ready.waitFor(); await this._rpcManager.ready.waitFor(); this.registerInternalWrapperGenerator( @@ -303,6 +305,7 @@ export class NopeInstanceManager implements INopeInstanceManager { async (dispather, description) => { const mod = new NopeGenericWrapper( dispather, + _this._generateEmitter, _this._generateObservable ); await mod.fromDescription(description, "overwrite"); @@ -311,7 +314,7 @@ export class NopeInstanceManager implements INopeInstanceManager { ); // We will use our status-manager to listen to changes. - this._statusManager.dispatchers.onChange.subscribe((changes) => { + this._connectivityManager.dispatchers.onChange.subscribe((changes) => { if (changes.added.length) { // If there are dispatchers online, // We will emit our available services. @@ -591,8 +594,10 @@ export class NopeInstanceManager implements INopeInstanceManager { }, } ); + // Store the Generator. this._registeredConstructors.set(identifier, _cb); + // TODO: Send an update. } // See interface description @@ -663,7 +668,7 @@ export class NopeInstanceManager implements INopeInstanceManager { // First we will check if the instance is available internally. if (this._internalInstances.has(identifier)) { - return this._statusManager.info; + return this._connectivityManager.info; } // If that isnt the case, we will check all dispatchers and search the instance. @@ -673,7 +678,7 @@ export class NopeInstanceManager implements INopeInstanceManager { ] of this._mappingOfRemoteDispatchersAndInstances.entries()) { for (const instance of msg.instances) { if (instance.identifier == identifier) { - return this._statusManager.getStatus(dispatcher); + return this._connectivityManager.getStatus(dispatcher); } } } diff --git a/lib/dispatcher/getDispatcher.ts b/lib/dispatcher/getDispatcher.ts index 4877bcf..adae8f0 100644 --- a/lib/dispatcher/getDispatcher.ts +++ b/lib/dispatcher/getDispatcher.ts @@ -3,6 +3,7 @@ * @email m.karkowski@zema.de */ +import { NopeEventEmitter } from "../eventEmitter"; import { getSingleton } from "../helpers/singletonMethod"; import { NopeGenericWrapper } from "../module/GenericWrapper"; import { NopeObservable } from "../observables/nopeObservable"; @@ -54,6 +55,7 @@ export function getDispatcher( const create = () => { const dispatcher = new options.dispatcherConstructorClass( dispatcherOptions, + () => new NopeEventEmitter(), () => new NopeObservable() ); @@ -62,7 +64,11 @@ export function getDispatcher( dispatcher.instanceManager.registerInternalWrapperGenerator( "*", async (core, description) => { - const mod = new NopeGenericWrapper(core, () => new NopeObservable()); + const mod = new NopeGenericWrapper( + core, + () => new NopeEventEmitter(), + () => new NopeObservable() + ); await mod.fromDescription(description, "overwrite"); // await mod.init(); return mod; diff --git a/lib/dispatcher/getLinkedDispatcher.ts b/lib/dispatcher/getLinkedDispatcher.ts index d486580..ee15606 100644 --- a/lib/dispatcher/getLinkedDispatcher.ts +++ b/lib/dispatcher/getLinkedDispatcher.ts @@ -6,7 +6,7 @@ * @desc [description] */ -import { IexportFunctionAsNopeServiceParameters } from "../decorators/index"; +import { IexportAsNopeServiceParameters } from "../decorators/index"; import { getSingleton } from "../helpers/singletonMethod"; import { INopeDispatcher, @@ -31,7 +31,7 @@ export function getLinkedDispatcher( { uri: string; callback: (...args) => Promise; - options: IexportFunctionAsNopeServiceParameters; + options: IexportAsNopeServiceParameters; } >(); }); diff --git a/lib/dispatcher/index.ts b/lib/dispatcher/index.ts index b7afe8f..a8d2e25 100644 --- a/lib/dispatcher/index.ts +++ b/lib/dispatcher/index.ts @@ -68,8 +68,8 @@ import * as instanceManager from "./InstanceManager"; import * as rpcManager from "./RpcManager"; export { - exportFunctionAsNopeService, - IexportFunctionAsNopeServiceParameters, + exportAsNopeService, + IexportAsNopeServiceParameters, nopeEmitter, nopeMethod, nopeProperty, diff --git a/lib/dispatcher/nopeDispatcher.injectable.ts b/lib/dispatcher/nopeDispatcher.injectable.ts index 64aa671..eb01f02 100644 --- a/lib/dispatcher/nopeDispatcher.injectable.ts +++ b/lib/dispatcher/nopeDispatcher.injectable.ts @@ -7,7 +7,12 @@ */ import { inject, injectable } from "inversify"; -import { DISPATCHER_OPTIONS, OBSERVABLE_FACTORY } from "../symbols/identifiers"; +import { + DISPATCHER_OPTIONS, + EMITTER_FACTORY, + OBSERVABLE_FACTORY, +} from "../symbols/identifiers"; +import { INopeEventEmitter } from "../types"; import { INopeDispatcherOptions } from "../types/nope/nopeDispatcher.interface"; import { INopeObservable } from "../types/nope/nopeObservable.interface"; import { NopeDispatcher } from "./nopeDispatcher"; @@ -16,9 +21,11 @@ import { NopeDispatcher } from "./nopeDispatcher"; export class InjectableNopeDispatcher extends NopeDispatcher { constructor( @inject(DISPATCHER_OPTIONS) public options: INopeDispatcherOptions, + @inject(EMITTER_FACTORY) + protected _generateEmitter: () => INopeEventEmitter, @inject(OBSERVABLE_FACTORY) protected _generateObservable: () => INopeObservable ) { - super(options, _generateObservable); + super(options, _generateEmitter, _generateObservable); } } diff --git a/lib/dispatcher/nopeDispatcher.ts b/lib/dispatcher/nopeDispatcher.ts index 867cf0a..0e76a08 100644 --- a/lib/dispatcher/nopeDispatcher.ts +++ b/lib/dispatcher/nopeDispatcher.ts @@ -26,7 +26,7 @@ import { NopeCore } from "./Core"; */ export class NopeDispatcher extends NopeCore implements INopeDispatcher { public get masterExists(): boolean { - return false; + return this.connectivityManager.master.isMasterForced; } // See interface description @@ -108,7 +108,7 @@ export class NopeDispatcher extends NopeCore implements INopeDispatcher { return Object.assign(this.connectivityManager.info, { isMaster: this.connectivityManager.isMaster, instances: this.instanceManager.instances.data.getContent(), - services: [], + services: this.rpcManager.services.data.getContent(), events: this.eventDistributor.emitters, properties: this.dataDistributor.emitters, // Show the data. diff --git a/lib/loader/generateNopeBasicPackage.ts b/lib/loader/generateNopeBasicPackage.ts index 2432f89..c2f7bc3 100644 --- a/lib/loader/generateNopeBasicPackage.ts +++ b/lib/loader/generateNopeBasicPackage.ts @@ -7,6 +7,7 @@ import { decorate, injectable } from "inversify"; import { getDispatcher } from "../dispatcher/getDispatcher"; import { NopeDispatcher } from "../dispatcher/nopeDispatcher"; +import { InjectableNopeEventEmitter } from "../eventEmitter"; import { NopeBaseModule } from "../module/BaseModule"; import { NopeObservable } from "../observables/nopeObservable"; import { InjectableNopeObservable } from "../observables/nopeObservable.injectable"; @@ -14,6 +15,8 @@ import { COMMUNICATION_LAYER, DISPATCHER_INSTANCE, DISPATCHER_OPTIONS, + EMITTER_FACTORY, + EMITTER_INSTANCE, OBSERVABLE_FACTORY, OBSERVABLE_INSTANCE, } from "../symbols/identifiers"; @@ -39,7 +42,9 @@ export function generateNopeBasicPackage( const TYPES = { dispatcher: DISPATCHER_INSTANCE, observableFactory: OBSERVABLE_FACTORY, + emitterFactory: EMITTER_FACTORY, observable: OBSERVABLE_INSTANCE, + emitter: EMITTER_INSTANCE, communicationLayer: COMMUNICATION_LAYER, dispatcherOptions: DISPATCHER_OPTIONS, }; @@ -83,6 +88,17 @@ export function generateNopeBasicPackage( allowInstanceGeneration: false, }, }, + { + description: { + name: "nopeEmitter", + selector: TYPES.emitter, + factorySelector: TYPES.emitterFactory, + type: InjectableNopeEventEmitter, + }, + settings: { + allowInstanceGeneration: false, + }, + }, { description: { name: "nopeObservable", diff --git a/lib/loader/nopePackageLoader.ts b/lib/loader/nopePackageLoader.ts index 5c9cc29..0612511 100644 --- a/lib/loader/nopePackageLoader.ts +++ b/lib/loader/nopePackageLoader.ts @@ -9,7 +9,7 @@ import { flatten, isArguments } from "lodash"; import "reflect-metadata"; import { getCentralDecoratedContainer, - IexportFunctionAsNopeServiceParameters, + IexportAsNopeServiceParameters, } from "../decorators"; import { arraysEqual } from "../helpers/arrayMethods"; import { sleep } from "../helpers/async"; @@ -706,14 +706,14 @@ export class NopePackageLoader implements INopePackageLoader { } /** - * Function to load all decorated elements with the decorators `exportFunctionAsNopeService` + * Function to load all decorated elements with the decorators `exportAsNopeService` * * @param options */ async addDecoratedElements( options: { addServiceCallback?: ( - options: IexportFunctionAsNopeServiceParameters + options: IexportAsNopeServiceParameters ) => Promise; addClassCallback?: (options: INopeModule) => Promise; consider?: Array<"services" | "classes">; diff --git a/lib/module/BaseModule.ts b/lib/module/BaseModule.ts index a9d0d16..561265f 100644 --- a/lib/module/BaseModule.ts +++ b/lib/module/BaseModule.ts @@ -69,10 +69,10 @@ export class NopeBaseModule implements INopeModule { */ public version: IVersion; - protected _registeredFunctions: Map< + protected _registeredMethods: Map< string, { - func: (...args: any[]) => Promise; + method: (...args: any[]) => Promise; options: IFunctionOptions; } >; @@ -99,10 +99,10 @@ export class NopeBaseModule implements INopeModule { * @readonly * @memberof BaseModule */ - public get functions() { + public get methods() { const ret: { [index: string]: IFunctionOptions } = {}; - for (const [name, funcs] of this._registeredFunctions.entries()) { + for (const [name, funcs] of this._registeredMethods.entries()) { ret[name] = funcs.options; } @@ -166,7 +166,7 @@ export class NopeBaseModule implements INopeModule { this.author = null; this.version = null; this.identifier = null; - this._registeredFunctions = new Map(); + this._registeredMethods = new Map(); this._registeredProperties = new Map(); this._registeredEvents = new Map(); this.uiLinks = []; @@ -220,7 +220,10 @@ export class NopeBaseModule implements INopeModule { options.topic.publish ); } + } else { + throw Error("Topic must be provided in the options"); } + const _observable = await this._core.dataDistributor.register( observable, options @@ -251,7 +254,7 @@ export class NopeBaseModule implements INopeModule { options: IEventOptions ): Promise { // Unregister the Function - await this.unregisterEvents(name); + await this.unregisterEvent(name); // Adapt the Topics if ( @@ -295,14 +298,14 @@ export class NopeBaseModule implements INopeModule { * Function used to register a Method. This Method will be available in the shared network. * * @param {string} name Name of the Method, which is used during registration at the dispatcher - * @param {(...args: any[]) => Promise} func The function itself. It must be async. + * @param {(...args: any[]) => Promise} method The function itself. It must be async. * @param {IFunctionOptions} options The Options, used for registering. * @return {*} {Promise} * @memberof NopeBaseModule */ public async registerMethod( name: string, - func: (...args: any[]) => Promise, + method: (...args: any[]) => Promise, options: IFunctionOptions ): Promise { // Unregister the Function @@ -317,11 +320,14 @@ export class NopeBaseModule implements INopeModule { options.id = getMethodPath(this.identifier, name); } - const _func = await this._core.rpcManager.registerService(func, options); + const _method = await this._core.rpcManager.registerService( + method, + options + ); // Register the new Function. - this._registeredFunctions.set(name, { - func: _func, + this._registeredMethods.set(name, { + method: _method, options, }); } @@ -336,21 +342,21 @@ export class NopeBaseModule implements INopeModule { public async unregisterFunction(name: string): Promise { // Test if the Method is already registerd, // If so => unregister it first. - if (this._registeredFunctions.has(name)) { + if (this._registeredMethods.has(name)) { this._core.rpcManager.unregisterService( - this._registeredFunctions.get(name).func + this._registeredMethods.get(name).method ); } } /** - * Helper Function to unregister an Observable (a Property.) + * Helper Function to unregister an Eventbased Property * * @param {string} name Name of the Property, that has been used to register. * @return {*} {Promise} * @memberof NopeBaseModule */ - public async unregisterEvents(name: string): Promise { + public async unregisterEvent(name: string): Promise { // Test if the Property is already registerd, // If so => unregister it first. if (this._registeredEvents.has(name)) { @@ -383,10 +389,10 @@ export class NopeBaseModule implements INopeModule { * @return {*} {Promise<{ func: (...args: any[]) => Promise; options: IFunctionOptions; }[]>} * @memberof NopeBaseModule */ - public async listFunctions(): Promise< + public async listMethods(): Promise< { func: (...args: any[]) => Promise; options: IFunctionOptions }[] > { - return Array.from(this._registeredFunctions.values()); + return Array.from(this._registeredMethods.values()); } /** @@ -401,6 +407,18 @@ export class NopeBaseModule implements INopeModule { return Array.from(this._registeredProperties.values()); } + /** + * Function used to list all available Properties. + * + * @return {*} {Promise, options: IPropertyOptions }>>} + * @memberof NopeBaseModule + */ + public async listEvents(): Promise< + Array<{ emitter: INopeEventEmitter; options: IEventOptions }> + > { + return Array.from(this._registeredEvents.values()); + } + /** * An init Function. Used to initialize the Element. * @@ -478,12 +496,12 @@ export class NopeBaseModule implements INopeModule { */ public async dispose() { // Unregister all Methods and Functions - for (const name of this._registeredFunctions.keys()) { + for (const name of this._registeredMethods.keys()) { await this.unregisterFunction(name); } // Remove all known Functions - this._registeredFunctions.clear(); + this._registeredMethods.clear(); // Unregister all Properties. for (const name of this._registeredProperties.keys()) { @@ -492,17 +510,25 @@ export class NopeBaseModule implements INopeModule { // Remove all known Properties. this._registeredProperties.clear(); + + // Unregister all Properties. + for (const name of this._registeredEvents.keys()) { + await this.unregisterEvent(name); + } + + // Remove all known Properties. + this._registeredEvents.clear(); } /** * Helper Function to extract the used identifiert of Property * - * @param {(((...args) => Promise) | INopeObservable)} propOrFunc The Property or the Function to receive the Name. + * @param {(((...args) => Promise) | INopeObservable)} prop_event_or_func The Property or the Function to receive the Name. * @return {*} {string} * @memberof NopeBaseModule */ public getIdentifierOf( - propOrFunc: ((...args) => Promise) | INopeObservable, + prop_event_or_func: ((...args) => Promise) | INopeObservable, type: "topicToPublish" | "topicToSubscribe" = null ): string { // To Extract the name of the Property or the Function, we will iterate over @@ -512,7 +538,7 @@ export class NopeBaseModule implements INopeModule { for (const [name, item] of this._registeredProperties.entries()) { const { observable, options } = item; - if (observable == propOrFunc) { + if (observable == prop_event_or_func) { const _subTopic = typeof options.topic === "string" ? options.topic @@ -543,9 +569,43 @@ export class NopeBaseModule implements INopeModule { } } } - for (const [name, item] of this._registeredFunctions.entries()) { - const { func, options } = item; - if (func == propOrFunc) { + for (const [name, item] of this._registeredEvents.entries()) { + const { emitter, options } = item; + + if (emitter == prop_event_or_func) { + const _subTopic = + typeof options.topic === "string" + ? options.topic + : options.topic.subscribe || null; + const _pubTopic = + typeof options.topic === "string" + ? options.topic + : options.topic.publish || null; + + switch (type) { + case "topicToPublish": + if (_pubTopic === null) { + throw Error("No topic for publishing is defined."); + } + return _pubTopic; + case "topicToSubscribe": + if (_subTopic === null) { + throw Error("No topic for subscribing is defined."); + } + return _subTopic; + default: + if (typeof options.topic === "string") { + return options.topic; + } + throw Error( + "Prop uses different name for subscribing and publishing. Please specify using the 'type' identier to select" + ); + } + } + } + for (const [name, item] of this._registeredMethods.entries()) { + const { method: func, options } = item; + if (func == prop_event_or_func) { return options.id; } } @@ -563,7 +623,7 @@ export class NopeBaseModule implements INopeModule { const ret: INopeModuleDescription = { author: this.author, description: this.description, - functions: this.functions, + methods: this.methods, events: this.events, identifier: this.identifier, properties: this.properties, diff --git a/lib/module/GenericWrapper.injectable.ts b/lib/module/GenericWrapper.injectable.ts index fa59b15..5b78bd6 100644 --- a/lib/module/GenericWrapper.injectable.ts +++ b/lib/module/GenericWrapper.injectable.ts @@ -4,9 +4,10 @@ */ import { inject, injectable } from "inversify"; -import { INopeCore } from "../types/nope"; +import { INopeCore, INopeEventEmitter } from "../types/nope"; import { DISPATCHER_INSTANCE, + EMITTER_FACTORY, OBSERVABLE_FACTORY, } from "../symbols/identifiers"; import { INopeObservable } from "../types/nope/nopeObservable.interface"; @@ -22,8 +23,9 @@ export class InjectableNopeGenericWrapper extends NopeGenericWrapper { */ constructor( @inject(DISPATCHER_INSTANCE) _core: INopeCore, - @inject(OBSERVABLE_FACTORY) _observableFactory: () => INopeObservable + @inject(OBSERVABLE_FACTORY) _observableFactory: () => INopeObservable, + @inject(EMITTER_FACTORY) _emitterFactory: () => INopeEventEmitter ) { - super(_core, _observableFactory); + super(_core, _emitterFactory, _observableFactory); } } diff --git a/lib/module/GenericWrapper.ts b/lib/module/GenericWrapper.ts index c0744db..defa5b6 100644 --- a/lib/module/GenericWrapper.ts +++ b/lib/module/GenericWrapper.ts @@ -5,7 +5,7 @@ import { deepClone } from "../helpers/objectMethods"; import { getNopeLogger } from "../logger/getLogger"; -import { ICallOptions, INopeCore } from "../types"; +import { ICallOptions, INopeCore, INopeEventEmitter } from "../types"; import { IEventOptions, IFunctionOptions, @@ -65,6 +65,10 @@ export class NopeGenericWrapper extends NopeBaseModule { public dynamicInstanceProperties: { [index: string]: INopeObservable; } = {}; + public dynamicInstanceEvents: { + [index: string]: INopeEventEmitter; + } = {}; + public dynamicInstanceMethodsWithOptions: { [index: string]: ( options: Partial, @@ -116,10 +120,10 @@ export class NopeGenericWrapper extends NopeBaseModule { ); } - for (const name in description.functions) { + for (const name in description.methods) { this._logger.debug('Create function interface for "' + name + '"'); - const options = description.functions[name]; + const options = description.methods[name]; const func = (...args) => { return _this._core.rpcManager.performCall(options.id, args, options); }; @@ -135,25 +139,23 @@ export class NopeGenericWrapper extends NopeBaseModule { }; if (this.dynamicInstanceMethods[name]) { - throw Error("Name alread used. Not able to use the method name twice"); + throw Error("Name alread used. Not able to use the 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"); + throw Error("Name alread used. Not able to use the 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" - ); + throw Error("Name alread used. Not able to use the name twice"); } this[name] = func; } - this._registeredFunctions.set(name, { - func, + this._registeredMethods.set(name, { + method: func, options, }); } @@ -171,7 +173,7 @@ export class NopeGenericWrapper extends NopeBaseModule { // let mode = prop.mode; if (this.dynamicInstanceProperties[name]) { - throw Error("Name alread used. Not able to use the method name twice"); + throw Error("Name alread used. Not able to use the name twice"); } // Make shure it isnt published. @@ -188,9 +190,7 @@ export class NopeGenericWrapper extends NopeBaseModule { if (!options.isDynamic) { if (this[name]) { - throw Error( - "Name alread used. Not able to use the method name twice" - ); + throw Error("Name alread used. Not able to use the name twice"); } // Use the Same Element. this[name] = this.dynamicInstanceProperties[name]; @@ -202,6 +202,48 @@ export class NopeGenericWrapper extends NopeBaseModule { options, }); } + + for (const name in description.events) { + this._logger.debug('Create property interface for "' + name + '"'); + + const options = description.events[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.dynamicInstanceEvents[name]) { + throw Error("Name alread used. Not able to use the name twice"); + } + + // Make shure it isnt published. + // options.preventSendingToRegistery = true; + + // Register the Observable: + this.dynamicInstanceEvents[name] = this._core.eventDistributor.register( + // Assign a new Observable. + this._emitterFactory(), + // Use the provided Properties: + _invertMode(options) + ); + + if (!options.isDynamic) { + if (this[name]) { + throw Error("Name alread used. Not able to use the name twice"); + } + // Use the Same Element. + this[name] = this.dynamicInstanceEvents[name]; + } + + this._logger.debug('Register Property "' + name + '"', options); + this._registeredEvents.set(name, { + emitter: this.dynamicInstanceEvents[name], + options, + }); + } } /** @@ -212,12 +254,13 @@ export class NopeGenericWrapper extends NopeBaseModule { */ constructor( _core: INopeCore, + protected _emitterFactory: () => INopeEventEmitter, protected _observableFactory: () => INopeObservable ) { super(_core); } - public async listFunctions(): Promise< + public async listMethods(): Promise< { func: (...args: any[]) => Promise; options: IFunctionOptions }[] > { const _this = this; @@ -270,7 +313,11 @@ export class NopeGenericWrapper extends NopeBaseModule { delete this[name]; } - this._registeredFunctions.clear(); + for (const name in this.dynamicInstanceEvents) { + this.dynamicInstanceEvents[name].dispose(); + // Remove Reference + delete this[name]; + } this.dynamicInstanceProperties = {}; @@ -280,5 +327,7 @@ export class NopeGenericWrapper extends NopeBaseModule { } this._registeredProperties.clear(); + this._registeredEvents.clear(); + this._registeredMethods.clear(); } } diff --git a/lib/symbols/identifiers.ts b/lib/symbols/identifiers.ts index aba649e..75c847e 100644 --- a/lib/symbols/identifiers.ts +++ b/lib/symbols/identifiers.ts @@ -9,6 +9,8 @@ export const DISPATCHER_INSTANCE = Symbol.for("nope.dispatcher.instance"); export const DISPATCHER_OPTIONS = Symbol.for("nope.dispatcher.options"); export const OBSERVABLE_FACTORY = Symbol.for("nope.observable.factory"); +export const EMITTER_FACTORY = Symbol.for("nope.emitter.factory"); export const OBSERVABLE_INSTANCE = Symbol.for("nope.observable.instance"); +export const EMITTER_INSTANCE = Symbol.for("nope.emitter.instance"); export const COMMUNICATION_LAYER = Symbol.for("nope.communication.layer"); export const LOADER = Symbol.for("nope.package.loader"); diff --git a/lib/types/nope/nopeDispatcher.interface.ts b/lib/types/nope/nopeDispatcher.interface.ts index 4b60bae..2a3ba60 100644 --- a/lib/types/nope/nopeDispatcher.interface.ts +++ b/lib/types/nope/nopeDispatcher.interface.ts @@ -16,6 +16,7 @@ import { INopeDescriptor } from "./nopeDescriptor.interface"; import { IEventAdditionalData, IEventCallback, + INopeEventEmitter, INopeObserver, } from "./nopeEventEmitter.interface"; import { INopeModule, INopeModuleDescription } from "./nopeModule.interface"; @@ -86,6 +87,7 @@ export interface IHostOverview extends IHost { export interface IDispatcherConstructor { new ( options: INopeDispatcherOptions, + _generateEmitter: () => INopeEventEmitter, _generateObservable: () => INopeObservable ): INopeDispatcher; } @@ -157,8 +159,8 @@ export interface INopeDispatcher extends INopeCore { /** * Helper to pull some data from the system. - * @param path - * @param _default + * @param path The path to the Data. + * @param _default The value to use if no data has been found. If not provided an error is thrown. Defaults to None. */ pullData(path: string, _default?: D): T; @@ -183,12 +185,13 @@ export interface INopeDispatcher extends INopeCore { /** * Receive the "instances" | "services" | "properties" | "events" - * which matches with the given pattern. + * which matches with the given pattern. Therefore the user provides + * the pattern and tyle. * * @author M.Karkowski - * @param {string} pattern - * @param {("instances" | "services" | "properties" | "events")} type - * @return {*} {string[]} + * @param {string} pattern Pattern to query the provided type. + * @param {("instances" | "services" | "properties" | "events")} type Type which should be querried + * @return {string[]} List of the matching items. * @memberof INopeDispatcher */ query( diff --git a/lib/types/nope/nopeInstanceManager.interface.ts b/lib/types/nope/nopeInstanceManager.interface.ts index 4d9ade5..abae9f0 100644 --- a/lib/types/nope/nopeInstanceManager.interface.ts +++ b/lib/types/nope/nopeInstanceManager.interface.ts @@ -124,7 +124,7 @@ export interface INopeInstanceManager { * able to create new ones. * * @author M.Karkowski - * @param {string} typeIdentifier + * @param {string} typeIdentifier The identifier for the Constructor (Like a service) * @return {Promise} * @memberof INopeInstanceManager */ @@ -208,7 +208,7 @@ export interface INopeInstanceManager { constructorExists(typeIdentifier: string): boolean; /** - * Returns the hosting Manager for the given instance. + * Returns the hosting dispatcher for the given instance. * * @author M.Karkowski * @param {string} instanceIdentifier The identifier for instance (its name) @@ -222,7 +222,7 @@ export interface INopeInstanceManager { * for the "instances"-property. * * @author M.Karkowski - * @param {string} instanceIdentifier + * @param {string} instanceIdentifier The identifier for instance (its name) * @return {(INopeModuleDescription | false)} * @memberof INopeInstanceManager */ @@ -236,7 +236,7 @@ export interface INopeInstanceManager { * * @author M.Karkowski * @template I - * @param {I} instance + * @param {I} instance The Instance to consider * @return {Promise} * @memberof INopeInstanceManager */ @@ -250,7 +250,7 @@ export interface INopeInstanceManager { * * @author M.Karkowski * @template I - * @param {(I | string)} instance + * @param {(I | string)} instance The Instance to consider * @return {Promise} * @memberof INopeInstanceManager */ diff --git a/lib/types/nope/nopeModule.interface.ts b/lib/types/nope/nopeModule.interface.ts index 1a09773..2baee43 100644 --- a/lib/types/nope/nopeModule.interface.ts +++ b/lib/types/nope/nopeModule.interface.ts @@ -85,7 +85,7 @@ export interface INopeModuleDescription { * @type {{ [index: string]: IFunctionOptions }} * @memberof INopeModuleDescription */ - readonly functions: { [index: string]: IFunctionOptions }; + readonly methods: { [index: string]: IFunctionOptions }; readonly events: { [index: string]: IEventOptions }; @@ -165,7 +165,7 @@ export interface INopeModule extends INopeModuleDescription { * @return {Promise>} * @memberof IBaseModule */ - listFunctions(): Promise< + listMethods(): Promise< Array<{ func: (...args) => Promise; options: IFunctionOptions }> >; diff --git a/lib/types/nope/nopePackageLoader.interface.ts b/lib/types/nope/nopePackageLoader.interface.ts index be151bb..7f315b2 100644 --- a/lib/types/nope/nopePackageLoader.interface.ts +++ b/lib/types/nope/nopePackageLoader.interface.ts @@ -1,5 +1,5 @@ import { Container } from "inversify"; -import { IexportFunctionAsNopeServiceParameters } from "../../decorators"; +import { IexportAsNopeServiceParameters } from "../../decorators"; import { INopeDispatcher } from "./nopeDispatcher.interface"; import { INopeModule } from "./nopeModule.interface"; import { @@ -84,7 +84,7 @@ export interface INopePackageLoader { */ addDecoratedElements(options?: { addServiceCallback?: ( - options: IexportFunctionAsNopeServiceParameters + options: IexportAsNopeServiceParameters ) => Promise; addClassCallback?: (options: INopeModule) => Promise; consider?: Array<"services" | "classes">;