nope/lib/cli/runNopeBackend.ts

285 lines
7.2 KiB
TypeScript
Raw Normal View History

/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-11-11 13:27:58
* @modify date 2021-02-05 10:29:03
* @desc [description]
*/
2020-11-23 06:09:31 +00:00
import { ArgumentParser } from "argparse";
import { readFile } from "fs/promises";
import "reflect-metadata";
2020-11-23 06:09:31 +00:00
import { AmqpLayer } from "../communication/amqpLayer";
import { Bridge } from "../communication/bridge";
2020-11-23 06:09:31 +00:00
import { EventLayer } from "../communication/eventLayer";
import { IoSocketClient } from "../communication/IoSocketClient";
import { IoSocketServer } from "../communication/IoSocketServer";
import { getPackageLoader } from "../loader/getPackageLoader";
import { loadFunctions, loadPackages } from "../loader/loadPackages";
import { getNopeLogger } from "../logger/getLogger";
import { LoggerLevel, LoggerLevels } from "../logger/nopeLogger";
2020-11-23 06:09:31 +00:00
import { setGlobalLoggerLevel } from "../logger/setGlobalLoggerLevel";
import { ICommunicationBridge } from "../types/nope/nopeCommunication.interface";
import { INopeDispatcher } from "../types/nope/nopeDispatcher.interface";
2020-11-23 06:09:31 +00:00
import { INopePackageLoader } from "../types/nope/nopePackageLoader.interface";
import { NOPELOGO } from "./renderNope";
2021-01-08 15:58:55 +00:00
export const validLayers = {
"event": EventLayer,
"amqp": AmqpLayer,
"io-server": IoSocketServer,
"io-client": IoSocketClient
};
const layerDefaults = {
event: [],
amqp: ["localhost"],
"io-server": [7000],
"io-client": ["http://localhost:7000"]
};
/**
* Helper Function to Read-In the Arguments used by the
* cli-tool
*
* @return {*}
*/
export async function readInArgs(
additionalArguments: {
help: string;
type: "string" | "number";
name: string | string;
defaultValue?: any;
}[] = []
): Promise<any> {
const parser = new ArgumentParser({
version: "1.0.0",
addHelp: true,
description: "Command Line interface, determines the available Packages."
});
for (const arg of additionalArguments) {
parser.addArgument(arg.name, {
help: arg.help,
defaultValue: arg.defaultValue,
type: arg.type
});
}
parser.addArgument(["-f", "--file"], {
help: "File containing containing the package definitions.",
defaultValue: "./config/settings.json",
type: "string",
dest: "file"
});
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"
});
parser.addArgument(["-p", "--params"], {
help:
"Paramas for the Channel, to connect to. The Following Defaults are used: \n" +
JSON.stringify(layerDefaults, undefined, 4),
defaultValue: "not-provided",
type: "string",
dest: "params"
});
parser.addArgument(["-s", "--skipLoadingConfig"], {
help: "Flag to prevent loading the elements defined in the settings.json.",
action: "append",
nargs: "?",
dest: "skipLoadingConfig"
});
parser.addArgument(["-l", "--log"], {
help:
"Specify the Logger Level. Defaults to \"info\". Valid values are: " +
LoggerLevels.join(", "),
defaultValue: "debug",
type: "string",
dest: "log"
});
const args: {
file: string;
channel: keyof typeof validLayers;
params?: string;
skipLoadingConfig?: boolean;
log: LoggerLevel;
} = parser.parseArgs();
if (args.params === "not-provided") {
delete args.params;
}
args.skipLoadingConfig = Array.isArray(args.skipLoadingConfig);
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;
channel?: keyof typeof validLayers;
params?: string;
skipLoadingConfig?: boolean;
log?: LoggerLevel;
} = {}
): Promise<INopeDispatcher> {
let opts: {
params: any[];
};
const args = Object.assign(
{
file: "./config/settings.json",
channel: "event",
skipLoadingConfig: false,
params: "not-provided",
log: "debug"
},
_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;
}
if (LoggerLevels.includes(args.log)) {
setGlobalLoggerLevel(args.log);
}
// Define a Logger
const logger = getNopeLogger("starter");
if (!Object.getOwnPropertyNames(validLayers).includes(args.channel)) {
logger.error(
"Invalid Channel. Please use the following values. " +
Object.getOwnPropertyNames(validLayers)
.map((item) => "\"" + item + "\"")
.join(", ")
);
return;
}
// Assign the Default Setting for the Channel.
opts.params = layerDefaults[args.channel];
if (args.params != "not-provided") {
try {
opts.params = JSON.parse(args.params);
} catch (e) {
logger.error(
"Unable to parse the Parameters for the channel. Please use valid JSON!"
);
return;
}
}
// If required load all Packages.
if (!args.skipLoadingConfig) {
// Try to load the Modules.
try {
logger.info("loading Functions");
await loadFunctions(args.file);
} catch (e) {
logger.error(
"Unable to load the Packages defined in " +
args.file +
" See Output for detailled information",
e
);
return;
}
}
let loader: INopePackageLoader;
try {
let communicator: ICommunicationBridge = null;
const bridgedLayers: Array<keyof typeof validLayers> = [
"io-server",
"io-client"
];
if (bridgedLayers.includes(args.channel)){
communicator = new validLayers[args.channel](...opts.params) as any as ICommunicationBridge;
} else {
communicator = new Bridge() as any as ICommunicationBridge;
communicator.addLayer(new validLayers[args.channel](...opts.params), true);
}
loader = getPackageLoader({
communicator,
logger: getNopeLogger("dispatcher", "debug")
});
} catch (e) {
getNopeLogger("cli", "info").error("failed to load the Packages", e);
}
// If required load all Packages.
if (!args.skipLoadingConfig) {
// Try to load the Modules.
try {
logger.info("loading Packages");
await loadPackages(loader, args.file);
} catch (e) {
logger.error(
"Unable to load the Packages defined in " +
args.file +
" See Output for detailled information",
e
);
return;
}
}
return loader.dispatcher;
}
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;
});
console.log(NOPELOGO);
console.log("\n\n");
readInArgs()
.then((args) => runNopeBackend(args).catch(console.error))
.catch(console.error);
}
2021-01-08 15:58:55 +00:00
export default main;
// If requested As Main => Perform the Operation.
if (require.main === module) {
main();
}