Adding Comments

This commit is contained in:
Martin Karkowski 2020-09-11 09:59:23 +02:00
parent 27e5f5569b
commit 52f4f5fc74
2 changed files with 144 additions and 19 deletions

View File

@ -2,7 +2,12 @@ import { EventEmitter } from "events";
import { CommunicationEvents, ICommunicationInterface } from "../dispatcher/nopeDispatcher";
/**
* Event Layer.
* A Communication Layer for the Dispatchers.
* Here, only a Events are used.
*
* @export
* @class EventLayer
* @implements {ICommunicationInterface}
*/
export class EventLayer implements ICommunicationInterface {
protected _emitter = new EventEmitter();

View File

@ -2,8 +2,29 @@ import { generateId } from '../helpers/idMethods';
export type CommunicationEvents = 'connection' | 'event' | 'disconnect';
/**
* A Layer to communicate.
*
* @export
* @interface ICommunicationInterface
*/
export interface ICommunicationInterface {
/**
* Function used to subscribe to updates. If there exist
* some state change in the Communication Interface it should
* be provided on the registered functions
*
* @param {CommunicationEvents} event The Selected Event.
* @param {(...args) => void} cb The Callback, which will be called if an Event occours
* @memberof ICommunicationInterface
*/
on(event: CommunicationEvents, cb: (...args) => void);
/**
* Function to send data via the Communication interface
*
* @param {*} data The data. Could be any type and element. In Generel it should be parsable.
* @memberof ICommunicationInterface
*/
send(data): void;
}
@ -30,56 +51,110 @@ type responseOfTask = {
}
/**
* A Dispatcher to perform a function with a remote
* A Dispatcher to perform a function on a Remote
* Dispatcher. Therefore a Task is created and forwarded
* to the remote.
*
* @export
* @class nopeDispatcher
*/
export class nopeDispatcher {
/**
* Internal Element to store the registered Functions
*
* @protected
* @memberof nopeDispatcher
*/
protected _definedFunctions: Map<number | string, (...args) => Promise<any>>;
/**
* Internal Element to store the running tasks.
*
* @protected
* @memberof nopeDispatcher
*/
protected _runningTasks: Map<number, {
resolve: (value: any) => void;
reject: (error: any) => void;
}>;
/**
* Creates an instance of nopeDispatcher.
* @param {ICommunicationInterface} communicator The Communication Layer which should be used.
* @memberof nopeDispatcher
*/
constructor(public communicator: ICommunicationInterface) {
this.reset();
this.init();
}
protected async _handleExternalRequest(data: requestTask) {
/**
* Internal Method to handle some requests.
*
* @protected
* @param {requestTask} data The provided data of the request
* @return {Promise<void>}
* @memberof nopeDispatcher
*/
protected async _handleExternalRequest(data: requestTask): Promise<void> {
try {
const _this = this;
// Extract the Function, which is linked to the Task.
const _function = _this._definedFunctions.get(data.functionId);
if (typeof _function === 'function') {
// Only if the Function is present extract the arguments etc.
const args = [];
// First extract the basic arguments
data.params.map(item => args[item.idx] = item.data);
// Add the Callbacks. Therefore create a function which will
// trigger the remote.
data.callbacks.map(item => args[item.idx] = async (..._args) => {
return await _this.performCall(item.functionId, _args);
});
// Perform the Task it self.
const _result = await _function(...args);
// Define the Result message
const result: responseOfTask = {
result: typeof (_result) !== 'undefined' ? _result : null,
taskId: data.taskId,
type: 'response'
}
// Use the communicator to publish the event.
this.communicator.send(result);
}
} catch (error) {
// An Error occourd => Forward the Error.
const result: responseOfTask = {
error,
taskId: data.taskId,
type: 'response'
}
// Send the Error via the communicator to the remote.
this.communicator.send(result);
}
}
protected _handleExternalResponse(data: responseOfTask) {
/**
* Internal Function to handle responses. In Generale,
* the dispatcher checks if there is an open task with
* the provided id. If so => finish the promise.
*
* @protected
* @param {responseOfTask} data The Data provided to handle the Response.
* @return {void} Nothing
* @memberof nopeDispatcher
*/
protected _handleExternalResponse(data: responseOfTask): void {
try {
// Extract the Task
const task = this._runningTasks.get(data.taskId);
@ -99,7 +174,14 @@ export class nopeDispatcher {
}
}
protected init() {
/**
* Internal Function, used to initialize the Dispatcher.
* It subscribes to the "Messages" of the communicator.
*
* @protected
* @memberof nopeDispatcher
*/
protected init(): void {
this.communicator.on('event', (data: requestTask | responseOfTask) => {
switch (data.type) {
case 'request':
@ -115,15 +197,24 @@ export class nopeDispatcher {
}
/**
* Function to register a Function
* @param func
* @param options
* Function to register a Function in the Dispatcher
*
* @param {(...args) => Promise<any>} func The function which should be called if a request is mapped to the Function.
* @param {{
* // Flag to enable unregistering the function after calling.
* deleteAfterCalling?: boolean,
* // Instead of generating a uuid an id could be provided
* id?: string;
* }} [options={}] Options to enhance the registered ID and enabling unregistering the Element after calling it.
* @return {*} {(...args) => Promise<any>} The registered Function
* @memberof nopeDispatcher
*/
public registerFunction(func: (...args) => Promise<any>, options: {
args?: any[],
/** Flag to enable unregistering the function after calling. */
deleteAfterCalling?: boolean,
/** Instead of generating a uuid an id could be provided */
id?: string;
} = {}) {
} = {}): (...args) => Promise<any> {
const _this = this;
const _id = options.id || generateId();
@ -154,20 +245,34 @@ export class nopeDispatcher {
/**
* Function to unregister a Function from the Dispatcher
* @param func The Function to unregister
* @returns Flag, whether the element was removed (only if found) or not.
* @param {(((...args) => void) | string | number)} func The Function to unregister
* @return {*} {boolean} Flag, whether the element was removed (only if found) or not.
* @memberof nopeDispatcher
*/
public unregistFunction(func: ((...args) => void) | string | number) {
public unregistFunction(func: ((...args) => void) | string | number): boolean {
const _id = typeof func === 'string' ? func : func['id'] || 0;
return this._definedFunctions.delete(_id);
}
/**
* Function which is used to perform a call on the remote.
*
* @template T
* @param {string} functionName The Name / ID of the Function
* @param {any[]} params The provided Parameters.
* @param {({
* deletableCallbacks: Array<number>;
* })} [options={
* deletableCallbacks: []
* }] You could provide the index of removeable callbacks.
* @return {*} {Promise<T>} The result of the Operation
* @memberof nopeDispatcher
*/
public performCall<T>(functionName: string, params: any[], options: {
deletableCallbacks: Array<string | number>;
deletableCallbacks: Array<number>;
} = {
deletableCallbacks: []
}) {
}): Promise<T> {
// Get a Call Id
const _taskId = generateId();
const _registeredIdx: Array<number | string> = [];
@ -242,7 +347,12 @@ export class nopeDispatcher {
});
}
public clearTasks() {
/**
* Function to clear all pending tasks
*
* @memberof nopeDispatcher
*/
public clearTasks(): void {
if (this._runningTasks)
this._runningTasks.clear();
else
@ -252,14 +362,24 @@ export class nopeDispatcher {
}>();
}
public unregisterAll() {
/**
* Function to unregister all Functions of the Dispatcher.
*
* @memberof nopeDispatcher
*/
public unregisterAll(): void {
if (this._definedFunctions)
this._definedFunctions.clear();
else
this._definedFunctions = new Map<string, (...args) => Promise<any>>();
}
public reset() {
/**
* Function to reset the Dispatcher.
*
* @memberof nopeDispatcher
*/
public reset(): void {
this.clearTasks();
this.unregisterAll();
}