2020-04-22 15:52:17 +02:00
|
|
|
import {Express, Router} from "express";
|
2021-01-22 15:54:26 +01:00
|
|
|
import {logger} from "./Logger";
|
2020-09-25 23:42:15 +02:00
|
|
|
import {sleep} from "./Utils";
|
2020-04-25 09:34:02 +02:00
|
|
|
import Application from "./Application";
|
2020-07-15 15:06:13 +02:00
|
|
|
import config from "config";
|
|
|
|
import SecurityError from "./SecurityError";
|
2020-09-25 23:42:15 +02:00
|
|
|
import Middleware, {MiddlewareType} from "./Middleware";
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
export default abstract class ApplicationComponent {
|
|
|
|
private currentRouter?: Router;
|
|
|
|
private app?: Application;
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
public async checkSecuritySettings?(): Promise<void>;
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
public async start?(expressApp: Express): Promise<void>;
|
2020-07-11 11:46:16 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
public async init?(router: Router): Promise<void>;
|
2020-07-11 11:46:16 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
public async handle?(router: Router): Promise<void>;
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
public async stop?(): Promise<void>;
|
2020-04-25 09:34:02 +02:00
|
|
|
|
2020-04-22 15:52:17 +02:00
|
|
|
protected async prepare(name: string, prepare: () => Promise<void>): Promise<void> {
|
|
|
|
let err;
|
|
|
|
do {
|
|
|
|
try {
|
|
|
|
await prepare();
|
|
|
|
err = null;
|
|
|
|
} catch (e) {
|
|
|
|
err = e;
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.error(err, `${name} failed to prepare; retrying in 5s...`);
|
2020-04-22 15:52:17 +02:00
|
|
|
await sleep(5000);
|
|
|
|
}
|
|
|
|
} while (err);
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.info(`${name} ready!`);
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
protected async close(thingName: string, fn: (callback: (err?: Error | null) => void) => void): Promise<void> {
|
2020-04-22 15:52:17 +02:00
|
|
|
try {
|
2020-12-04 14:42:09 +01:00
|
|
|
await new Promise<void>((resolve, reject) => fn((err?: Error | null) => {
|
2020-04-22 15:52:17 +02:00
|
|
|
if (err) reject(err);
|
|
|
|
else resolve();
|
|
|
|
}));
|
|
|
|
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.info(`${thingName} closed.`);
|
2020-04-22 15:52:17 +02:00
|
|
|
} catch (e) {
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.error(e, `An error occurred while closing the ${thingName}.`);
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
}
|
2020-07-15 15:06:13 +02:00
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
protected checkSecurityConfigField(field: string): void {
|
2020-07-15 15:06:13 +02:00
|
|
|
if (!config.has(field) || config.get<string>(field) === 'default') {
|
2020-07-29 16:16:42 +02:00
|
|
|
throw new SecurityError(`${field} field not configured.`);
|
2020-07-15 15:06:13 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-25 22:03:22 +02:00
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
protected use<M extends Middleware>(middleware: MiddlewareType<M>): void {
|
2020-09-25 22:03:22 +02:00
|
|
|
if (!this.currentRouter) throw new Error('Cannot call this method outside init() and handle().');
|
|
|
|
|
|
|
|
const instance = new middleware(this.getApp());
|
|
|
|
this.currentRouter.use(async (req, res, next) => {
|
|
|
|
try {
|
|
|
|
await instance.getRequestHandler()(req, res, next);
|
|
|
|
} catch (e) {
|
|
|
|
next(e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public setCurrentRouter(router: Router | null): void {
|
|
|
|
this.currentRouter = router || undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected getApp(): Application {
|
|
|
|
if (!this.app) throw new Error('app field not initialized.');
|
|
|
|
return this.app;
|
|
|
|
}
|
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
public setApp(app: Application): void {
|
2020-09-25 22:03:22 +02:00
|
|
|
this.app = app;
|
|
|
|
}
|
2020-07-15 15:06:13 +02:00
|
|
|
}
|