2020-12-04 18:10:33 +00:00
|
|
|
/**
|
|
|
|
* @author Martin Karkowski
|
|
|
|
* @email m.karkowski@zema.de
|
|
|
|
* @create date 2020-11-06 08:52:36
|
2021-03-19 18:17:39 +00:00
|
|
|
* @modify date 2021-03-19 14:27:23
|
2020-12-04 18:10:33 +00:00
|
|
|
* @desc [description]
|
|
|
|
*/
|
2021-03-19 18:17:39 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
import { EventEmitter } from "events";
|
2021-03-19 18:17:39 +00:00
|
|
|
import * as Logger from "js-logger";
|
2020-12-04 18:10:33 +00:00
|
|
|
import { ILogger } from "js-logger";
|
2021-03-19 13:01:51 +00:00
|
|
|
import { generateId } from "../helpers/idMethods";
|
|
|
|
import { getNopeLogger } from "../logger/getLogger";
|
|
|
|
import { LoggerLevel } from "../logger/nopeLogger";
|
2020-12-04 20:39:18 +00:00
|
|
|
import { NopeObservable } from "../observables/nopeObservable";
|
2021-03-19 13:01:51 +00:00
|
|
|
import {
|
|
|
|
ICommunicationBridge,
|
|
|
|
ICommunicationInterface
|
|
|
|
} from "../types/nope/nopeCommunication.interface";
|
2020-12-04 18:10:33 +00:00
|
|
|
import { INopeObservable } from "../types/nope/nopeObservable.interface";
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
const EMITTING_METHODS: Array<keyof ICommunicationInterface> = [
|
2020-12-04 18:10:33 +00:00
|
|
|
"emitAurevoir",
|
|
|
|
"emitBonjour",
|
|
|
|
"emitNewInstanceGeneratorsAvailable",
|
|
|
|
"emitNewInstancesAvailable",
|
|
|
|
"emitNewObersvablesAvailable",
|
|
|
|
"emitNewServicesAvailable",
|
2020-12-05 01:28:33 +00:00
|
|
|
"emitStatusUpdate",
|
2021-03-19 13:01:51 +00:00
|
|
|
"emitTaskCancelation"
|
|
|
|
];
|
|
|
|
|
|
|
|
const EMITTING_SPECIFIC_METHODS: Array<keyof ICommunicationInterface> = [
|
|
|
|
"emitEvent",
|
|
|
|
"emitRpcRequest",
|
|
|
|
"emitRpcResponse"
|
|
|
|
];
|
|
|
|
|
|
|
|
const ON_METHODS: Array<keyof ICommunicationInterface> = [
|
2020-12-04 18:10:33 +00:00
|
|
|
"onAurevoir",
|
|
|
|
"onBonjour",
|
|
|
|
"onNewInstanceGeneratorsAvailable",
|
|
|
|
"onNewInstancesAvailable",
|
|
|
|
"onNewObservablesAvailable",
|
|
|
|
"onNewServicesAvailable",
|
2020-12-05 01:28:33 +00:00
|
|
|
"onStatusUpdate",
|
2021-01-12 15:40:54 +00:00
|
|
|
"onTaskCancelation"
|
2020-12-04 18:10:33 +00:00
|
|
|
];
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
const ON_SPECIFIC_METHODS: Array<keyof ICommunicationInterface> = [
|
|
|
|
"onEvent",
|
|
|
|
"onRpcRequest",
|
|
|
|
"onRpcResponse"
|
|
|
|
];
|
|
|
|
|
|
|
|
const METHOD_TO_EVENT: { [P in keyof ICommunicationInterface]: string } = {
|
|
|
|
// Default emitters
|
|
|
|
emitAurevoir: "aurevoir",
|
|
|
|
emitBonjour: "bonjour",
|
|
|
|
emitNewInstanceGeneratorsAvailable: "NewInstanceGeneratorsAvailable",
|
|
|
|
emitNewInstancesAvailable: "NewInstancesAvailable",
|
|
|
|
emitNewObersvablesAvailable: "NewObersvablesAvailable",
|
|
|
|
emitNewServicesAvailable: "NewServicesAvailable",
|
|
|
|
emitStatusUpdate: "StatusUpdate",
|
|
|
|
emitTaskCancelation: "TaskCancelation",
|
|
|
|
|
|
|
|
// The default Listeners
|
|
|
|
onAurevoir: "aurevoir",
|
|
|
|
onBonjour: "bonjour",
|
|
|
|
onNewInstanceGeneratorsAvailable: "NewInstanceGeneratorsAvailable",
|
|
|
|
onNewInstancesAvailable: "NewInstancesAvailable",
|
|
|
|
onNewObservablesAvailable: "NewObersvablesAvailable",
|
|
|
|
onNewServicesAvailable: "NewServicesAvailable",
|
|
|
|
onStatusUpdate: "StatusUpdate",
|
|
|
|
onTaskCancelation: "TaskCancelation",
|
|
|
|
|
|
|
|
// Specific:
|
|
|
|
onEvent: "event/",
|
2021-03-19 18:17:39 +00:00
|
|
|
onRpcRequest: "",
|
|
|
|
onRpcResponse: "",
|
2021-03-19 13:01:51 +00:00
|
|
|
emitEvent: "event/",
|
2021-03-19 18:17:39 +00:00
|
|
|
emitRpcRequest: "",
|
|
|
|
emitRpcResponse: ""
|
2021-03-19 13:01:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const OFF_METHODS: Array<keyof ICommunicationInterface> = [
|
|
|
|
"offEvent",
|
|
|
|
"offRpcRequest",
|
|
|
|
"offRpcResponse"
|
2021-03-01 16:26:18 +00:00
|
|
|
];
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
const MAPPING_METHODS: {
|
2021-01-12 15:40:54 +00:00
|
|
|
[P in keyof ICommunicationInterface]: keyof ICommunicationInterface;
|
|
|
|
} = {
|
|
|
|
onAurevoir: "emitAurevoir",
|
|
|
|
onBonjour: "emitBonjour",
|
2021-03-19 13:01:51 +00:00
|
|
|
onEvent: "emitEvent",
|
2021-01-12 15:40:54 +00:00
|
|
|
onNewInstanceGeneratorsAvailable: "emitNewInstanceGeneratorsAvailable",
|
|
|
|
onNewInstancesAvailable: "emitNewInstancesAvailable",
|
|
|
|
onNewObservablesAvailable: "emitNewObersvablesAvailable",
|
|
|
|
onNewServicesAvailable: "emitNewServicesAvailable",
|
2021-03-19 13:01:51 +00:00
|
|
|
onRpcRequest: "emitRpcRequest",
|
|
|
|
onRpcResponse: "emitRpcResponse",
|
2021-01-12 15:40:54 +00:00
|
|
|
onTaskCancelation: "emitTaskCancelation",
|
2021-03-01 14:33:59 +00:00
|
|
|
onStatusUpdate: "emitStatusUpdate"
|
2020-12-05 01:28:33 +00:00
|
|
|
};
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
const METHODS_WITH_NAME: Array<keyof ICommunicationInterface> = [
|
2020-12-04 20:39:18 +00:00
|
|
|
"onRpcResponse",
|
2020-12-04 18:10:33 +00:00
|
|
|
"onRpcRequest",
|
2020-12-04 20:39:18 +00:00
|
|
|
"onEvent"
|
2020-12-04 18:10:33 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
//@ts-ignore Ignore the Interface. Its implemented manually
|
2021-03-19 18:17:39 +00:00
|
|
|
export class Bridge implements ICommunicationBridge {
|
2021-02-05 10:53:33 +00:00
|
|
|
public connected: INopeObservable<boolean>;
|
|
|
|
|
|
|
|
public considerConnection = true;
|
2021-03-12 07:34:22 +00:00
|
|
|
public allowServiceRedundancy = false;
|
|
|
|
public ownDispatcherId: string;
|
2021-03-19 13:01:51 +00:00
|
|
|
public id: string;
|
|
|
|
|
|
|
|
protected _logger: ILogger;
|
|
|
|
protected _internalEmitter: EventEmitter;
|
|
|
|
protected _layers: Map<
|
2021-03-12 07:40:31 +00:00
|
|
|
string,
|
|
|
|
{
|
2021-03-19 13:01:51 +00:00
|
|
|
layer: ICommunicationInterface;
|
|
|
|
considerConnection: boolean;
|
|
|
|
forwardData: boolean;
|
2021-03-12 07:40:31 +00:00
|
|
|
}
|
|
|
|
>;
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
protected _callbacks: Map<
|
|
|
|
string, // Method
|
|
|
|
Array<(...args) => any>
|
|
|
|
>;
|
|
|
|
|
|
|
|
protected _specificCallbacks: Array<{
|
|
|
|
callback: (...args) => any;
|
|
|
|
method: keyof ICommunicationInterface;
|
|
|
|
event: string;
|
|
|
|
}>;
|
2020-12-04 20:39:18 +00:00
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
/**
|
|
|
|
* Creates an instance of Bridge.
|
|
|
|
* @param {*} [id=generateId()] The ID. (this can be adapted later and is only used to simplify debugging)
|
|
|
|
* @param {string} [loggerName="bridge"] The Name of the Logger.
|
|
|
|
* @param {LoggerLevel} [level="info"] The Level of the Logger.
|
|
|
|
* @memberof Bridge
|
|
|
|
*/
|
|
|
|
constructor(
|
|
|
|
id = generateId(),
|
|
|
|
loggerName = "bridge",
|
|
|
|
level: LoggerLevel = "info"
|
|
|
|
) {
|
2021-03-19 13:01:51 +00:00
|
|
|
this._internalEmitter = new EventEmitter();
|
|
|
|
this._callbacks = new Map();
|
2021-03-19 18:17:39 +00:00
|
|
|
this._specificCallbacks = [];
|
2021-03-19 13:01:51 +00:00
|
|
|
this._layers = new Map();
|
2021-03-19 18:17:39 +00:00
|
|
|
this._logger = getNopeLogger(loggerName, level);
|
2021-03-19 13:01:51 +00:00
|
|
|
this.id = id;
|
2021-02-05 10:53:33 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
const _this = this;
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Now we use the loops to define the functions,
|
|
|
|
// required by the interface.
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
for (const method of ON_METHODS) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this[method] = async (cb) => {
|
|
|
|
_this._on(method, cb);
|
2021-03-19 13:01:51 +00:00
|
|
|
};
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
for (const method of ON_SPECIFIC_METHODS) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this[method] = async (event: string, cb) => {
|
|
|
|
_this._onSpecific(method, event, cb);
|
2021-03-19 13:01:51 +00:00
|
|
|
};
|
2021-03-19 12:19:06 +00:00
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
for (const method of OFF_METHODS) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this[method] = async (event: string, cb) => {
|
|
|
|
_this._off(cb);
|
2021-03-19 13:01:51 +00:00
|
|
|
};
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
for (const method of EMITTING_METHODS) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this[method] = async (data) => {
|
|
|
|
_this._emit(method, data);
|
2021-03-19 13:01:51 +00:00
|
|
|
};
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
for (const method of EMITTING_SPECIFIC_METHODS) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this[method] = (event: string, data) => {
|
|
|
|
_this._emitSpecific(method, event, data);
|
2021-03-12 07:34:22 +00:00
|
|
|
};
|
2021-03-19 13:01:51 +00:00
|
|
|
}
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
this.connected = new NopeObservable();
|
|
|
|
this.connected.setContent(false);
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Add a custom handler for the connect flag.
|
|
|
|
// the Flag is defined as true, if every socket
|
|
|
|
// is connected.
|
|
|
|
this.connected.getter = () => {
|
|
|
|
for (const data of _this._layers.values()) {
|
|
|
|
if (data.considerConnection && !data.layer.connected.getContent())
|
|
|
|
return false;
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
return true;
|
|
|
|
};
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-19 13:01:51 +00:00
|
|
|
* Helper Function, which will forward an Event.
|
2021-03-12 07:34:22 +00:00
|
|
|
*
|
|
|
|
* @protected
|
2021-03-19 13:01:51 +00:00
|
|
|
* @param {ICommunicationInterface} layerToExclude Layer which should not be handled.
|
|
|
|
* @param {keyof ICommunicationInterface} method The method.
|
|
|
|
* @param {...any[]} args args, used during forwarding.
|
|
|
|
* @memberof BridgeV2
|
2021-03-12 07:34:22 +00:00
|
|
|
*/
|
2021-03-19 13:01:51 +00:00
|
|
|
protected _forward(
|
|
|
|
layerToExclude: ICommunicationInterface,
|
|
|
|
method: keyof ICommunicationInterface,
|
2021-03-19 18:17:39 +00:00
|
|
|
...args
|
2021-03-12 07:34:22 +00:00
|
|
|
): void {
|
2021-03-19 13:01:51 +00:00
|
|
|
// Iterate over the layers and forward the Data to the other Layers
|
|
|
|
for (const data of this._layers.values()) {
|
|
|
|
if (data.layer !== layerToExclude) {
|
2021-03-19 18:17:39 +00:00
|
|
|
data.layer[method as any](...args).catch((error) => {
|
|
|
|
this._logger.error("failed forwarding", method, ...args);
|
|
|
|
this._logger.error(error);
|
|
|
|
});
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-19 13:01:51 +00:00
|
|
|
* Helper Function, which will internally subscribe to the Events of the Layer.
|
2021-03-12 07:34:22 +00:00
|
|
|
*
|
|
|
|
* @protected
|
2021-03-19 13:01:51 +00:00
|
|
|
* @param {ICommunicationInterface} layer The Layer to consinder, on this layer, we will subscribe to the events
|
|
|
|
* @param {keyof ICommunicationInterface} method The method used for subscription
|
2021-03-19 18:17:39 +00:00
|
|
|
* @param {string} event The name of the Event
|
2021-03-19 13:01:51 +00:00
|
|
|
* @param {boolean} forwardData Flag, showing whether data will be forwarded or not.
|
|
|
|
* @memberof BridgeV2
|
2021-03-12 07:34:22 +00:00
|
|
|
*/
|
2021-03-19 13:01:51 +00:00
|
|
|
protected _subscribeToCallback(
|
2021-03-12 07:34:22 +00:00
|
|
|
layer: ICommunicationInterface,
|
2021-03-19 13:01:51 +00:00
|
|
|
method: keyof ICommunicationInterface,
|
2021-03-19 18:17:39 +00:00
|
|
|
event: string,
|
2021-03-19 13:01:51 +00:00
|
|
|
forwardData: boolean
|
|
|
|
): void {
|
2021-03-12 07:34:22 +00:00
|
|
|
const _this = this;
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
if (METHODS_WITH_NAME.includes(method)) {
|
2021-03-19 18:17:39 +00:00
|
|
|
layer[method as any](event, (data) => {
|
2021-03-19 13:01:51 +00:00
|
|
|
// Define the Method to Forward data.
|
2021-03-19 18:17:39 +00:00
|
|
|
_this._internalEmitter.emit(event, data);
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Now we are able to iterate over the Methods and forward the content
|
|
|
|
// but only if the Layer forwards the content
|
|
|
|
if (forwardData) {
|
2021-03-19 18:17:39 +00:00
|
|
|
_this._forward(layer, method, event, data);
|
2021-03-19 13:01:51 +00:00
|
|
|
}
|
2021-03-19 18:17:39 +00:00
|
|
|
}).catch((error) => {
|
|
|
|
_this._logger.error("failed subscribing", method);
|
|
|
|
_this._logger.error(error);
|
2021-03-19 13:01:51 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// Subscribe to the Event.
|
2021-03-19 18:17:39 +00:00
|
|
|
layer[method as any]((data) => {
|
2021-03-19 13:01:51 +00:00
|
|
|
// Define the Method to Forward data.
|
2021-03-19 18:17:39 +00:00
|
|
|
_this._internalEmitter.emit(METHOD_TO_EVENT[method], data);
|
2021-03-19 13:01:51 +00:00
|
|
|
|
|
|
|
// Now we are able to iterate over the Methods and forward the content
|
|
|
|
// but only if the Layer forwards the content
|
|
|
|
if (forwardData) {
|
2021-03-19 18:17:39 +00:00
|
|
|
_this._forward(layer, method, data);
|
2021-03-19 13:01:51 +00:00
|
|
|
}
|
2021-03-19 18:17:39 +00:00
|
|
|
}).catch((error) => {
|
|
|
|
_this._logger.error("failed subscribing", method);
|
|
|
|
_this._logger.error(error);
|
2021-03-19 13:01:51 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
protected _on(method: keyof ICommunicationInterface, cb): void {
|
|
|
|
// Determine the Corresponding Event, that should be used
|
|
|
|
// to subescribe to.
|
|
|
|
const event = METHOD_TO_EVENT[method];
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Subscribe on the Event
|
|
|
|
this._internalEmitter.setMaxListeners(
|
|
|
|
this._internalEmitter.getMaxListeners() + 1
|
|
|
|
);
|
2021-03-19 18:17:39 +00:00
|
|
|
|
|
|
|
if (this._logger.enabledFor(Logger.DEBUG) && event !== "StatusUpdate") {
|
|
|
|
this._logger.debug("subscribe to", event);
|
|
|
|
|
|
|
|
// If logging is enable, we subscribe to that.
|
|
|
|
const _this = this;
|
|
|
|
this._internalEmitter.on(event, (data) => {
|
|
|
|
_this._logger.debug("received", event, data);
|
|
|
|
});
|
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
this._internalEmitter.on(event, cb);
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
// Store the Unspecific callbacks
|
2021-03-19 13:01:51 +00:00
|
|
|
if (!this._callbacks.has(method)) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this._callbacks.set(method, [cb]);
|
2021-03-19 13:01:51 +00:00
|
|
|
} else {
|
2021-03-19 18:17:39 +00:00
|
|
|
this._callbacks.get(method).push(cb);
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
2021-03-19 18:17:39 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Iterate over the Layers and on the connected Layers,
|
|
|
|
// subscribe the methods.
|
|
|
|
for (const data of this._layers.values()) {
|
|
|
|
if (data.layer.connected.getContent()) {
|
2021-03-19 18:17:39 +00:00
|
|
|
this._subscribeToCallback(data.layer, method, event, data.forwardData);
|
2021-03-19 13:01:51 +00:00
|
|
|
}
|
2021-03-12 07:34:22 +00:00
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
protected _onSpecific(
|
2021-03-19 13:01:51 +00:00
|
|
|
method: keyof ICommunicationInterface,
|
|
|
|
event: string,
|
2021-03-19 18:17:39 +00:00
|
|
|
callback
|
2021-03-19 13:01:51 +00:00
|
|
|
): void {
|
2021-03-19 18:17:39 +00:00
|
|
|
// Determine the event that we are using internally.
|
|
|
|
// It is a mix between the method alias channel and
|
|
|
|
// the event.
|
|
|
|
const eventToUse = METHOD_TO_EVENT[method] + event;
|
2020-12-04 20:39:18 +00:00
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
// Subscribe on the Event
|
|
|
|
this._internalEmitter.setMaxListeners(
|
|
|
|
this._internalEmitter.getMaxListeners() + 1
|
|
|
|
);
|
|
|
|
if (this._logger.enabledFor(Logger.DEBUG) && event !== "StatusUpdate") {
|
|
|
|
this._logger.debug("subscribe ", method, "specifically on", eventToUse);
|
|
|
|
|
|
|
|
const _this = this;
|
|
|
|
this._internalEmitter.on(eventToUse, (data) => {
|
|
|
|
_this._logger.debug("received", event, data);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
this._internalEmitter.on(eventToUse, callback);
|
|
|
|
|
|
|
|
// Add the callbacks.
|
|
|
|
this._specificCallbacks.push({
|
|
|
|
callback,
|
|
|
|
method,
|
|
|
|
event
|
|
|
|
});
|
|
|
|
|
|
|
|
// Iterate over the Layers and on the connected Layers,
|
|
|
|
// subscribe the methods.
|
|
|
|
for (const data of this._layers.values()) {
|
|
|
|
if (data.layer.connected.getContent()) {
|
|
|
|
this._subscribeToCallback(data.layer, method, event, data.forwardData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected _off(cb): void {
|
|
|
|
// Determine the event that we are using internally.
|
|
|
|
// It is a mix between the method alias channel and
|
|
|
|
// the event.
|
|
|
|
|
|
|
|
for (let i = 0; i < this._specificCallbacks.length; i++) {
|
|
|
|
if (this._specificCallbacks[i].callback == cb) {
|
|
|
|
this._specificCallbacks.splice(i, 1);
|
|
|
|
break;
|
|
|
|
}
|
2021-03-19 13:01:51 +00:00
|
|
|
}
|
2020-12-05 01:28:33 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Theoretically we must remove the subscriptions.
|
|
|
|
// But we wont do this, because if the connection has
|
|
|
|
// been lost, or the Layer has been removed, the stored
|
|
|
|
// callbacks wont be called any more.
|
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
protected _emit(
|
2021-03-19 18:17:39 +00:00
|
|
|
method: keyof ICommunicationInterface,
|
|
|
|
dataToSend: any
|
|
|
|
): void {
|
|
|
|
const event = METHOD_TO_EVENT[method];
|
|
|
|
|
|
|
|
if (this._logger.enabledFor(Logger.DEBUG) && event !== "StatusUpdate") {
|
|
|
|
this._logger.debug("emitting", event, dataToSend);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the Event on the internal Layer.
|
|
|
|
this._internalEmitter.emit(event, dataToSend);
|
|
|
|
|
|
|
|
const _this = this;
|
|
|
|
|
|
|
|
// Iterate over the Layers.
|
|
|
|
for (const data of this._layers.values()) {
|
|
|
|
// If the Layer has been conneced
|
|
|
|
if (data.layer.connected.getContent()) {
|
|
|
|
data.layer[method as any](dataToSend).catch((error) => {
|
|
|
|
_this._logger.error("failed executing", method);
|
|
|
|
_this._logger.error(error);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected _emitSpecific(
|
2021-03-19 13:01:51 +00:00
|
|
|
method: keyof ICommunicationInterface,
|
|
|
|
event: string,
|
2021-03-19 18:17:39 +00:00
|
|
|
dataToSend: any
|
2021-03-19 13:01:51 +00:00
|
|
|
): void {
|
2021-03-19 18:17:39 +00:00
|
|
|
if (this._logger.enabledFor(Logger.DEBUG) && event !== "StatusUpdate") {
|
|
|
|
this._logger.debug(
|
|
|
|
"emitting",
|
|
|
|
METHOD_TO_EVENT[method] + event,
|
|
|
|
dataToSend
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Emit the Event on the internal Layer.
|
2021-03-19 18:17:39 +00:00
|
|
|
this._internalEmitter.emit(METHOD_TO_EVENT[method] + event, dataToSend);
|
|
|
|
|
|
|
|
const _this = this;
|
2021-03-19 13:01:51 +00:00
|
|
|
|
|
|
|
// Iterate over the Layers.
|
|
|
|
for (const data of this._layers.values()) {
|
|
|
|
// If the Layer has been conneced
|
|
|
|
if (data.layer.connected.getContent()) {
|
2021-03-19 18:17:39 +00:00
|
|
|
data.layer[method as any](event, dataToSend).catch((error) => {
|
|
|
|
_this._logger.error("failed executing", method);
|
|
|
|
_this._logger.error(error);
|
|
|
|
});
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-04 20:39:18 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
public async addLayer(
|
2021-01-12 15:40:54 +00:00
|
|
|
layer: ICommunicationInterface,
|
2021-03-19 13:01:51 +00:00
|
|
|
forwardData = false,
|
|
|
|
considerConnection = false
|
|
|
|
): Promise<void> {
|
|
|
|
if (!this._layers.has(layer.id)) {
|
|
|
|
// Store the Layers:
|
|
|
|
this._layers.set(layer.id, {
|
|
|
|
layer,
|
|
|
|
considerConnection,
|
|
|
|
forwardData
|
|
|
|
});
|
2020-12-05 01:28:33 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Forward the Events of the Layer
|
|
|
|
// being connected to our aggregated
|
|
|
|
// state
|
|
|
|
const _this = this;
|
|
|
|
layer.connected.subscribe(() => {
|
|
|
|
_this.connected.forcePublish();
|
|
|
|
});
|
2021-03-01 13:32:43 +00:00
|
|
|
|
2021-03-19 13:01:51 +00:00
|
|
|
// Wait until the Layer is connected.
|
|
|
|
await layer.connected.waitFor((value) => value);
|
2021-03-12 07:34:22 +00:00
|
|
|
|
2021-03-19 18:17:39 +00:00
|
|
|
// Register all know unspecific methods
|
|
|
|
for (const [method, cbs] of this._callbacks.entries()) {
|
|
|
|
for (const callback of cbs) {
|
|
|
|
layer[method as any](callback);
|
2020-12-05 01:28:33 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-19 18:17:39 +00:00
|
|
|
|
|
|
|
// Register all know specific methods
|
|
|
|
for (const { method, event, callback } of this._specificCallbacks) {
|
|
|
|
layer[method as any](event, callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public async removeLayer(layer: ICommunicationInterface): Promise<void> {
|
|
|
|
if (this._layers.has(layer.id)) {
|
|
|
|
this._layers.delete(layer.id);
|
2020-12-04 20:39:18 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|