|
@@ -0,0 +1,182 @@
|
|
|
+import express, {Express} from 'express';
|
|
|
+import Middleware from '../base/http/Middleware';
|
|
|
+import Route from '../base/http/Route';
|
|
|
+import HttpMethod from '../base/http/HttpMethod';
|
|
|
+import RouteNotSetException from '../base/exceptions/RouteNotSetException';
|
|
|
+import IncorrectMethodException from '../base/exceptions/IncorrectMethodException';
|
|
|
+import Message from '../base/logger/Message';
|
|
|
+import MessageTypes from '../base/logger/MessageTypes';
|
|
|
+import Logger from '../base/logger/Logger';
|
|
|
+import ServerProperties from './ServerProperties';
|
|
|
+import {i18nLoader, $$} from '../base/i18n/i18n';
|
|
|
+import path from 'path';
|
|
|
+import fs from 'fs';
|
|
|
+import HttpHandler from '../base/http/HttpHandler';
|
|
|
+import InvalidMiddlewareException from '../base/exceptions/InvalidMiddlewareException';
|
|
|
+import InvalidRouteException from '../base/exceptions/InvalidRouteException';
|
|
|
+import ServerNotInitializedException from '../base/exceptions/ServerNotInitializedException';
|
|
|
+
|
|
|
+/** @sealed */
|
|
|
+class Server {
|
|
|
+ private instance: Express;
|
|
|
+ private readonly port: number;
|
|
|
+ private readonly logger: Logger;
|
|
|
+ private i18n: i18nLoader;
|
|
|
+ public static readonly i18nDefaultPath = '../resources/i18n.json';
|
|
|
+ public static readonly defaultMiddlewaresPath = '../middlewares';
|
|
|
+ public static readonly defaultRoutesPath = '../routes';
|
|
|
+ private readonly httpHandlers: {[key: string]: HttpHandler};
|
|
|
+ private initialized: boolean;
|
|
|
+
|
|
|
+ private readonly i18nPath?: string;
|
|
|
+ private readonly middlewaresPath?: string;
|
|
|
+ private readonly routesPath?: string;
|
|
|
+
|
|
|
+ public constructor(properties: ServerProperties) {
|
|
|
+ this.instance = express();
|
|
|
+ this.port = properties.port;
|
|
|
+ this.i18n = i18nLoader.getInstance().setLocale(properties.locale);
|
|
|
+ this.logger = new Logger();
|
|
|
+ this.httpHandlers = {};
|
|
|
+ this.i18nPath = properties.i18nPath;
|
|
|
+ this.middlewaresPath = properties.middlewaresPath;
|
|
|
+ this.routesPath = properties.routesPath;
|
|
|
+ this.initialized = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async init(): Promise<Server> {
|
|
|
+ this.i18n.load(path.resolve(__dirname, Server.i18nDefaultPath));
|
|
|
+ await this.registerMiddlewares(path.resolve(__dirname, Server.defaultMiddlewaresPath));
|
|
|
+ await this.registerRoutes(path.resolve(__dirname, Server.defaultRoutesPath));
|
|
|
+ await this.postInit();
|
|
|
+ this.initialized = true;
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ private async postInit(): Promise<void> {
|
|
|
+ if(this.i18nPath)
|
|
|
+ this.i18n.load(this.i18nPath);
|
|
|
+ if(this.middlewaresPath)
|
|
|
+ await this.registerMiddlewares(this.middlewaresPath);
|
|
|
+ if(this.routesPath)
|
|
|
+ await this.registerRoutes(this.routesPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ private processHttpHandlers(): void {
|
|
|
+ const handlers: HttpHandler[] = [];
|
|
|
+ for(const key in this.httpHandlers)
|
|
|
+ handlers.push(this.httpHandlers[key]);
|
|
|
+ handlers.sort((a, b) => a.getOrder() - b.getOrder());
|
|
|
+
|
|
|
+ for(const handler of handlers) {
|
|
|
+ if(handler instanceof Middleware)
|
|
|
+ this.addMiddleware(handler);
|
|
|
+ else if (handler instanceof Route)
|
|
|
+ this.addRoute(handler);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public addMiddleware(middleware: Middleware): Server {
|
|
|
+ if(middleware.getRoute() != null)
|
|
|
+ this.instance.use(<string>middleware.getRoute(), middleware.getAction());
|
|
|
+ else
|
|
|
+ this.instance.use(middleware.getAction());
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public addRoute(route: Route): Server {
|
|
|
+ if(route.getRoute() == null)
|
|
|
+ throw new RouteNotSetException();
|
|
|
+ switch(route.getMethod()) {
|
|
|
+ case HttpMethod.GET:
|
|
|
+ return this.get(route);
|
|
|
+ case HttpMethod.POST:
|
|
|
+ return this.post(route);
|
|
|
+ default:
|
|
|
+ throw new IncorrectMethodException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public logInfo(message: string): void {
|
|
|
+ this.logger.getLogger().info(message);
|
|
|
+ }
|
|
|
+
|
|
|
+ public logError(message: string): void {
|
|
|
+ this.logger.getLogger().error(message);
|
|
|
+ }
|
|
|
+
|
|
|
+ public logWarn(message: string): void {
|
|
|
+ this.logger.getLogger().warn(message);
|
|
|
+ }
|
|
|
+
|
|
|
+ public log(message: Message): void {
|
|
|
+ switch(message.type) {
|
|
|
+ case MessageTypes.WARNING:
|
|
|
+ return this.logWarn(message.text);
|
|
|
+ case MessageTypes.ERROR:
|
|
|
+ return this.logError(message.text);
|
|
|
+ default:
|
|
|
+ return this.logInfo(message.text);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private get(route: Route): Server {
|
|
|
+ this.instance.get(<string>route.getRoute(), route.getAction());
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ private post(route: Route): Server {
|
|
|
+ this.instance.post(<string>route.getRoute(), route.getAction());
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async registerRoutes(dir: string): Promise<Server> {
|
|
|
+ const files = fs.readdirSync(dir);
|
|
|
+
|
|
|
+ for(const file of files) {
|
|
|
+ if(/\.(ts|js)$/.test(file)) {
|
|
|
+ const {default: RouteClass} = await import(path.join(dir, file));
|
|
|
+ if(RouteClass.prototype instanceof Route) {
|
|
|
+ this.httpHandlers[RouteClass.name] = <HttpHandler>new RouteClass(this);
|
|
|
+ } else throw new InvalidRouteException(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public async registerMiddlewares(dir: string): Promise<Server> {
|
|
|
+ const files = fs.readdirSync(dir);
|
|
|
+
|
|
|
+ for(const file of files) {
|
|
|
+ if(/\.(ts|js)$/.test(file)) {
|
|
|
+ const {default: MiddlewareClass} = await import(path.join(dir, file));
|
|
|
+ if(MiddlewareClass.prototype instanceof Middleware) {
|
|
|
+ this.httpHandlers[MiddlewareClass.name] = <HttpHandler>new MiddlewareClass(this);
|
|
|
+ } else throw new InvalidMiddlewareException(file);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public getLogger(): Logger {
|
|
|
+ return this.logger;
|
|
|
+ }
|
|
|
+
|
|
|
+ public i18nLoad(path: string): Server {
|
|
|
+ this.i18n.load(path);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public start(callback?: () => any): void {
|
|
|
+ if(!this.initialized)
|
|
|
+ throw new ServerNotInitializedException();
|
|
|
+ this.processHttpHandlers();
|
|
|
+ const cb = (): void => {
|
|
|
+ this.logInfo($$('org.crazydoctor.expressts.start', { 'port': this.port }));
|
|
|
+ if(callback) callback();
|
|
|
+ };
|
|
|
+ this.instance.listen(this.port, cb);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default Server;
|