2020-11-11 16:08:11 +00:00
|
|
|
/**
|
|
|
|
* @author Martin Karkowski
|
|
|
|
* @email m.karkowski@zema.de
|
|
|
|
* @create date 2020-11-11 13:27:58
|
2021-10-19 08:01:00 +00:00
|
|
|
* @modify date 2021-10-19 09:15:38
|
2020-11-11 16:08:11 +00:00
|
|
|
* @desc [description]
|
2021-03-24 06:50:36 +00:00
|
|
|
*
|
2020-11-11 16:08:11 +00:00
|
|
|
*/
|
|
|
|
|
2020-11-23 06:09:31 +00:00
|
|
|
import { ArgumentParser } from "argparse";
|
|
|
|
import { readFile } from "fs/promises";
|
2020-11-11 16:08:11 +00:00
|
|
|
import "reflect-metadata";
|
2021-03-24 06:50:36 +00:00
|
|
|
import {
|
|
|
|
getLayer,
|
|
|
|
layerDefaultParameters,
|
2021-04-12 05:09:47 +00:00
|
|
|
validLayerOrMirror,
|
|
|
|
validLayers
|
2021-09-03 05:42:37 +00:00
|
|
|
} from "../communication/getLayer.nodejs";
|
2021-10-18 18:46:06 +00:00
|
|
|
import { sleep } from "../helpers/async";
|
2020-11-23 06:09:31 +00:00
|
|
|
import { getPackageLoader } from "../loader/getPackageLoader";
|
|
|
|
import { loadFunctions, loadPackages } from "../loader/loadPackages";
|
2021-10-18 05:56:24 +00:00
|
|
|
import { generateLogfilePath, useLogFile } from "../logger/fileLogging";
|
2020-11-23 06:09:31 +00:00
|
|
|
import { getNopeLogger } from "../logger/getLogger";
|
2021-01-08 07:56:01 +00:00
|
|
|
import { LoggerLevel, LoggerLevels } from "../logger/nopeLogger";
|
2020-11-23 06:09:31 +00:00
|
|
|
import { setGlobalLoggerLevel } from "../logger/setGlobalLoggerLevel";
|
2021-10-19 08:01:00 +00:00
|
|
|
import { INopeTimeOptions, ValidDefaultSelectors } from "../types/nope/nopeDispatcher.interface";
|
2020-11-23 06:09:31 +00:00
|
|
|
import { INopePackageLoader } from "../types/nope/nopePackageLoader.interface";
|
2020-12-04 18:10:33 +00:00
|
|
|
import { NOPELOGO } from "./renderNope";
|
2020-11-11 16:08:11 +00:00
|
|
|
|
2021-01-08 07:56:01 +00:00
|
|
|
/**
|
|
|
|
* Helper Function to Read-In the Arguments used by the
|
|
|
|
* cli-tool
|
|
|
|
*
|
|
|
|
* @return {*}
|
|
|
|
*/
|
2021-01-21 07:38:44 +00:00
|
|
|
export async function readInArgs(
|
|
|
|
additionalArguments: {
|
|
|
|
help: string;
|
|
|
|
type: "string" | "number";
|
|
|
|
name: string | string;
|
|
|
|
defaultValue?: any;
|
|
|
|
}[] = []
|
|
|
|
): Promise<any> {
|
2020-12-04 18:10:33 +00:00
|
|
|
const parser = new ArgumentParser({
|
|
|
|
version: "1.0.0",
|
|
|
|
addHelp: true,
|
|
|
|
description: "Command Line interface, determines the available Packages."
|
|
|
|
});
|
|
|
|
|
2021-01-21 07:38:44 +00:00
|
|
|
for (const arg of additionalArguments) {
|
|
|
|
parser.addArgument(arg.name, {
|
|
|
|
help: arg.help,
|
|
|
|
defaultValue: arg.defaultValue,
|
|
|
|
type: arg.type
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
parser.addArgument(["-f", "--file"], {
|
|
|
|
help: "File containing containing the package definitions.",
|
|
|
|
defaultValue: "./config/settings.json",
|
|
|
|
type: "string",
|
|
|
|
dest: "file"
|
|
|
|
});
|
2021-10-15 06:16:53 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
parser.addArgument(["-c", "--channel"], {
|
|
|
|
help:
|
|
|
|
"The Communication Channel, which should be used. Possible Values are: " +
|
|
|
|
// Display all Options:
|
|
|
|
Object.getOwnPropertyNames(validLayers)
|
|
|
|
.map((item) => "\"" + item + "\"")
|
|
|
|
.join(", "),
|
|
|
|
defaultValue: "event",
|
|
|
|
type: "string",
|
|
|
|
dest: "channel"
|
|
|
|
});
|
2021-10-15 06:16:53 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
parser.addArgument(["-p", "--params"], {
|
|
|
|
help:
|
|
|
|
"Paramas for the Channel, to connect to. The Following Defaults are used: \n" +
|
2021-03-24 06:50:36 +00:00
|
|
|
JSON.stringify(layerDefaultParameters, undefined, 4),
|
2020-12-04 18:10:33 +00:00
|
|
|
defaultValue: "not-provided",
|
|
|
|
type: "string",
|
|
|
|
dest: "params"
|
|
|
|
});
|
2021-10-15 06:16:53 +00:00
|
|
|
|
2021-08-04 12:55:56 +00:00
|
|
|
parser.addArgument(["-s", "--skip-loading-config"], {
|
2020-12-04 18:10:33 +00:00
|
|
|
help: "Flag to prevent loading the elements defined in the settings.json.",
|
|
|
|
action: "append",
|
|
|
|
nargs: "?",
|
|
|
|
dest: "skipLoadingConfig"
|
|
|
|
});
|
2021-08-04 12:55:56 +00:00
|
|
|
|
2021-10-15 06:16:53 +00:00
|
|
|
parser.addArgument(["--default-selector"], {
|
|
|
|
help: "The default-selector to select the service providers. Possible Values are: " +
|
|
|
|
// Display all Options:
|
|
|
|
Object.getOwnPropertyNames(ValidDefaultSelectors)
|
|
|
|
.map((item) => "\"" + item + "\"")
|
|
|
|
.join(", "),
|
|
|
|
defaultValue: "first",
|
2021-10-15 14:59:56 +00:00
|
|
|
type: "string",
|
2021-10-15 06:16:53 +00:00
|
|
|
dest: "defaultSelector"
|
|
|
|
});
|
|
|
|
|
2021-08-04 12:55:56 +00:00
|
|
|
parser.addArgument(["--force-emit"], {
|
|
|
|
help: "Forces emitting the events of the system. Otherwise, only subscribed events are emitted.",
|
|
|
|
action: "append",
|
|
|
|
nargs: "?",
|
|
|
|
dest: "forceEmittingUpdates"
|
|
|
|
});
|
|
|
|
|
2021-10-18 05:56:24 +00:00
|
|
|
parser.addArgument(["--log-to-file"], {
|
|
|
|
help: "Log will be stored in a logfile.",
|
|
|
|
action: "append",
|
|
|
|
nargs: "?",
|
|
|
|
dest: "logToFile"
|
|
|
|
});
|
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
parser.addArgument(["-l", "--log"], {
|
|
|
|
help:
|
|
|
|
"Specify the Logger Level. Defaults to \"info\". Valid values are: " +
|
|
|
|
LoggerLevels.join(", "),
|
2021-01-08 07:56:01 +00:00
|
|
|
defaultValue: "debug",
|
2020-12-04 18:10:33 +00:00
|
|
|
type: "string",
|
|
|
|
dest: "log"
|
|
|
|
});
|
|
|
|
|
2021-10-17 10:15:30 +00:00
|
|
|
parser.addArgument(["--dispatcher-log"], {
|
|
|
|
help:
|
|
|
|
"Specify the Logger Level of the Dispatcher. Defaults to \"info\". Valid values are: " +
|
|
|
|
LoggerLevels.join(", "),
|
2021-10-18 05:56:24 +00:00
|
|
|
defaultValue: "info",
|
2021-10-17 10:15:30 +00:00
|
|
|
type: "string",
|
|
|
|
dest: "dispatcherLogLevel"
|
|
|
|
});
|
|
|
|
|
2021-10-18 18:46:06 +00:00
|
|
|
parser.addArgument(["--force-selector"], {
|
|
|
|
help: "Forces to use the Selector. Otherwise a smart approach is used, which only enables them if required.",
|
|
|
|
action: "append",
|
|
|
|
nargs: "?",
|
|
|
|
dest: "forceUsingSelectors"
|
|
|
|
});
|
|
|
|
|
|
|
|
parser.addArgument(["-d", "--delay"], {
|
|
|
|
help: "Adds an delay, which will be waited, after the system connected. Parmeter is provided in [s]. Defaults to \"2\"",
|
|
|
|
defaultValue: 2,
|
|
|
|
type: "float",
|
|
|
|
dest: "delay"
|
|
|
|
});
|
|
|
|
|
2021-10-18 05:56:24 +00:00
|
|
|
parser.addArgument(["--communication-log"], {
|
|
|
|
help:
|
|
|
|
"Specify the Logger Level of the Communication. Defaults to \"info\". Valid values are: " +
|
|
|
|
LoggerLevels.join(", "),
|
|
|
|
defaultValue: "info",
|
|
|
|
type: "string",
|
|
|
|
dest: "communicationLogLevel"
|
|
|
|
});
|
|
|
|
|
2021-01-08 07:56:01 +00:00
|
|
|
const args: {
|
|
|
|
file: string;
|
|
|
|
channel: keyof typeof validLayers;
|
|
|
|
params?: string;
|
|
|
|
skipLoadingConfig?: boolean;
|
|
|
|
log: LoggerLevel;
|
2021-08-04 12:55:56 +00:00
|
|
|
forceEmittingUpdates?: boolean;
|
2021-10-15 06:16:53 +00:00
|
|
|
defaultSelector: ValidDefaultSelectors
|
2021-10-17 10:15:30 +00:00
|
|
|
dispatcherLogLevel: LoggerLevel
|
2021-10-18 05:56:24 +00:00
|
|
|
communicationLogLevel?: LoggerLevel,
|
|
|
|
logToFile?: boolean
|
2021-10-18 18:46:06 +00:00
|
|
|
delay: number,
|
|
|
|
forceUsingSelectors?: boolean
|
2021-01-08 07:56:01 +00:00
|
|
|
} = parser.parseArgs();
|
2020-12-04 18:10:33 +00:00
|
|
|
|
2021-01-08 07:56:01 +00:00
|
|
|
if (args.params === "not-provided") {
|
|
|
|
delete args.params;
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
args.skipLoadingConfig = Array.isArray(args.skipLoadingConfig);
|
2021-08-04 12:55:56 +00:00
|
|
|
args.forceEmittingUpdates = Array.isArray(args.forceEmittingUpdates);
|
2021-10-18 05:56:24 +00:00
|
|
|
args.logToFile = Array.isArray(args.logToFile);
|
2021-10-18 18:46:06 +00:00
|
|
|
args.forceUsingSelectors = Array.isArray(args.forceUsingSelectors);
|
2020-12-04 18:10:33 +00:00
|
|
|
|
2021-01-08 07:56:01 +00:00
|
|
|
return args;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define the Main Function.
|
|
|
|
// This function is used as cli tool.
|
2021-01-08 15:58:55 +00:00
|
|
|
export async function runNopeBackend(
|
|
|
|
_args: {
|
|
|
|
file?: string;
|
2021-03-24 06:50:36 +00:00
|
|
|
channel?: validLayerOrMirror;
|
2021-01-08 15:58:55 +00:00
|
|
|
params?: string;
|
2021-08-04 12:55:56 +00:00
|
|
|
// Flag to prevent loading the configuration
|
2021-01-08 15:58:55 +00:00
|
|
|
skipLoadingConfig?: boolean;
|
2021-08-04 12:55:56 +00:00
|
|
|
// Flag to force sending updates.
|
|
|
|
forceEmittingUpdates?: boolean;
|
|
|
|
// Level of the logger.
|
2021-01-08 15:58:55 +00:00
|
|
|
log?: LoggerLevel;
|
2021-08-17 15:52:46 +00:00
|
|
|
// The Enable Singletons. Defaults to true
|
|
|
|
singleton?: boolean;
|
2021-10-15 06:16:53 +00:00
|
|
|
// The default-selector to select the service providers
|
2021-10-17 10:15:30 +00:00
|
|
|
defaultSelector?: ValidDefaultSelectors;
|
|
|
|
// The default-selector to select the service providers
|
|
|
|
dispatcherLogLevel?: LoggerLevel
|
2021-10-18 05:56:24 +00:00
|
|
|
// The default-selector to select the service providers
|
|
|
|
communicationLogLevel?: LoggerLevel,
|
|
|
|
// Enable File-logging:
|
2021-10-18 18:46:06 +00:00
|
|
|
logToFile?: boolean,
|
|
|
|
// Delay to wait for system beeing ready.
|
|
|
|
delay?: number,
|
|
|
|
// Flag to force using the selectors. Might have a performance inpact.
|
2021-10-19 08:01:00 +00:00
|
|
|
forceUsingSelectors?: boolean,
|
|
|
|
// Define the Timingsparameter
|
|
|
|
timings?: Partial<INopeTimeOptions>
|
2021-09-03 05:42:37 +00:00
|
|
|
} = {}
|
2021-08-17 15:52:46 +00:00
|
|
|
): Promise<INopePackageLoader> {
|
2021-01-08 07:56:01 +00:00
|
|
|
let opts: {
|
2021-03-24 06:50:36 +00:00
|
|
|
params: string | number;
|
2021-01-08 07:56:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const args = Object.assign(
|
|
|
|
{
|
|
|
|
file: "./config/settings.json",
|
|
|
|
channel: "event",
|
|
|
|
skipLoadingConfig: false,
|
|
|
|
params: "not-provided",
|
2021-08-17 15:52:46 +00:00
|
|
|
log: "debug",
|
2021-10-17 10:15:30 +00:00
|
|
|
singleton: true,
|
2021-10-18 05:56:24 +00:00
|
|
|
dispatcherLogLevel: "info",
|
2021-10-18 18:46:06 +00:00
|
|
|
communicationLogLevel: "info",
|
|
|
|
delay: 2,
|
2021-10-19 08:01:00 +00:00
|
|
|
forceSelectors: false,
|
|
|
|
timings: {}
|
2021-01-08 07:56:01 +00:00
|
|
|
},
|
|
|
|
_args
|
|
|
|
);
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Try to read in the default config file.
|
|
|
|
opts = JSON.parse(
|
|
|
|
await readFile("./nopeconfig.json", {
|
|
|
|
encoding: "utf-8"
|
|
|
|
})
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
opts = {} as any;
|
|
|
|
}
|
|
|
|
|
2021-10-18 05:56:24 +00:00
|
|
|
if (args.logToFile) {
|
|
|
|
const fileName = generateLogfilePath("run");
|
|
|
|
useLogFile(fileName, 10);
|
|
|
|
}
|
|
|
|
|
2021-01-08 07:56:01 +00:00
|
|
|
if (LoggerLevels.includes(args.log)) {
|
|
|
|
setGlobalLoggerLevel(args.log);
|
|
|
|
}
|
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
// Define a Logger
|
|
|
|
const logger = getNopeLogger("starter");
|
|
|
|
|
|
|
|
if (!Object.getOwnPropertyNames(validLayers).includes(args.channel)) {
|
|
|
|
logger.error(
|
|
|
|
"Invalid Channel. Please use the following values. " +
|
2021-10-15 06:16:53 +00:00
|
|
|
Object.getOwnPropertyNames(validLayers)
|
|
|
|
.map((item) => "\"" + item + "\"")
|
|
|
|
.join(", ")
|
2020-11-11 16:08:11 +00:00
|
|
|
);
|
2020-12-04 18:10:33 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-11-12 16:07:05 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
// Assign the Default Setting for the Channel.
|
2021-03-24 06:50:36 +00:00
|
|
|
opts.params = layerDefaultParameters[args.channel];
|
2020-11-11 16:08:11 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
if (args.params != "not-provided") {
|
|
|
|
try {
|
2021-08-04 12:55:56 +00:00
|
|
|
try {
|
|
|
|
// We try to parse the data.
|
|
|
|
opts.params = JSON.parse(args.params);
|
|
|
|
} catch (e) {
|
|
|
|
opts.params = JSON.parse("\"" + args.params + "\"");
|
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
} catch (e) {
|
|
|
|
logger.error(
|
|
|
|
"Unable to parse the Parameters for the channel. Please use valid JSON!"
|
|
|
|
);
|
2021-08-04 12:55:56 +00:00
|
|
|
logger.error(args.params[0]);
|
|
|
|
logger.error(e);
|
2020-12-04 18:10:33 +00:00
|
|
|
return;
|
2020-11-12 16:07:05 +00:00
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
2020-11-12 16:07:05 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
// If required load all Packages.
|
|
|
|
if (!args.skipLoadingConfig) {
|
|
|
|
// Try to load the Modules.
|
2020-11-11 16:08:11 +00:00
|
|
|
try {
|
2020-12-04 18:10:33 +00:00
|
|
|
logger.info("loading Functions");
|
|
|
|
await loadFunctions(args.file);
|
|
|
|
} catch (e) {
|
|
|
|
logger.error(
|
|
|
|
"Unable to load the Packages defined in " +
|
2021-10-15 06:16:53 +00:00
|
|
|
args.file +
|
|
|
|
" See Output for detailled information",
|
2020-12-04 18:10:33 +00:00
|
|
|
e
|
|
|
|
);
|
|
|
|
return;
|
2020-11-11 16:08:11 +00:00
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
2020-11-11 16:08:11 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
let loader: INopePackageLoader;
|
|
|
|
try {
|
2021-09-03 05:42:37 +00:00
|
|
|
loader = getPackageLoader(
|
|
|
|
{
|
2021-10-18 05:56:24 +00:00
|
|
|
communicator: getLayer(args.channel, opts.params, args.communicationLogLevel),
|
2021-10-17 10:15:30 +00:00
|
|
|
logger: getNopeLogger("dispatcher", args.dispatcherLogLevel),
|
2021-09-03 05:42:37 +00:00
|
|
|
forceEmittingUpdates:
|
2021-10-15 06:16:53 +00:00
|
|
|
args.forceEmittingUpdates || args.channel == "event",
|
2021-10-18 18:46:06 +00:00
|
|
|
defaultSelector: args.defaultSelector,
|
|
|
|
forceUsingSelectors: args.forceUsingSelectors
|
2021-09-03 05:42:37 +00:00
|
|
|
},
|
|
|
|
_args.singleton
|
|
|
|
);
|
2020-12-04 18:10:33 +00:00
|
|
|
} catch (e) {
|
|
|
|
getNopeLogger("cli", "info").error("failed to load the Packages", e);
|
|
|
|
}
|
2020-11-11 17:11:37 +00:00
|
|
|
|
2021-10-18 18:46:06 +00:00
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
// If required load all Packages.
|
|
|
|
if (!args.skipLoadingConfig) {
|
|
|
|
// Try to load the Modules.
|
2021-10-18 18:46:06 +00:00
|
|
|
|
|
|
|
if (args.delay > 0) {
|
|
|
|
logger.info(`Waiting ${args.delay} [s] to get all information.`);
|
|
|
|
await sleep(args.delay * 1000);
|
|
|
|
}
|
|
|
|
|
2020-12-04 18:10:33 +00:00
|
|
|
try {
|
|
|
|
logger.info("loading Packages");
|
2021-10-18 18:46:06 +00:00
|
|
|
await loadPackages(loader, args.file, args.delay);
|
2020-12-04 18:10:33 +00:00
|
|
|
} catch (e) {
|
|
|
|
logger.error(
|
|
|
|
"Unable to load the Packages defined in " +
|
2021-10-15 06:16:53 +00:00
|
|
|
args.file +
|
|
|
|
" See Output for detailled information",
|
2020-12-04 18:10:33 +00:00
|
|
|
e
|
|
|
|
);
|
|
|
|
return;
|
2020-11-12 16:07:05 +00:00
|
|
|
}
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
2020-11-12 16:07:05 +00:00
|
|
|
|
2021-05-13 11:26:45 +00:00
|
|
|
const _dispose = () => {
|
|
|
|
// We should close the Process:
|
|
|
|
logger.warn("received 'ctrl+c'. Shutting down the Instances");
|
|
|
|
loader.dispatcher.dispose().finally(process.exit);
|
|
|
|
};
|
|
|
|
|
|
|
|
process.on("SIGINT", _dispose);
|
|
|
|
process.on("SIGTERM", _dispose);
|
|
|
|
process.on("exit", () => {
|
|
|
|
logger.info("Completed. Goodbye");
|
|
|
|
});
|
2021-08-17 15:52:46 +00:00
|
|
|
return loader;
|
2020-11-11 16:08:11 +00:00
|
|
|
}
|
|
|
|
|
2021-01-08 15:58:55 +00:00
|
|
|
/**
|
|
|
|
* Main Function.
|
|
|
|
*
|
|
|
|
* @export
|
|
|
|
*/
|
|
|
|
export function main() {
|
2021-01-04 18:12:17 +00:00
|
|
|
// Subscribe to unhandled Reactions.
|
|
|
|
process.on("unhandledRejection", (reason, p) => {
|
|
|
|
console.log("Unhandled Rejection at: Promise", p, "reason:", reason);
|
|
|
|
console.error(reason);
|
|
|
|
// application specific logging, throwing an error, or other logic here
|
|
|
|
|
|
|
|
// Forward the error
|
|
|
|
throw reason;
|
|
|
|
});
|
|
|
|
|
2021-01-08 07:56:01 +00:00
|
|
|
console.log(NOPELOGO);
|
|
|
|
console.log("\n\n");
|
|
|
|
readInArgs()
|
|
|
|
.then((args) => runNopeBackend(args).catch(console.error))
|
|
|
|
.catch(console.error);
|
2020-12-04 18:10:33 +00:00
|
|
|
}
|
2021-01-08 15:58:55 +00:00
|
|
|
|
|
|
|
export default main;
|
|
|
|
|
|
|
|
// If requested As Main => Perform the Operation.
|
|
|
|
if (require.main === module) {
|
|
|
|
main();
|
|
|
|
}
|