|
@@ -1,3 +1,4 @@
|
|
|
+import async from "async";
|
|
|
import BaseModule from "./BaseModule";
|
|
|
import Job from "./Job";
|
|
|
import JobQueue from "./JobQueue";
|
|
@@ -10,7 +11,7 @@ type ModuleClass<Module extends typeof BaseModule> = {
|
|
|
};
|
|
|
|
|
|
export default class ModuleManager {
|
|
|
- private modules: Modules | null;
|
|
|
+ private modules?: Modules;
|
|
|
|
|
|
private jobQueue: JobQueue;
|
|
|
|
|
@@ -19,7 +20,6 @@ export default class ModuleManager {
|
|
|
*
|
|
|
*/
|
|
|
public constructor() {
|
|
|
- this.modules = null;
|
|
|
this.jobQueue = new JobQueue();
|
|
|
}
|
|
|
|
|
@@ -29,14 +29,10 @@ export default class ModuleManager {
|
|
|
* @returns {object} Module statuses
|
|
|
*/
|
|
|
public getStatus() {
|
|
|
- if (!this.modules) return {};
|
|
|
-
|
|
|
const status: Record<string, ModuleStatus> = {};
|
|
|
-
|
|
|
- Object.entries(this.modules).forEach(([name, module]) => {
|
|
|
+ Object.entries(this.modules || {}).forEach(([name, module]) => {
|
|
|
status[name] = module.getStatus();
|
|
|
});
|
|
|
-
|
|
|
return status;
|
|
|
}
|
|
|
|
|
@@ -68,31 +64,29 @@ export default class ModuleManager {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * loadModule - Load and initialize module
|
|
|
*
|
|
|
* @param {string} moduleName Name of the module
|
|
|
* @returns {typeof BaseModule} Module
|
|
|
*/
|
|
|
- private getModule<T extends keyof Modules>(
|
|
|
+ private loadModule<T extends keyof Modules>(
|
|
|
moduleName: T
|
|
|
): Promise<Modules[T]> {
|
|
|
return new Promise(resolve => {
|
|
|
const mapper = {
|
|
|
stations: "StationModule",
|
|
|
- others: "OtherModule"
|
|
|
+ others: "OtherModule",
|
|
|
+ data: "DataModule"
|
|
|
};
|
|
|
- import(`./modules/${mapper[moduleName]}`).then(response => {
|
|
|
- const Module: ModuleClass<Modules[T]> = response.default;
|
|
|
- const module = new Module(this);
|
|
|
- resolve(module);
|
|
|
- });
|
|
|
+ import(`./modules/${mapper[moduleName]}`).then(
|
|
|
+ ({ default: Module }: { default: ModuleClass<Modules[T]> }) => {
|
|
|
+ const module = new Module(this);
|
|
|
+ resolve(module);
|
|
|
+ }
|
|
|
+ );
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * loadModules - Load and initialize all modules
|
|
|
- *
|
|
|
- * @returns {Promise} Promise
|
|
|
- */
|
|
|
/**
|
|
|
* loadModules - Load and initialize all modules
|
|
|
*
|
|
@@ -101,8 +95,9 @@ export default class ModuleManager {
|
|
|
private loadModules(): Promise<void> {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const fetchModules = async () => ({
|
|
|
- stations: await this.getModule("stations"),
|
|
|
- others: await this.getModule("others")
|
|
|
+ data: await this.loadModule("data"),
|
|
|
+ others: await this.loadModule("others"),
|
|
|
+ stations: await this.loadModule("stations")
|
|
|
});
|
|
|
fetchModules()
|
|
|
.then(modules => {
|
|
@@ -121,20 +116,60 @@ export default class ModuleManager {
|
|
|
public startup(): void {
|
|
|
this.loadModules()
|
|
|
.then(() => {
|
|
|
- if (!this.modules) return;
|
|
|
- Object.values(this.modules).forEach(module => module.startup());
|
|
|
- this.jobQueue.resume();
|
|
|
+ if (!this.modules) throw new Error("No modules were loaded");
|
|
|
+ async.each(
|
|
|
+ Object.values(this.modules),
|
|
|
+ (module, next) => {
|
|
|
+ module
|
|
|
+ .startup()
|
|
|
+ .then(() => next())
|
|
|
+ .catch(err => {
|
|
|
+ module.setStatus("ERROR");
|
|
|
+ next(err);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async err => {
|
|
|
+ if (err) {
|
|
|
+ await this.shutdown();
|
|
|
+ throw err;
|
|
|
+ }
|
|
|
+ this.jobQueue.resume();
|
|
|
+ }
|
|
|
+ );
|
|
|
})
|
|
|
- .catch(() => this.shutdown());
|
|
|
+ .catch(async err => {
|
|
|
+ await this.shutdown();
|
|
|
+ throw err;
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* shutdown - Handle shutdown
|
|
|
*/
|
|
|
- public shutdown(): void {
|
|
|
- if (!this.modules) return;
|
|
|
- console.log(this.modules);
|
|
|
- Object.values(this.modules).forEach(module => module.shutdown());
|
|
|
+ public shutdown(): Promise<void> {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // TODO: await jobQueue completion/handle shutdown
|
|
|
+ if (this.modules)
|
|
|
+ async.each(
|
|
|
+ Object.values(this.modules),
|
|
|
+ (module, next) => {
|
|
|
+ if (
|
|
|
+ module.getStatus() === "STARTED" ||
|
|
|
+ module.getStatus() === "STARTING" || // TODO: Handle better
|
|
|
+ module.getStatus() === "ERROR"
|
|
|
+ )
|
|
|
+ module
|
|
|
+ .shutdown()
|
|
|
+ .then(() => next())
|
|
|
+ .catch(next);
|
|
|
+ },
|
|
|
+ err => {
|
|
|
+ if (err) reject(err);
|
|
|
+ else resolve();
|
|
|
+ }
|
|
|
+ );
|
|
|
+ else resolve();
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -163,8 +198,7 @@ export default class ModuleManager {
|
|
|
): Promise<ReturnType> {
|
|
|
const [payload, options] = params;
|
|
|
return new Promise<ReturnType>((resolve, reject) => {
|
|
|
- if (!this.modules) return;
|
|
|
- const module = this.modules[moduleName];
|
|
|
+ const module = this.modules && this.modules[moduleName];
|
|
|
if (!module) reject(new Error("Module not found."));
|
|
|
else {
|
|
|
const jobFunction = module[jobName];
|