nope-js-node
Version:
NoPE Runtime for Nodejs. For Browser-Support please use nope-browser
446 lines (413 loc) • 12.8 kB
text/typescript
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-11-11 13:27:58
* @modify date 2021-01-18 18:48:59
* @desc [description]
*/
import { ArgumentParser } from "argparse";
import { readFile } from "fs/promises";
import { join, resolve } from "path";
import {
parseWithFunctions,
stringifyWithFunctions,
} from "../helpers/jsonMethods";
import { IConfigFile, writeDefaultConfig } from "../loader/loadPackages";
import {
ValidLoggerDefinition,
getNopeLogger,
LoggerLevel,
LoggerLevels,
} from "../logger/index.nodejs";
import * as inquirer from "inquirer";
import { createInteractiveMenu } from "../helpers/cli";
import { createFile } from "../helpers/fileMethods";
import {
layerDefaultParameters,
validLayerOrMirror,
} from "../communication/index.nodejs";
inquirer.registerPrompt("search-checkbox", require("inquirer-search-checkbox"));
// Define the Main Function.
// This function is used as cli tool.
export const generateDefaultPackageConfig = async function (
additionalArguments: {
help: string;
type: "string" | "number";
name: string | string;
defaultValue?: any;
}[] = []
) {
const parser = new ArgumentParser({
// version: "1.0.0",
add_help: true,
description: "Command Line interface, determines the available Packages.",
});
let opts: {
modules: string;
};
for (const arg of additionalArguments) {
parser.add_argument(arg.name, {
help: arg.help,
default: arg.defaultValue,
type: arg.type,
});
}
try {
// Try to read in the default config file.
opts = JSON.parse(
await readFile("./nopeconfig.json", {
encoding: "utf-8",
})
);
} catch (error) {
opts = {} as any;
}
parser.add_argument("-f", "--file", {
help: "File containing containing the package definitions.",
default: "./config/settings.json",
type: "str",
dest: "file",
});
parser.add_argument("-d", "--dir", {
help: "Directory containing the Modules.",
default: "not-provided",
type: "str",
dest: "modules",
});
parser.add_argument("-i", "--interactive", {
help: "Interactive mode to define the config.",
action: "append",
nargs: "?",
dest: "interact",
});
const args = parser.parse_args();
args.interact = Array.isArray(args.interact);
if (args.modules != "not-provided") {
opts.modules = args.modules;
}
// Define a Logger
const logger = getNopeLogger("Setup-CLI");
try {
logger.info("Scanning " + opts.modules);
// Write the Config.
await writeDefaultConfig(opts.modules, args.file);
// Inform the user.
logger.info("Created Package-File at " + args.file);
if (args.interact) {
await reduceConfiguration(args.file);
}
} catch (error) {
logger.error("Failed generating the Config");
logger.error(error);
}
};
export async function reduceConfiguration(
filename: string = join(resolve(process.cwd()), "config", "settings.json")
) {
/** Load the File and Parse it. */
let data: IConfigFile = parseWithFunctions(
await readFile(filename, { encoding: "utf8" })
);
await createInteractiveMenu(
[
{
name: "save changes",
value: "save",
type: "item",
async onSelect() {
// Store the config file
await createFile(filename, stringifyWithFunctions(data, 4));
},
},
{
name: "reload configuration",
value: "reload",
type: "item",
async onSelect() {
// Reload the data.
data = parseWithFunctions(
await readFile(filename, { encoding: "utf8" })
);
},
},
{
name: "service",
type: "menu",
items: [
{
name: "remove services",
value: "remove-services",
type: "item",
async onSelect() {
const functions = (
await inquirer.prompt({
type: "search-checkbox",
name: "result",
message: "Please select the enabled services",
choices: data.functions.map((func) => {
return {
key: func.path,
name: func.path,
value: func,
};
}),
})
).result;
data.functions = functions;
},
},
],
value: "service",
},
{
type: "menu",
value: "package",
items: [
{
name: "select provided packages",
value: "select-packages",
type: "item",
async onSelect() {
const packages = (
await inquirer.prompt({
type: "search-checkbox",
name: "result",
message: "Please select the enabled packages",
choices: data.packages.map((pkg) => {
return {
key: pkg.path,
name: pkg.nameOfPackage,
value: pkg,
checked: true,
};
}),
})
).result;
data.packages = packages;
},
},
{
name: "select default instances",
value: "select-default-instances",
type: "item",
async onSelect() {
const choices: {
key: string;
name: string;
value: any;
checked: true;
}[] = [];
for (const pkg of data.packages) {
for (const instance of pkg.defaultInstances || []) {
choices.push({
key: pkg.nameOfPackage + instance.options.identifier,
name: pkg.nameOfPackage + "." + instance.options.identifier,
value: {
pkg,
instance,
},
checked: true,
});
}
}
const selectedInstances = (
await inquirer.prompt({
type: "search-checkbox",
name: "result",
message: "Please select the packages to use.",
choices,
})
).result;
for (const pkg of data.packages) {
pkg.defaultInstances = [];
}
for (const item of selectedInstances) {
const { instance, pkg } = item;
pkg.defaultInstances.push(instance);
}
},
},
{
name: "disable default instances",
value: "disable-default-instances",
type: "item",
async onSelect() {
for (const pkg of data.packages) {
pkg.defaultInstances = [];
pkg.autostart = {};
}
},
},
{
name: "select autostart of instances",
value: "select-autostart",
type: "item",
async onSelect() {
const choices: {
key: string;
name: string;
value: any;
checked: true;
}[] = [];
for (const pkg of data.packages) {
for (const name in pkg.autostart || {}) {
const start = pkg.autostart[name];
choices.push({
key: pkg.nameOfPackage + name,
name: pkg.nameOfPackage + "." + name,
value: {
pkg,
start,
name,
},
checked: true,
});
}
}
const selectedInstances = (
await inquirer.prompt({
type: "search-checkbox",
name: "result",
message: "Please select the packages to use.",
choices,
})
).result;
for (const pkg of data.packages) {
pkg.autostart = {};
}
for (const item of selectedInstances) {
const { pkg, start, name } = item;
pkg.autostart[name] = start;
}
},
},
{
name: "disable autostart of instances",
value: "disable-autostart",
type: "item",
async onSelect() {
for (const pkg of data.packages) {
pkg.autostart = {};
}
},
},
],
name: "packages",
},
{
type: "menu",
value: "connection",
items: [
{
name: "add connection",
value: "add-connection",
type: "item",
async onSelect() {
const name: Omit<validLayerOrMirror, "event"> = (
await inquirer.prompt({
type: "search-list",
name: "layer",
message: "Please select the layer:",
choices: Object.getOwnPropertyNames(layerDefaultParameters),
})
).layer;
console.log(
"Please provide the required URL. Please use '" +
layerDefaultParameters[name as any] +
"' as example."
);
const url = (
await inquirer.prompt([
{
type: "input",
message: "Please enter valid JSON.",
name: "url",
},
])
).url;
const wantToLog = (
await inquirer.prompt({
type: "confirm",
name: "result",
message: "Do you want to have a logger for the Layer?",
})
).result;
let log: ValidLoggerDefinition = false;
if (wantToLog) {
log = (
await inquirer.prompt({
type: "list",
name: "result",
message: "Please select the logger level.",
choices: LoggerLevels,
})
).result;
}
const considerConnection = (
await inquirer.prompt({
type: "confirm",
name: "result",
message:
"Do you want to consider that layer as base Layer. If 'yes', the Dispatcher will wait until the Layer is connected before autostarting.",
})
).result;
const forwardData = (
await inquirer.prompt({
type: "confirm",
name: "result",
message:
"Do you want to forward data of other layers to this layer?",
})
).result;
data.connections.push({
name: name as any,
url,
considerConnection,
log,
forwardData,
});
},
},
{
name: "select enabled connections",
value: "select-connections",
type: "item",
async onSelect() {
const connections = (
await inquirer.prompt({
type: "search-checkbox",
name: "result",
message: "Please select the enabled packages",
choices: data.connections.map((item, index) => {
return {
key: index,
name: item.name + ": " + item.url.toString(),
value: item,
checked: true,
};
}),
})
).result;
data.connections = connections;
// Store the config file
await createFile(filename, stringifyWithFunctions(data, 4));
},
},
],
name: "connections",
},
],
{
addExit: true,
async exitCallback() {
// Store the change
await createFile(filename, stringifyWithFunctions(data, 4));
},
}
);
}
if (require.main === module) {
generateDefaultPackageConfig().catch((e) => {
console.error(e);
});
}