2022-01-04 11:40:40 +00:00
|
|
|
/**
|
|
|
|
* @author Martin Karkowski
|
|
|
|
* @email m.karkowski@zema.de
|
|
|
|
* @create date 2022-01-03 21:21:45
|
2022-01-16 19:38:45 +00:00
|
|
|
* @modify date 2022-01-10 14:10:00
|
2022-01-04 11:40:40 +00:00
|
|
|
* @desc [description]
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { ILogger } from "js-logger";
|
2022-04-20 12:20:48 +00:00
|
|
|
import { avgOfArray, minOfArray } from "../../helpers/arrayMethods";
|
2022-01-04 11:40:40 +00:00
|
|
|
import { generateId } from "../../helpers/idMethods";
|
|
|
|
import { MapBasedMergeData } from "../../helpers/mergedData";
|
|
|
|
import { RUNNINGINNODE } from "../../helpers/runtimeMethods";
|
|
|
|
import { defineNopeLogger } from "../../logger/getLogger";
|
2022-01-16 19:38:45 +00:00
|
|
|
import { DEBUG, WARN } from "../../logger/index.browser";
|
2022-01-04 11:40:40 +00:00
|
|
|
import {
|
|
|
|
ENopeDispatcherStatus,
|
2022-01-07 17:12:08 +00:00
|
|
|
ICommunicationBridge,
|
|
|
|
IMapBasedMergeData,
|
|
|
|
INopeConnectivityManager,
|
2022-01-05 17:13:46 +00:00
|
|
|
INopeINopeConnectivityOptions,
|
2022-01-07 17:12:08 +00:00
|
|
|
INopeINopeConnectivityTimeOptions,
|
|
|
|
INopeObservable,
|
2022-04-08 07:35:02 +00:00
|
|
|
INopeStatusInfo,
|
2022-01-04 11:40:40 +00:00
|
|
|
} from "../../types/nope";
|
|
|
|
|
2022-01-05 16:49:45 +00:00
|
|
|
// Chached Moduls, which will be loaded in nodejs
|
2022-01-04 11:40:40 +00:00
|
|
|
let os = null;
|
|
|
|
let cpus = null;
|
|
|
|
|
2022-01-18 07:01:50 +00:00
|
|
|
// The Naviagtor for the Browser
|
|
|
|
declare const navigator;
|
|
|
|
|
2022-01-04 11:40:40 +00:00
|
|
|
/**
|
2022-01-05 16:49:45 +00:00
|
|
|
* A Modul to manage the status of other statusmanagers.
|
|
|
|
* Dispatcher should have a status manager, to ensure, the
|
|
|
|
* system is online etc.
|
2022-01-04 11:40:40 +00:00
|
|
|
*
|
2022-01-05 16:49:45 +00:00
|
|
|
* @author M.Karkowski
|
2022-01-04 11:40:40 +00:00
|
|
|
* @export
|
2022-01-05 17:13:46 +00:00
|
|
|
* @class NopeConnectivityManager
|
|
|
|
* @implements {INopeConnectivityManager}
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
2022-01-05 17:13:46 +00:00
|
|
|
export class NopeConnectivityManager implements INopeConnectivityManager {
|
2022-01-04 11:40:40 +00:00
|
|
|
protected _logger: ILogger;
|
|
|
|
protected _deltaTime = 0;
|
2022-01-16 19:38:45 +00:00
|
|
|
protected _connectedSince: number;
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The used Communication interface
|
|
|
|
*
|
|
|
|
* @type {ICommunicationBridge}
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
2022-01-05 16:49:45 +00:00
|
|
|
protected readonly _communicator: ICommunicationBridge;
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A Map holding the current Status of external dispatchers.
|
|
|
|
* Key = Dispatcher-ID
|
|
|
|
* Value = Last Known status of the dispatcher
|
|
|
|
*
|
|
|
|
* @protected
|
2022-01-05 16:49:45 +00:00
|
|
|
* @type {Map<string, INopeStatusInfo>}
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
2022-01-05 16:49:45 +00:00
|
|
|
protected _externalDispatchers: Map<string, INopeStatusInfo>;
|
2022-01-04 11:40:40 +00:00
|
|
|
|
2022-01-05 16:49:45 +00:00
|
|
|
/**
|
|
|
|
* Timeout settings. This will define the Timers etc.
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @protected
|
2022-01-05 17:13:46 +00:00
|
|
|
* @type {INopeINopeConnectivityTimeOptions}
|
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-05 16:49:45 +00:00
|
|
|
*/
|
2022-01-05 17:13:46 +00:00
|
|
|
protected _timeouts: INopeINopeConnectivityTimeOptions;
|
2022-01-04 11:40:40 +00:00
|
|
|
|
2022-01-05 16:49:45 +00:00
|
|
|
protected _checkInterval: any = null; // Timer to check the status
|
2022-01-07 17:12:08 +00:00
|
|
|
protected _sendInterval: any = null; // Timer to send the status
|
|
|
|
protected _cpuInterval: any = null; // Timer to update the CPU-Load
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
/**
|
2022-01-05 16:49:45 +00:00
|
|
|
* Internal var to hold the cpu-load
|
2022-01-04 11:40:40 +00:00
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
2022-01-05 16:49:45 +00:00
|
|
|
* @protected
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
2022-01-05 16:49:45 +00:00
|
|
|
protected _cpuLoad = -1;
|
|
|
|
|
|
|
|
public readonly ready: INopeObservable<boolean>;
|
|
|
|
public readonly dispatchers: IMapBasedMergeData<
|
2022-07-07 07:14:22 +00:00
|
|
|
string, // Dispatcher ID
|
|
|
|
INopeStatusInfo, // Orginal Message
|
|
|
|
string, // Dispatcher ID
|
|
|
|
string // Dispatcher ID
|
2022-01-05 16:49:45 +00:00
|
|
|
>;
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
/**
|
2022-01-19 17:38:43 +00:00
|
|
|
* see {@link INopeConnectivityManager.info}
|
2022-01-04 11:40:40 +00:00
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
2022-01-19 17:38:43 +00:00
|
|
|
* @readonly
|
|
|
|
* @type {INopeStatusInfo}
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
2022-01-05 16:49:45 +00:00
|
|
|
public get info(): INopeStatusInfo {
|
2022-01-04 11:40:40 +00:00
|
|
|
if (RUNNINGINNODE) {
|
|
|
|
// If we are running our programm in node,
|
|
|
|
// we will load the corresponding libs,
|
|
|
|
// to calc the cpu load etc.
|
|
|
|
|
|
|
|
if (os === null) {
|
|
|
|
// eslint-disable-next-line
|
|
|
|
os = require("os");
|
|
|
|
}
|
|
|
|
if (cpus === null) {
|
|
|
|
// eslint-disable-next-line
|
|
|
|
cpus = os.cpus();
|
|
|
|
}
|
2022-01-05 16:49:45 +00:00
|
|
|
|
|
|
|
// Now lets return our status message
|
2022-01-04 11:40:40 +00:00
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
env: "javascript",
|
2022-01-05 16:49:45 +00:00
|
|
|
version: "1.0.0",
|
2022-01-16 19:38:45 +00:00
|
|
|
isMaster: this.isMaster,
|
2022-04-20 12:20:48 +00:00
|
|
|
isMasterForced: typeof this.__isMaster === "boolean",
|
2022-01-04 11:40:40 +00:00
|
|
|
host: {
|
|
|
|
cores: cpus.length,
|
|
|
|
cpu: {
|
|
|
|
model: `${cpus[0].model}`.slice(
|
|
|
|
0,
|
|
|
|
(cpus[0].model as string).indexOf("@") - 1
|
|
|
|
),
|
|
|
|
speed: avgOfArray(cpus, "speed"),
|
|
|
|
usage: this._cpuLoad,
|
|
|
|
},
|
|
|
|
os: os.platform(),
|
|
|
|
ram: {
|
|
|
|
// Return the used Memory
|
|
|
|
usedPerc: 1 - os.freemem() / os.totalmem(),
|
|
|
|
// The Values are given in Byte but we want MByte
|
|
|
|
free: Math.round(os.freemem() / 1048576),
|
|
|
|
total: Math.round(os.totalmem() / 1048576),
|
|
|
|
},
|
|
|
|
name: os.hostname(),
|
|
|
|
},
|
|
|
|
pid: process.pid,
|
2022-01-16 19:38:45 +00:00
|
|
|
timestamp: this.now,
|
2022-04-08 07:33:31 +00:00
|
|
|
connectedSince: this.connectedSince,
|
2022-01-04 11:40:40 +00:00
|
|
|
status: ENopeDispatcherStatus.HEALTHY,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
env: "javascript",
|
2022-01-05 16:49:45 +00:00
|
|
|
version: "1.0.0",
|
2022-01-16 19:38:45 +00:00
|
|
|
isMaster: this.isMaster,
|
2022-04-20 12:20:48 +00:00
|
|
|
isMasterForced: typeof this.__isMaster === "boolean",
|
2022-01-04 11:40:40 +00:00
|
|
|
host: {
|
|
|
|
cores: -1,
|
|
|
|
cpu: {
|
|
|
|
model: "unkown",
|
|
|
|
speed: -1,
|
|
|
|
usage: -1,
|
|
|
|
},
|
|
|
|
name: navigator.appCodeName + " " + navigator.appName,
|
|
|
|
os: navigator.platform,
|
|
|
|
ram: {
|
|
|
|
free: -1,
|
|
|
|
usedPerc: -1,
|
|
|
|
total: -1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
id: this.id,
|
|
|
|
pid: this.id,
|
2022-01-16 19:38:45 +00:00
|
|
|
timestamp: this.now,
|
2022-04-08 07:33:31 +00:00
|
|
|
connectedSince: this.connectedSince,
|
2022-01-04 11:40:40 +00:00
|
|
|
status: ENopeDispatcherStatus.HEALTHY,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-19 17:38:43 +00:00
|
|
|
* Creates an instance of NopeConnectivityManager.
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @param {INopeINopeConnectivityOptions} options The Options, used by the Manager.
|
|
|
|
* @param {<T>() => INopeObservable<T>} _generateObservable A Helper, to generate Observables.
|
|
|
|
* @param {string} [id=null] specific id. Otherwise a ID is generated
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
|
|
|
constructor(
|
2022-01-05 17:13:46 +00:00
|
|
|
public options: INopeINopeConnectivityOptions,
|
2022-01-04 11:40:40 +00:00
|
|
|
protected _generateObservable: <T>() => INopeObservable<T>,
|
|
|
|
public readonly id: string = null
|
|
|
|
) {
|
2022-01-05 16:49:45 +00:00
|
|
|
this._communicator = options.communicator;
|
2022-01-16 19:38:45 +00:00
|
|
|
this._connectedSince = Date.now();
|
|
|
|
|
2022-04-20 12:20:48 +00:00
|
|
|
this.__isMaster =
|
|
|
|
typeof options.isMaster === "boolean" ? options.isMaster : null;
|
|
|
|
|
2022-01-04 11:40:40 +00:00
|
|
|
if (id === null) {
|
|
|
|
this.id = generateId();
|
|
|
|
}
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
this._logger = defineNopeLogger(
|
|
|
|
options.logger,
|
|
|
|
"core.connectivity-manager"
|
|
|
|
);
|
2022-01-04 11:40:40 +00:00
|
|
|
|
2022-01-05 16:49:45 +00:00
|
|
|
// Update the Timesettings
|
|
|
|
this.setTimings(options.timeouts || {});
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
// Flag to show if the system is ready or not.
|
|
|
|
this.ready = this._generateObservable();
|
|
|
|
this.ready.setContent(false);
|
|
|
|
|
|
|
|
// Observable containing all Dispatcher Informations.
|
|
|
|
this._externalDispatchers = new Map();
|
2022-01-16 19:38:45 +00:00
|
|
|
this.dispatchers = new MapBasedMergeData(this._externalDispatchers, "id");
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
if (this._logger) {
|
2022-01-16 19:38:45 +00:00
|
|
|
this._logger.info("core.connectivity-manager", this.id, "is ready");
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.reset();
|
|
|
|
const _this = this;
|
|
|
|
this._init().catch((error) => {
|
|
|
|
if (_this._logger) {
|
|
|
|
_this._logger.error("Failed to intialize status manager");
|
|
|
|
_this._logger.error(error);
|
|
|
|
|
|
|
|
// Now we should exit the program (if we are running in nodejs)
|
|
|
|
if (RUNNINGINNODE) {
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.upTime}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @readonly
|
|
|
|
* @type {number}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-01-16 19:38:45 +00:00
|
|
|
public get upTime(): number {
|
|
|
|
return Date.now() - this._connectedSince;
|
|
|
|
}
|
|
|
|
|
2022-04-08 07:33:31 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.connectedSince}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @readonly
|
|
|
|
* @type {number}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
|
|
|
public get connectedSince(): number {
|
|
|
|
return this._connectedSince + this._deltaTime;
|
|
|
|
}
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
/**
|
|
|
|
* Internal value to store the Master.
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @protected
|
|
|
|
* @type {boolean}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-04-20 12:20:48 +00:00
|
|
|
protected __isMaster: boolean;
|
2022-01-16 19:38:45 +00:00
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.isMaster}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-04-20 12:20:48 +00:00
|
|
|
public set isMaster(value: boolean | null) {
|
2022-01-16 19:38:45 +00:00
|
|
|
this.__isMaster = value;
|
2022-01-20 10:02:38 +00:00
|
|
|
// We want to forward our new status.
|
|
|
|
this._sendStatus();
|
2022-01-16 19:38:45 +00:00
|
|
|
}
|
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.isMaster}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @type {boolean}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-01-16 19:38:45 +00:00
|
|
|
public get isMaster(): boolean {
|
2022-04-20 12:20:48 +00:00
|
|
|
if (typeof this.__isMaster !== "boolean") {
|
|
|
|
try {
|
|
|
|
return this.id == this.master.id;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
2022-01-16 19:38:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.__isMaster;
|
|
|
|
}
|
|
|
|
|
2022-04-20 12:20:48 +00:00
|
|
|
/**
|
|
|
|
* Helper, to extract the possible-masters
|
|
|
|
* @returns
|
|
|
|
*/
|
|
|
|
protected _getPossibleMasterCandidates() {
|
|
|
|
const possibleMasters: INopeStatusInfo[] = [];
|
|
|
|
|
|
|
|
for (const info of this.dispatchers.originalData.values()) {
|
|
|
|
if (info.isMasterForced && !info.isMaster) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
possibleMasters.push(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return possibleMasters;
|
|
|
|
}
|
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.master}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @readonly
|
|
|
|
* @type {INopeStatusInfo}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-01-16 19:38:45 +00:00
|
|
|
public get master(): INopeStatusInfo {
|
2022-04-20 12:20:48 +00:00
|
|
|
const candidates = this._getPossibleMasterCandidates();
|
|
|
|
const masters = candidates.filter((item) => item.isMaster);
|
2022-01-16 19:38:45 +00:00
|
|
|
|
|
|
|
if (masters.length === 0) {
|
2022-04-20 12:20:48 +00:00
|
|
|
const idx = minOfArray(candidates, "connectedSince").index;
|
|
|
|
if (idx !== -1) {
|
|
|
|
return candidates[idx];
|
|
|
|
}
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
throw Error("No Master has been found !");
|
|
|
|
} else if (masters.length > 1) {
|
2022-04-20 12:20:48 +00:00
|
|
|
throw Error(
|
|
|
|
"Multiple Masters has been found!" +
|
|
|
|
JSON.stringify(masters, undefined, 4)
|
|
|
|
);
|
2022-01-16 19:38:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return masters[0];
|
|
|
|
}
|
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.now}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @readonly
|
|
|
|
* @type {number}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-01-16 19:38:45 +00:00
|
|
|
public get now(): number {
|
|
|
|
return Date.now() + this._deltaTime;
|
|
|
|
}
|
|
|
|
|
2022-01-04 11:40:40 +00:00
|
|
|
/**
|
|
|
|
* Internal Function, used to initialize the Dispatcher.
|
|
|
|
* It subscribes to the "Messages" of the communicator.
|
|
|
|
*
|
|
|
|
* @protected
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
|
|
|
protected async _init(): Promise<void> {
|
|
|
|
const _this = this;
|
|
|
|
|
|
|
|
this.ready.setContent(false);
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
// Now lets wait until we are ready.
|
|
|
|
// Everytime, we reconnect, we will adapt
|
|
|
|
this._communicator.connected.subscribe((connected) => {
|
|
|
|
if (connected) {
|
|
|
|
// Now we are up.
|
|
|
|
this._connectedSince = Date.now();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-04 11:40:40 +00:00
|
|
|
// Wait until the Element is connected.
|
2022-01-05 16:49:45 +00:00
|
|
|
await this._communicator.connected.waitFor((value) => value);
|
2022-01-04 11:40:40 +00:00
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
await this._communicator.on("StatusChanged", (info) => {
|
2022-01-04 11:40:40 +00:00
|
|
|
_this._externalDispatchers.set(info.id, info);
|
2022-04-20 12:20:48 +00:00
|
|
|
|
|
|
|
// If there is an update, we have to make shure, that our information
|
|
|
|
// is propageted correctly.
|
|
|
|
if (info.id !== _this.id) {
|
|
|
|
_this._externalDispatchers.set(_this.id, _this.info);
|
|
|
|
}
|
|
|
|
|
2022-01-05 16:49:45 +00:00
|
|
|
_this.dispatchers.update();
|
2022-01-04 11:40:40 +00:00
|
|
|
});
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
await this._communicator.on("Bonjour", ({ dispatcherId }) => {
|
|
|
|
if (_this.id !== dispatcherId) {
|
|
|
|
if (_this._logger?.enabledFor(DEBUG)) {
|
2022-01-04 11:40:40 +00:00
|
|
|
// If there is a Logger:
|
|
|
|
_this._logger.debug(
|
2022-01-16 19:38:45 +00:00
|
|
|
'Remote Dispatcher "' + dispatcherId + '" went online'
|
2022-01-04 11:40:40 +00:00
|
|
|
);
|
|
|
|
}
|
2022-04-08 07:33:31 +00:00
|
|
|
|
|
|
|
// Say Hello by sending the Status
|
2022-04-08 07:35:02 +00:00
|
|
|
_this._sendStatus();
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
await this._communicator.on("Aurevoir", ({ dispatcherId }) => {
|
2022-01-04 11:40:40 +00:00
|
|
|
// Remove the Dispatcher.
|
2022-01-16 19:38:45 +00:00
|
|
|
_this._externalDispatchers.delete(dispatcherId);
|
2022-01-05 16:49:45 +00:00
|
|
|
_this.dispatchers.update();
|
2022-01-04 11:40:40 +00:00
|
|
|
});
|
|
|
|
|
2022-04-20 12:20:48 +00:00
|
|
|
await this._sendStatus();
|
|
|
|
|
2022-01-04 11:40:40 +00:00
|
|
|
if (this._logger) {
|
2022-01-16 19:38:45 +00:00
|
|
|
this._logger.info("core.connectivity-manager", this.id, "initialized");
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
await this.emitBonjour();
|
2022-01-20 10:02:38 +00:00
|
|
|
await this._sendStatus();
|
2022-01-04 11:40:40 +00:00
|
|
|
|
|
|
|
this.ready.setContent(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function, which will be called to update the
|
|
|
|
* Status to the Dispatchers
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @protected
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
|
|
|
protected _checkDispatcherHealth(): void {
|
|
|
|
const currentTime = Date.now();
|
|
|
|
let changes = false;
|
|
|
|
|
|
|
|
for (const status of this._externalDispatchers.values()) {
|
|
|
|
// determine the Difference
|
|
|
|
const diff = currentTime - status.timestamp;
|
|
|
|
|
|
|
|
// Based on the Difference Determine the Status
|
|
|
|
if (diff > this._timeouts.remove) {
|
|
|
|
// remove the Dispatcher. But be quite.
|
|
|
|
// Perhaps more dispatchers will be removed
|
|
|
|
this._removeDispatcher(status.id, true);
|
|
|
|
changes = true;
|
|
|
|
} else if (
|
|
|
|
diff > this._timeouts.dead &&
|
|
|
|
status.status !== ENopeDispatcherStatus.DEAD
|
|
|
|
) {
|
|
|
|
status.status = ENopeDispatcherStatus.DEAD;
|
|
|
|
changes = true;
|
|
|
|
} else if (
|
|
|
|
diff > this._timeouts.warn &&
|
|
|
|
diff <= this._timeouts.dead &&
|
|
|
|
status.status !== ENopeDispatcherStatus.WARNING
|
|
|
|
) {
|
|
|
|
status.status = ENopeDispatcherStatus.WARNING;
|
|
|
|
changes = true;
|
|
|
|
} else if (
|
|
|
|
diff > this._timeouts.slow &&
|
|
|
|
diff <= this._timeouts.warn &&
|
|
|
|
status.status !== ENopeDispatcherStatus.SLOW
|
|
|
|
) {
|
|
|
|
status.status = ENopeDispatcherStatus.SLOW;
|
|
|
|
changes = true;
|
|
|
|
} else if (
|
|
|
|
diff <= this._timeouts.slow &&
|
|
|
|
status.status !== ENopeDispatcherStatus.HEALTHY
|
|
|
|
) {
|
|
|
|
status.status = ENopeDispatcherStatus.HEALTHY;
|
|
|
|
changes = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changes) {
|
|
|
|
// Update the External Dispatchers
|
2022-01-05 16:49:45 +00:00
|
|
|
this.dispatchers.update();
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-05 16:49:45 +00:00
|
|
|
/**
|
|
|
|
* Removes a Dispatcher.
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @protected
|
2022-01-19 17:38:43 +00:00
|
|
|
* @param {string} dispatcher The Id of the dispatcher
|
|
|
|
* @param {boolean} [quite=false] if set to quite, the *dispatchers* attribute wont be udpated.
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-05 16:49:45 +00:00
|
|
|
*/
|
2022-01-04 11:40:40 +00:00
|
|
|
protected _removeDispatcher(dispatcher: string, quite = false): void {
|
|
|
|
// Delete the Generators of the Instances.
|
|
|
|
const dispatcherInfo = this._externalDispatchers.get(dispatcher);
|
|
|
|
const deleted = this._externalDispatchers.delete(dispatcher);
|
|
|
|
|
|
|
|
if (!quite) {
|
2022-01-05 16:49:45 +00:00
|
|
|
this.dispatchers.update();
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-16 19:38:45 +00:00
|
|
|
if (deleted && this._logger?.enabledFor(WARN)) {
|
2022-01-04 11:40:40 +00:00
|
|
|
// If there is a Logger:
|
|
|
|
this._logger.warn(
|
|
|
|
"a dispatcher on",
|
|
|
|
dispatcherInfo?.host.name || "unkown",
|
|
|
|
"went offline. ID of the Dispatcher: ",
|
|
|
|
dispatcher
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-10 06:52:05 +00:00
|
|
|
/**
|
|
|
|
* Helper to send the current status to other statusmanagers.
|
2022-01-19 17:38:43 +00:00
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @protected
|
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-10 06:52:05 +00:00
|
|
|
*/
|
2022-04-20 12:20:48 +00:00
|
|
|
protected async _sendStatus(): Promise<void> {
|
2022-01-20 10:02:38 +00:00
|
|
|
// Test if we are connected
|
|
|
|
if (this._communicator.connected.getContent()) {
|
2022-04-20 12:20:48 +00:00
|
|
|
try {
|
|
|
|
const info = this.info;
|
|
|
|
this._externalDispatchers.set(this.id, info);
|
|
|
|
await this._communicator.emit("StatusChanged", info);
|
|
|
|
} catch (e) {
|
|
|
|
this._logger.error("Failled to send the status");
|
|
|
|
}
|
2022-01-20 10:02:38 +00:00
|
|
|
}
|
2022-01-05 16:49:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-19 17:38:43 +00:00
|
|
|
* see {@link INopeConnectivityManager.syncTime}
|
2022-01-05 16:49:45 +00:00
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
2022-01-19 17:38:43 +00:00
|
|
|
* @param {number} timestamp
|
|
|
|
* @param {number} [delay=0]
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-05 16:49:45 +00:00
|
|
|
*/
|
|
|
|
public syncTime(timestamp: number, delay = 0) {
|
|
|
|
const _internalTimestamp = Date.now();
|
2022-01-25 19:43:17 +00:00
|
|
|
this._deltaTime = _internalTimestamp - timestamp - delay;
|
2022-01-05 16:49:45 +00:00
|
|
|
}
|
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.getStatus}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @param {string} id
|
|
|
|
* @return {*}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-01-05 16:49:45 +00:00
|
|
|
public getStatus(id: string) {
|
2022-01-07 17:12:08 +00:00
|
|
|
return this._externalDispatchers.get(id);
|
2022-01-05 16:49:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-19 17:38:43 +00:00
|
|
|
* see {@link INopeConnectivityManager.emitBonjour}
|
2022-01-05 16:49:45 +00:00
|
|
|
*
|
2022-01-19 17:38:43 +00:00
|
|
|
* @author M.Karkowski
|
|
|
|
* @return {Promise<void>}
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-05 16:49:45 +00:00
|
|
|
*/
|
|
|
|
public async emitBonjour(): Promise<void> {
|
|
|
|
// Emit the Bonjour Message.
|
2022-01-16 19:38:45 +00:00
|
|
|
this._communicator.emit("Bonjour", { dispatcherId: this.id });
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-19 17:38:43 +00:00
|
|
|
* see {@link INopeConnectivityManager.reset}
|
2022-01-04 11:40:40 +00:00
|
|
|
*
|
2022-01-19 17:38:43 +00:00
|
|
|
* @author M.Karkowski
|
2022-01-05 17:13:46 +00:00
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-04 11:40:40 +00:00
|
|
|
*/
|
|
|
|
public reset(): void {
|
|
|
|
this._externalDispatchers.clear();
|
2022-01-05 16:49:45 +00:00
|
|
|
this.dispatchers.update(this._externalDispatchers);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-19 17:38:43 +00:00
|
|
|
* see {@link INopeConnectivityManager.setTimings}
|
2022-01-05 16:49:45 +00:00
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
2022-01-05 17:13:46 +00:00
|
|
|
* @param {Partial<INopeINopeConnectivityTimeOptions>} options
|
|
|
|
* @memberof NopeConnectivityManager
|
2022-01-05 16:49:45 +00:00
|
|
|
*/
|
2022-01-05 17:13:46 +00:00
|
|
|
public setTimings(options: Partial<INopeINopeConnectivityTimeOptions>): void {
|
2022-01-05 16:49:45 +00:00
|
|
|
// Clear all Intervals etc.
|
|
|
|
this.dispose(true);
|
|
|
|
|
|
|
|
const _this = this;
|
|
|
|
|
|
|
|
this._timeouts = {
|
|
|
|
sendAliveInterval: 500,
|
|
|
|
checkInterval: 250,
|
|
|
|
slow: 1000,
|
|
|
|
warn: 2000,
|
|
|
|
dead: 5000,
|
|
|
|
remove: 10000,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Define the Timeouts.
|
|
|
|
if (options) {
|
|
|
|
this._timeouts = Object.assign(this._timeouts, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RUNNINGINNODE) {
|
|
|
|
// eslint-disable-next-line
|
|
|
|
const os = require("os");
|
|
|
|
|
|
|
|
const getLoad = () => {
|
|
|
|
const cpus = os.cpus();
|
2022-07-17 20:26:33 +00:00
|
|
|
let totalTime = 0;
|
|
|
|
let idleTime = 0;
|
2022-01-05 16:49:45 +00:00
|
|
|
|
|
|
|
// Determine the current load:
|
|
|
|
for (const cpu of cpus) {
|
|
|
|
for (const name in cpu.times) {
|
|
|
|
totalTime += cpu.times[name];
|
|
|
|
}
|
|
|
|
idleTime += cpu.times.idle;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
totalTime,
|
|
|
|
idleTime,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initally store the load
|
|
|
|
let oldTimes = getLoad();
|
|
|
|
this._cpuInterval = setInterval(() => {
|
|
|
|
// Get the current CPU Times.
|
|
|
|
const currentTimes = getLoad();
|
|
|
|
// Determine the difference between the old Times an the current Times.
|
|
|
|
_this._cpuLoad =
|
|
|
|
1 -
|
|
|
|
(currentTimes.idleTime - oldTimes.idleTime) /
|
2022-01-07 17:12:08 +00:00
|
|
|
(currentTimes.totalTime - oldTimes.totalTime);
|
2022-01-05 16:49:45 +00:00
|
|
|
// Store the current CPU-Times
|
|
|
|
oldTimes = currentTimes;
|
|
|
|
}, this._timeouts.sendAliveInterval);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup Test Intervals:
|
|
|
|
if (this._timeouts.checkInterval > 0) {
|
|
|
|
// Define a Checker, which will test the status
|
|
|
|
// of the external Dispatchers.
|
|
|
|
this._checkInterval = setInterval(
|
|
|
|
() => _this._checkDispatcherHealth(),
|
|
|
|
this._timeouts.checkInterval
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._timeouts.sendAliveInterval > 0) {
|
|
|
|
// Define a Timer, which will emit Status updates with
|
|
|
|
// the disered delay.
|
|
|
|
this._sendInterval = setInterval(
|
|
|
|
() => _this._sendStatus(),
|
|
|
|
this._timeouts.sendAliveInterval
|
|
|
|
);
|
|
|
|
}
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
|
2022-01-19 17:38:43 +00:00
|
|
|
/**
|
|
|
|
* see {@link INopeConnectivityManager.getAllHosts}
|
|
|
|
*
|
|
|
|
* @author M.Karkowski
|
|
|
|
* @return {*} {string[]}
|
|
|
|
* @memberof NopeConnectivityManager
|
|
|
|
*/
|
2022-01-16 19:38:45 +00:00
|
|
|
public getAllHosts(): string[] {
|
|
|
|
const hosts = new Set<string>();
|
|
|
|
for (const info of this.dispatchers.originalData.values()) {
|
|
|
|
hosts.add(info.host.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Array.from(hosts);
|
|
|
|
}
|
|
|
|
|
2022-01-04 11:40:40 +00:00
|
|
|
/**
|
|
|
|
* Will dispose the Dispatcher. Must be called on exit for a clean exit. Otherwise it is defined as dirty exits
|
|
|
|
*/
|
|
|
|
public async dispose(quite = false): Promise<void> {
|
|
|
|
if (this._sendInterval) {
|
|
|
|
clearInterval(this._sendInterval);
|
|
|
|
}
|
|
|
|
if (this._checkInterval) {
|
|
|
|
clearInterval(this._checkInterval);
|
|
|
|
}
|
|
|
|
if (this._cpuInterval) {
|
|
|
|
clearInterval(this._cpuInterval);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emits the aurevoir Message.
|
|
|
|
if (!quite) {
|
2022-01-16 19:38:45 +00:00
|
|
|
this._communicator.emit("Aurevoir", { dispatcherId: this.id });
|
2022-01-04 11:40:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|