nope/lib/loader/loadPackages.ts

302 lines
7.5 KiB
TypeScript
Raw Normal View History

/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @desc [description]
*/
import { readFile } from "fs/promises";
import { join, resolve } from "path";
import "reflect-metadata";
import { sleep } from "../helpers/async";
import { createFile, listFiles } from "../helpers/fileMethods";
import { determineDifference } from "../helpers/setMethods";
import {
getCentralDecoratedContainer,
parseWithFunctions,
stringifyWithFunctions,
} from "../index.browser";
import { getNopeLogger } from "../logger/getLogger";
import { IPackageDescription } from "../types/nope/nopePackage.interface";
import { INopePackageLoader } from "../types/nope/nopePackageLoader.interface";
const logger = getNopeLogger("helper-load-packages");
# 1.2.0 - Added: - `lib/cli/nope` adding scan for ui service - `lib/decorators/container`: Main Container, holding all `methods` and `classes`. Use `getCentralDecoratedContainer()` to get this decorator. - `types/nope/nopePackage.interface` added `IClassDescription` which contains the class description used in the Package Description. - `logger/nopeLogger`: added methods: `enabledFor`, `enableFor`, `shouldLog` - `package.json`: installed types of `ace` text editor. - `ui/helpers.browser`: Created `convertInstanceRenderPage` and `IUiDefinition` - `ui/helpers.nodejs`: Added a Helper to write the Ui-File (`writeUiFile`) and parse its arguments (`readInwriteUiFileArgs`) - `ui/index.*`: Crated the corresponding exports. - Modified: - `lib/decorators/*` Adding the main `container` where every function, service method etc is added. All decorators now safe the decorated elements in the container. - `helpers/json`: Adding `BEGIN_STR` and `END_STR` for parsing functions as constants. - `logger/eventLogging`: simplify `useEventLogger` - `logger/index.browser`: Adating exports. - `loader/loadPackages`: Modifing `IPackageConfig` now extends Partial the `IPackageDescription` - `types/ui/editor/IEditPage`: adapting Type of `getData` to `T`->`any`. Adapting the return of `getPorts` (The Ports will be generated in the ui then) - `types/ui/editor/helpers.interface`: Adapting the `w2ui` and added `w2uiHelpers` and added `ace`. Rearanging `IRenderData` element. to compact the data. - `types/ui/editor/render.callbacks`: Rearange the Generic Type of `TRenderInstancePage` and Renaming `TCreatorPage` to `TInstanceManagerPage`. Adapting the `option` of `TInstanceManagerPage` regarding the `createInstance` and `instances` - `types/ui/editor/index`: Adapting the Exports. - `lib/index.browser`: Exporting `ui` elements - `lib/index.nodejs`: Exporting `ui` elements - `lib/types/index`: Exporting `ui` elements - Fixes: - `types/nope/nopeInstanceManager.interface`: Fixing Type of createInstance. Now the Type `I` extends `INopeModule` instead of being set to `IGenericNopeModule`
2022-07-02 09:30:10 +00:00
export interface IPackageConfig extends Partial<IPackageDescription<any>> {
// File Path of the element.
path: string;
}
export interface IConfigFile {
functions: {
path: string;
functions: [];
}[];
packages: IPackageConfig[];
}
/**
* List the available Packages
*
* @export
* @param {string} [dir='./modules']
* @return {*}
*/
export async function listPackages(dir = "./modules") {
// Define the Return Array.
const ret = new Array<{
package: IPackageDescription<any>;
path: string;
}>();
// Scan for the Package-Files
// And iterate over them.
for (const fileName of await listFiles(dir, ".package.js")) {
// Now Try to load a Package, to test whether is is an assembly.
try {
logger.info("found ", fileName);
ret.push({
package: (await import(resolve(fileName)))
.DESCRIPTION as IPackageDescription<any>,
2021-12-04 07:25:26 +00:00
path: fileName,
});
} catch (e) {
logger.error("Failed Loading the Package " + fileName);
logger.error(e);
}
}
return ret;
}
export async function listFunctions(dir = "./modules") {
// Define the Return Array.
const ret = new Array<{
content: any;
path: string;
}>();
// Scan for the Package-Files
// And iterate over them.
for (const fileName of await listFiles(dir, ".functions.js")) {
// Now Try to load a Package, to test whether is is an assembly.
try {
logger.info("found ", fileName);
ret.push({
content: (await import(resolve(fileName))).DESCRIPTION,
2021-12-04 07:25:26 +00:00
path: fileName,
});
} catch (e) {
logger.error("Failed Loading the functions in file: " + fileName);
logger.error(e);
}
}
return ret;
}
/**
* Helper Function to write a default configuration.
*
* @export
* @param {string} [dir='./modules']
* @param {string} [filename=join(resolve(process.cwd()), 'config', 'assembly.json')]
*/
export async function writeDefaultConfig(
dir = "./modules",
filename: string = join(resolve(process.cwd()), "config", "assembly.json")
) {
// Determine all Packages
const packages: IPackageConfig[] = (await listPackages(dir)).map((item) => {
return {
nameOfPackage: item.package.nameOfPackage,
defaultInstances: item.package.defaultInstances,
autostart: item.package.autostart,
2021-12-04 07:25:26 +00:00
path: item.path,
};
});
const functions = (await listFunctions(dir)).map((item) => {
return {
path: item.path,
2021-12-04 07:25:26 +00:00
functions: Object.getOwnPropertyNames(item.content || {}),
};
});
await createFile(
filename,
stringifyWithFunctions(
{
functions,
2021-12-04 07:25:26 +00:00
packages,
},
4
)
);
}
/**
* Function to load the Packages.
*
* @export
* @param {INopePackageLoader} loader
* @param {string} filename
*/
export async function loadPackages(
loader: INopePackageLoader,
filename: string = join(resolve(process.cwd()), "config", "settings.json"),
delay = 2
) {
let data: IConfigFile = {
functions: [],
2021-12-04 07:25:26 +00:00
packages: [],
};
try {
/** Load the File and Parse it. */
data = parseWithFunctions(await readFile(filename, { encoding: "utf8" }));
} catch (e) {
// Generate the Default File
await writeDefaultConfig(filename);
// Show an Hint
logger.warn(
"No configuration was present. Created a new config file in " + filename
);
// Readin the newly created Data.
data = JSON.parse(
await readFile(filename, {
2021-12-04 07:25:26 +00:00
encoding: "utf8",
})
);
}
// Define the Return Array.
const packages = new Array<IPackageDescription<any>>();
// Scan for the Package-Files
// And iterate over them.
for (const item of data.packages) {
// Now Try to load a Package, to test whether is is an assembly.
try {
const loadedPackage = (await import(resolve(item.path)))
.DESCRIPTION as IPackageDescription<any>;
loadedPackage.autostart = item.autostart;
loadedPackage.defaultInstances = item.defaultInstances;
packages.push(loadedPackage);
} catch (e) {
logger.error("Failed Loading the Package " + item.nameOfPackage);
logger.error(e);
}
}
2022-07-23 05:34:38 +00:00
await loader.dispatcher.ready.waitFor();
2020-11-15 19:11:25 +00:00
// Iterate over the Packages
for (const thePackageToLoad of packages) {
try {
await loader.addPackage(thePackageToLoad);
} catch (e) {
logger.error(
2021-12-04 07:25:26 +00:00
'Failed Add the Package "' +
thePackageToLoad.nameOfPackage +
'" to the PackageLoader',
e
);
}
}
if (delay > 0) {
logger.info(`Waiting ${delay} [s] before creating instances.`);
await sleep(delay * 1000);
}
// Generate the instances.
await loader.generateInstances();
}
# 1.2.0 - Added: - `lib/cli/nope` adding scan for ui service - `lib/decorators/container`: Main Container, holding all `methods` and `classes`. Use `getCentralDecoratedContainer()` to get this decorator. - `types/nope/nopePackage.interface` added `IClassDescription` which contains the class description used in the Package Description. - `logger/nopeLogger`: added methods: `enabledFor`, `enableFor`, `shouldLog` - `package.json`: installed types of `ace` text editor. - `ui/helpers.browser`: Created `convertInstanceRenderPage` and `IUiDefinition` - `ui/helpers.nodejs`: Added a Helper to write the Ui-File (`writeUiFile`) and parse its arguments (`readInwriteUiFileArgs`) - `ui/index.*`: Crated the corresponding exports. - Modified: - `lib/decorators/*` Adding the main `container` where every function, service method etc is added. All decorators now safe the decorated elements in the container. - `helpers/json`: Adding `BEGIN_STR` and `END_STR` for parsing functions as constants. - `logger/eventLogging`: simplify `useEventLogger` - `logger/index.browser`: Adating exports. - `loader/loadPackages`: Modifing `IPackageConfig` now extends Partial the `IPackageDescription` - `types/ui/editor/IEditPage`: adapting Type of `getData` to `T`->`any`. Adapting the return of `getPorts` (The Ports will be generated in the ui then) - `types/ui/editor/helpers.interface`: Adapting the `w2ui` and added `w2uiHelpers` and added `ace`. Rearanging `IRenderData` element. to compact the data. - `types/ui/editor/render.callbacks`: Rearange the Generic Type of `TRenderInstancePage` and Renaming `TCreatorPage` to `TInstanceManagerPage`. Adapting the `option` of `TInstanceManagerPage` regarding the `createInstance` and `instances` - `types/ui/editor/index`: Adapting the Exports. - `lib/index.browser`: Exporting `ui` elements - `lib/index.nodejs`: Exporting `ui` elements - `lib/types/index`: Exporting `ui` elements - Fixes: - `types/nope/nopeInstanceManager.interface`: Fixing Type of createInstance. Now the Type `I` extends `INopeModule` instead of being set to `IGenericNopeModule`
2022-07-02 09:30:10 +00:00
/**
* Helper to read function provided in the defined configuration.
*
* @author M.Karkowski
* @export
* @param {string} [filename=join(resolve(process.cwd()), "config", "assembly.json")]
* @return {*}
*/
export async function loadFunctions(
loader: INopePackageLoader,
filename: string = join(resolve(process.cwd()), "config", "settings.json"),
delay = 2
) {
let data: IConfigFile = {
functions: [],
2021-12-04 07:25:26 +00:00
packages: [],
};
try {
/** Load the File and Parse it. */
data = JSON.parse(await readFile(filename, { encoding: "utf8" }));
} catch (e) {
// Generate the Default File
await writeDefaultConfig(filename);
// Show an Hint
logger.warn(
"No configuration was present. Created a new config file in " + filename
);
// Readin the newly created Data.
data = JSON.parse(
await readFile(filename, {
2021-12-04 07:25:26 +00:00
encoding: "utf8",
})
);
}
// Define the Return Array.
const successfull = new Array<any>();
// Get the container containing all registered Services and Classes.
const CONTAINER = getCentralDecoratedContainer();
// Scan for the Package-Files
// And iterate over them.
for (const item of data.functions) {
// Now Try to load a Package, to test whether is is an assembly.
try {
// Load the Function:
const before = new Set<string>(CONTAINER.services.keys());
await import(resolve(item.path));
const after = new Set<string>(CONTAINER.services.keys());
const diff = determineDifference(before, after);
if (diff.added.size > 0) {
logger.info(
"loaded services of file",
'"' + item.path + '"',
"found:" + JSON.stringify(Array.from(diff.added), undefined, 4)
);
}
// Mark the file as sucessfully loaded.
successfull.push(item.path);
} catch (e) {
logger.error("Failed Loading function-file at " + item.path);
logger.error(e);
}
}
await loader.addDecoratedElements({
consider: ["services"],
});
if (delay > 0) {
logger.info(`Waiting ${delay} [s] before creating instances.`);
await sleep(delay * 1000);
}
return successfull;
}