diff --git a/lib/communication/bridge.ts b/lib/communication/bridge.ts index a288012..3d031f4 100644 --- a/lib/communication/bridge.ts +++ b/lib/communication/bridge.ts @@ -25,6 +25,7 @@ import { IEmitter, IExecutingTaskMsg, IExternalEventMsg, + IExternalPropertyChangedMsg, IRequestTaskMsg, IResponseTaskMsg, IRpcUnregisterMsg, @@ -173,7 +174,7 @@ export class Bridge implements ICommunicationBridge { public connected: INopeObservable; public considerConnection = true; - public allowServiceRedundancy = false; + public allowsServiceRedundancy = false; public ownDispatcherId: string; public id: string; @@ -806,4 +807,13 @@ export class Bridge implements ICommunicationBridge { emitNewInstancesAvailable(instances: IAvailableInstancesMsg): Promise { throw new Error("Method should be overwritten."); } + onPropertyChange(name: string, cb: (data: IExternalPropertyChangedMsg) => void): Promise { + throw new Error("Method should be overwritten."); + } + emitPropertyChange(name: string, data: IExternalPropertyChangedMsg): Promise { + throw new Error("Method should be overwritten."); + } + offPropertyChange(name: string, cb: (data: IExternalPropertyChangedMsg) => void): Promise { + throw new Error("Method should be overwritten."); + } } diff --git a/lib/dispatcher/nopeDispatcher.ts b/lib/dispatcher/nopeDispatcher.ts index c7b495a..5c194c6 100644 --- a/lib/dispatcher/nopeDispatcher.ts +++ b/lib/dispatcher/nopeDispatcher.ts @@ -63,7 +63,6 @@ import { INopePromise } from "../types/nope/nopePromise.interface"; * @export * @class nopeDispatcher */ -// @injectable() export class nopeDispatcher implements INopeDispatcher { public readonly id: string; @@ -232,10 +231,17 @@ export class nopeDispatcher implements INopeDispatcher { protected _lastPublishedEvent: Map; + public readonly externallySubscribedProperties: INopeObservable; + public readonly externallyPublishedProperties: INopeObservable; + public readonly subscribedProperties: INopeObservable; + public readonly publishedProperties: INopeObservable; + + public readonly externallySubscribedEvents: INopeObservable; public readonly externallyPublishedEvents: INopeObservable; public readonly subscribedEvents: INopeObservable; public readonly publishedEvents: INopeObservable; + public readonly externalProvidedServices: INopeObservable; public readonly canceledTask: INopeObservable; public readonly ready: INopeObservable; @@ -373,14 +379,14 @@ export class nopeDispatcher implements INopeDispatcher { this.methodInterface = new Proxy({}, _handlerWithoutOptions); // Define the Observables provided by the dispatcher. - this.externallySubscribedEvents = this._generateObservable(); - this.externallySubscribedEvents.setContent([]); - this.externallyPublishedEvents = this._generateObservable(); - this.externallyPublishedEvents.setContent([]); - this.publishedEvents = this._generateObservable(); - this.publishedEvents.setContent([]); - this.subscribedEvents = this._generateObservable(); - this.subscribedEvents.setContent([]); + this.externallySubscribedProperties = this._generateObservable(); + this.externallySubscribedProperties.setContent([]); + this.externallyPublishedProperties = this._generateObservable(); + this.externallyPublishedProperties.setContent([]); + this.publishedProperties = this._generateObservable(); + this.publishedProperties.setContent([]); + this.subscribedProperties = this._generateObservable(); + this.subscribedProperties.setContent([]); this.externalProvidedServices = this._generateObservable(); this.externalProvidedServices.setContent([]); this.canceledTask = this._generateObservable(); @@ -587,7 +593,7 @@ export class nopeDispatcher implements INopeDispatcher { } } - public registerInternalInstanceGenerator( + public registerInternalWrapperGenerator( identifier: string, cb: IGenerateRemoteInstanceCallback ): void { @@ -602,7 +608,7 @@ export class nopeDispatcher implements INopeDispatcher { this._internalGenerators.set(identifier, cb); } - public unregisterInternalInstanceGenerator(identifier: string): void { + public unregisterInternalWrapperGenerator(identifier: string): void { if (this._logger?.enabledFor((Logger as any).DEBUG)) { this._logger.debug( "Rmoving instance generator for \"" + @@ -1611,7 +1617,7 @@ export class nopeDispatcher implements INopeDispatcher { ); } - this.registerInternalInstanceGenerator( + this.registerInternalWrapperGenerator( "*", async (dispather, description) => { const mod = new NopeGenericModule(dispather, _this._generateObservable); @@ -1672,12 +1678,12 @@ export class nopeDispatcher implements INopeDispatcher { } } // Update the all internal subscribed / published events. - this.subscribedEvents.setContent( + this.subscribedProperties.setContent( Array.from( new Set([..._this._externalSubscribed, ...this._internalSubscribed]) ) ); - this.publishedEvents.setContent( + this.publishedProperties.setContent( Array.from( new Set([..._this._externalPublished, ...this._internalPublished]) ) @@ -2285,10 +2291,10 @@ export class nopeDispatcher implements INopeDispatcher { this._externalPublished = _published; // Update the Elements. - this.externallySubscribedEvents.setContent( + this.externallySubscribedProperties.setContent( Array.from(this._externalSubscribed) ); - this.externallyPublishedEvents.setContent( + this.externallyPublishedProperties.setContent( Array.from(this._externalPublished) ); } @@ -2358,7 +2364,7 @@ export class nopeDispatcher implements INopeDispatcher { * @return {boolean} The result of the test. True if an external subscription exsits * @memberof nopeDispatcher */ - public subscriptionExists(topic: string, externalOnly = true): boolean { + public subscriptionForPropertyExists(topic: string, externalOnly = true): boolean { if (externalOnly) { return this._externalSubscribed.has(topic); } else { @@ -2367,7 +2373,7 @@ export class nopeDispatcher implements INopeDispatcher { } } - public publisherExists(topic: string, externalOnly = true): boolean { + public publisherForPropertyExists(topic: string, externalOnly = true): boolean { if (externalOnly) { return this._externalPublished.has(topic); } else { @@ -2494,12 +2500,17 @@ export class nopeDispatcher implements INopeDispatcher { * @return {nopeObservable} An Listener on the Communication Channel. * @memberof nopeDispatcher */ - protected _subscribeToEvent(event: string) { + protected _subscribeToEvent(event: string): { + newSubscription: boolean, + observable: INopeObservable + } { const item = this._externalTopicLinkedWithObservable.get(event) || { observable: this._generateObservable(), cb: () => { // Default callback - } + }, + // we must know, whether this element is new or not. + newSubscription: this._externalTopicLinkedWithObservable.has(event) }; if (!item.observable.hasSubscriptions) { @@ -2515,7 +2526,12 @@ export class nopeDispatcher implements INopeDispatcher { // Set the Items. this._externalTopicLinkedWithObservable.set(event, item); - return item.observable; + const { cb, ...ret } = item; + + return ret as { + newSubscription: boolean, + observable: INopeObservable + }; } /** @@ -2797,7 +2813,7 @@ export class nopeDispatcher implements INopeDispatcher { // Updates is enabled: if so, use the socket to send the data // to other dispatchers. if ( - _this.subscriptionExists(_pubTopic) || + _this.subscriptionForPropertyExists(_pubTopic) || _this._forceEmittingUpdates || // If the Update is forced options.forced @@ -3144,7 +3160,7 @@ export class nopeDispatcher implements INopeDispatcher { ...args ): Promise { // Only Publish data, if there exists a Subscription. - if (forced || (this.subscriptionExists(_eventName) && this.id !== sender)) { + if (forced || (this.subscriptionForPropertyExists(_eventName) && this.id !== sender)) { // Use the Communicator to emit the Event or its forced await this.communicator.emitEvent(_eventName, { forced, diff --git a/lib/types/nope/nopeCommunication.interface.ts b/lib/types/nope/nopeCommunication.interface.ts index edcb27e..c21ae14 100644 --- a/lib/types/nope/nopeCommunication.interface.ts +++ b/lib/types/nope/nopeCommunication.interface.ts @@ -200,6 +200,33 @@ export interface ICommunicationInterface { */ offEvent(event: string, cb: (data: IExternalEventMsg) => void): Promise; + /** + * Function to subscribe to an event + * + * @param {string} name The Event name (Usually the Topic.) + * @param {(data: IExternalPropertyChangedMsg) => void} cb The Callback which should be used to call if there are new Events. + * @memberof ICommunicationInterface + */ + onPropertyChange(name: string, cb: (data: IExternalPropertyChangedMsg) => void): Promise; + + /** + * Function used to emit an event on the given event channel + * + * @param {string} name The Name of the Event + * @param {IExternalPropertyChangedMsg} data A datapacket describing the Property Change + * @memberof ICommunicationInterface + */ + emitPropertyChange(name: string, data: IExternalPropertyChangedMsg): Promise; + + /** + * Function to unregister an event listener + * + * @param {string} name The Name of the Event + * @param {(data: IExternalPropertyChangedMsg) => void} cb The desired Callback + * @memberof ICommunicationInterface + */ + offPropertyChange(name: string, cb: (data: IExternalPropertyChangedMsg) => void): Promise; + /** * Function, to subscribe to "Bonjour"-Messages of the Dispatcher Dispatchers. * @@ -308,15 +335,22 @@ export interface ICommunicationInterface { * @type {boolean} * @memberof ICommunicationInterface */ - allowServiceRedundancy: boolean; + allowsServiceRedundancy: boolean; /** * Used to show, whether the the layer receives its own messages * @type {boolean} * @memberof ICommunicationInterface */ - receivesOwnMessages?: boolean; + receivesOwnMessages: boolean; + /** + * ID of the Layer. + * + * @author M.Karkowski + * @type {string} + * @memberof ICommunicationInterface + */ readonly id: string; /** @@ -598,6 +632,52 @@ export type IExternalEventMsg = { forced?: boolean; }; +export type IExternalPropertyChangedMsg = { + /** + * Type of the Message + * + * @type {'property'} + */ + type: "property"; + + /** + * Data of the Message. + * Holding the Data of the Event + * + * @type {*} + */ + data: T; + + /** + * The Topic, on which it was hosted + * + * @type {string} + */ + propertyName: string; + + /** + * Information about the Sender. + * + * @type {string} + */ + sender: string; + + /** + * The Timestamp, when the message was created. + * + * @type {number} + */ + timestamp?: number; + + /** + * Flag, indicating that the update is forced. + * + * @author M.Karkowski + * @type {boolean} + */ + forced?: boolean; +}; + export type IRequestOfService = { type: "requestOfService"; taskId: string; diff --git a/lib/types/nope/nopeDispatcher.interface.ts b/lib/types/nope/nopeDispatcher.interface.ts index 7d31abe..bf3dd8e 100644 --- a/lib/types/nope/nopeDispatcher.interface.ts +++ b/lib/types/nope/nopeDispatcher.interface.ts @@ -252,7 +252,22 @@ export type INopeDispatcherOptions = { * @interface INopeDispatcher */ export interface INopeDispatcher { + /** + * Flag showing, that the system is ready. + * + * @author M.Karkowski + * @type {INopeObservable} + * @memberof INopeDispatcher + */ readonly ready: INopeObservable; + + /** + * The Communicator which is used + * + * @author M.Karkowski + * @type {ICommunicationBridge} + * @memberof INopeDispatcher + */ readonly communicator: ICommunicationBridge; /** @@ -263,9 +278,27 @@ export interface INopeDispatcher { */ readonly id: string; + /** + * Just a proxy to call functions the easy way. + * + * @example For example after registering a function "test": + * await dispatcher.methodInterfaceWithOptions.test({},"hello") + * + * @author M.Karkowski + * @memberof INopeDispatcher + */ methodInterfaceWithOptions: { - [index: string]: (optins: ICallOptions, ...args) => INopePromise; + [index: string]: (options: ICallOptions, ...args) => INopePromise; }; + + /** + * Just a proxy to call functions the easy way. + * + * @example For example after registering a function "test": + * await dispatcher.methodInterface.test("hello") + * @author M.Karkowski + * @memberof INopeDispatcher + */ methodInterface: { [index: string]: (...args) => INopePromise }; /** @@ -274,7 +307,7 @@ export interface INopeDispatcher { * @type {INopeObservable} * @memberof INopeDispatcher */ - readonly externallySubscribedEvents: INopeObservable; + readonly externallySubscribedProperties: INopeObservable; /** * An Observable holding the newest published elements @@ -282,7 +315,23 @@ export interface INopeDispatcher { * @type {INopeObservable} * @memberof INopeDispatcher */ - readonly externallyPublishedEvents: INopeObservable; + readonly externallyPublishedProperties: INopeObservable; + + /** + * An Observable holding the newest External Subscription + * + * @type {INopeObservable} + * @memberof INopeDispatcher + */ + readonly subscribedProperties: INopeObservable; + + /** + * An Observable holding the newest published elements + * + * @type {INopeObservable} + * @memberof INopeDispatcher + */ + readonly publishedProperties: INopeObservable; /** * An Observable holding the newest External Subscription @@ -300,6 +349,22 @@ export interface INopeDispatcher { */ readonly publishedEvents: INopeObservable; + /** + * An Observable holding the newest External Subscription + * + * @type {INopeObservable} + * @memberof INopeDispatcher + */ + readonly externallySubscribedEvents: INopeObservable; + + /** + * An Observable holding the newest published elements + * + * @type {INopeObservable} + * @memberof INopeDispatcher + */ + readonly externallyPublishedEvents: INopeObservable; + /** * Observable holding all available Dispatchers. * @@ -343,7 +408,7 @@ export interface INopeDispatcher { * @return {*} {boolean} * @memberof INopeDispatcher */ - subscriptionExists(topic: string, externalOnly?: boolean): boolean; + subscriptionForPropertyExists(topic: string, externalOnly?: boolean): boolean; /** * Element to test, if a publisher for a specific topic exists or not. @@ -353,7 +418,7 @@ export interface INopeDispatcher { * @return {*} {boolean} * @memberof INopeDispatcher */ - publisherExists(topic: string, externalOnly?: boolean): boolean; + publisherForPropertyExists(topic: string, externalOnly?: boolean): boolean; /** * Function to register a Function in the Dispatcher @@ -363,10 +428,10 @@ export interface INopeDispatcher { * @return {*} {(...args) => Promise} * @memberof INopeDispatcher */ - registerFunction( - func: (...args) => IValidPromise, + registerFunction( + func: (...args) => IValidPromise | T, options?: IFunctionOptions - ): (...args) => Promise; + ): (...args) => Promise | T; /** * Function to unregister a Function from the Dispatcher @@ -394,7 +459,7 @@ export interface INopeDispatcher { * @return {*} {INopeObservable} * @memberof INopeDispatcher */ - registerObservable( + registerObservable( observable: INopeObservable, options: IPropertyOptions ): INopeObservable; @@ -493,12 +558,12 @@ export interface INopeDispatcher { * @return {*} {(Promise)} The Element * @memberof INopeDispatcher */ - generateInstance( + generateInstance( description: Partial, options?: { selector?: ValidDefaultSelectors | ValidSelectorFunction } - ): Promise; + ): Promise; /** * Function, used to delete a remote instance. @@ -547,8 +612,8 @@ export interface INopeDispatcher { unprovideInstanceGeneratorForExternalDispatchers(identifier: string): Promise; /** - * A function, to provide an internal internal generator. This generator - * will be used to generate a specific internal accessor for a remote instance. + * A function, to provide an internal wrapper for instances generator. This generator + * will be used to generate a specific internal wrapper for a remote instance. * * @author M.Karkowski * @template I @@ -556,21 +621,21 @@ export interface INopeDispatcher { * @param {IGenerateRemoteInstanceCallback} cb * @memberof INopeDispatcher */ - registerInternalInstanceGenerator( + registerInternalWrapperGenerator( identifier: string, cb: IGenerateRemoteInstanceCallback ); /** - * Function, that is used to remove an instance generator. This removes the - * generator from the NoPE-Network. Available instance of that type wont be - * removed. + * Function, that is used to remove an wrapper generator. This removes the + * generator for the wrapper. Available instance inside of NoPE of that type + * which is being wrapped wont be removed. * * @author M.Karkowski * @param {string} identifier * @memberof INopeDispatcher */ - unregisterInternalInstanceGenerator(identifier: string); + unregisterInternalWrapperGenerator(identifier: string); /** * Helper Function to get a Dispatcer for the desired Instance diff --git a/lib/types/nope/nopeModule.interface.ts b/lib/types/nope/nopeModule.interface.ts index 6219c84..53adeb3 100644 --- a/lib/types/nope/nopeModule.interface.ts +++ b/lib/types/nope/nopeModule.interface.ts @@ -6,9 +6,9 @@ * @desc Defintion of a generic Module. */ -import { ICallOptions, IExternalEventMsg } from "./nopeCommunication.interface"; +import { ICallOptions } from "./nopeCommunication.interface"; import { INopeDescriptor } from "./nopeDescriptor.interface"; -import { INopeObservable, IPipe } from "./nopeObservable.interface"; +import { INopeObservable } from "./nopeObservable.interface"; import { INopePromise } from "./nopePromise.interface"; /** @@ -255,14 +255,6 @@ export interface IPropertyOptions { publish?: string; }; - /** - * An Advanced Pipe Option. - */ - pipe?: { - pipe?: IPipe; - scope?: { [index: string]: any }; - }; - /** * Flag to disable Registery Updates. */