UNPKG

miter

Version:

A typescript web framework based on ExpressJs based loosely on SailsJs

287 lines 12.5 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const createExpressApp = require("express"); const bodyParser = require("body-parser"); const injector_1 = require("../core/injector"); const injectable_decorator_1 = require("../decorators/services/injectable.decorator"); const server_1 = require("../metadata/server/server"); const router_1 = require("../metadata/server/router"); const views_1 = require("../metadata/server/views"); const orm_1 = require("../metadata/server/orm"); const ssl_1 = require("../metadata/server/ssl"); const database_1 = require("../metadata/server/database"); const reflector_1 = require("../orm/reflector"); const reflector_2 = require("../services/reflector"); const logger_core_1 = require("../services/logger-core"); const template_service_1 = require("../services/template.service"); const reflector_3 = require("../router/reflector"); const wrap_promise_1 = require("../util/wrap-promise"); const get_miter_version_1 = require("../util/get-miter-version"); const static_middleware_1 = require("./static-middleware"); const http = require("http"); const https = require("https"); const debug_module = require("debug"); let debug = debug_module('express:server'); let Server = Server_1 = class Server { constructor(_origMeta) { this._origMeta = _origMeta; this.startTime = null; this.errorCode = 0; this._loggerCore = new logger_core_1.LoggerCore(_origMeta.name || null, _origMeta.logLevel); this._injector = new injector_1.Injector(this._loggerCore); this._injector.provide({ provide: Server_1, useValue: this }); this._injector.provideMetadata('server-meta', _origMeta); let meta; meta = this._injector.resolveInjectable(server_1.ServerMetadata); for (let q = 0; q < meta.inject.length; q++) { this._injector.provide(meta.inject[q]); } } get originalMeta() { return this._origMeta; } get logger() { return this._loggerCore.getSubsystem('miter'); } get app() { return this._app; } get injector() { return this._injector; } init() { this.initPromise = this.initImpl(); process.on('SIGINT', this.onSIGINT.bind(this)); return this.initPromise; } initImpl() { return __awaiter(this, void 0, void 0, function* () { this.startTime = new Date(); try { this.logger.info(`Initializing miter server. (Miter version ${get_miter_version_1.getMiterVersion()})`); let routerMeta = this.injector.resolveInjectable(router_1.RouterMetadata); if (routerMeta) yield this.createExpressApp(); yield this.reflectOrm(); yield this.startServices(); if (routerMeta) { this.reflectRoutes(); yield this.listen(); } } catch (e) { this.logger.error(`FATAL ERROR: Failed to launch server.`); this.logger.error(e); return; } }); } onSIGINT() { return __awaiter(this, void 0, void 0, function* () { this.logger.error(`Received SIGINT kill signal...`); try { yield this.initPromise; yield this.shutdown(); } finally { process.exit(this.errorCode); } }); } shutdown() { return __awaiter(this, void 0, void 0, function* () { let shutdownSuccessful = true; try { try { this.logger.info(`Shutting down miter server...`); let routerMeta = this.injector.resolveInjectable(router_1.RouterMetadata); if (routerMeta) yield this.stopListening(); yield this.stopServices(); } finally { this._loggerCore.shutdown(); } } catch (e) { this.logger.error(`FATAL ERROR: Failed to gracefully shutdown server.`); this.logger.error(e); shutdownSuccessful = false; } if (shutdownSuccessful) this.logger.info(`Miter server shut down successfully.`); }); } createExpressApp() { this._app = createExpressApp(); this._app.use(bodyParser.urlencoded({ extended: true }), bodyParser.json()); let meta = this.injector.resolveInjectable(server_1.ServerMetadata); let routerMeta = this.injector.resolveInjectable(router_1.RouterMetadata); let viewsMeta = this.injector.resolveInjectable(views_1.ViewsMetadata); if (meta.allowCrossOrigin) { this.logger.warn(`Server starting with cross-origin policy enabled. This should not be enabled in production.`); this._app.use(function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers")); next(); }); } this._app.use(static_middleware_1.monkeypatchResponseSendFile); if (routerMeta && routerMeta.middleware && routerMeta.middleware.length) { this._app.use(...routerMeta.middleware); } if (viewsMeta) { if (viewsMeta.fileRoot) this._app.set('views', viewsMeta.fileRoot); if (typeof viewsMeta.engine === 'string') this._app.set('view engine', viewsMeta.engine); else if (viewsMeta.engine) { this.injector.provide({ provide: template_service_1.TemplateService, useClass: viewsMeta.engine }); this._app.use(static_middleware_1.monkeypatchResponseRender(this.injector, this._app)); } } } reflectOrm() { return __awaiter(this, void 0, void 0, function* () { let ormMeta = this.injector.resolveInjectable(orm_1.OrmMetadata); let dbMeta = this.injector.resolveInjectable(database_1.DatabaseMetadata); if (ormMeta && (typeof ormMeta.enabled === 'undefined' || ormMeta.enabled) && dbMeta) { this.ormReflector = this._injector.resolveInjectable(reflector_1.OrmReflector); yield this.ormReflector.init(); } else if (ormMeta.models.length) { this.logger.warn(`Models included in server metadata, but no orm configuration defined.`); } }); } startServices() { return __awaiter(this, void 0, void 0, function* () { this.serviceReflector = this._injector.resolveInjectable(reflector_2.ServiceReflector); yield this.serviceReflector.startServices(); }); } listenServices() { return __awaiter(this, void 0, void 0, function* () { if (!this.webServer) throw new Error(`onListening called, but there is no httpServer!`); yield this.serviceReflector.listenServices(this.webServer); }); } stopServices() { return __awaiter(this, void 0, void 0, function* () { yield this.serviceReflector.shutdownServices(); }); } reflectRoutes() { this.routerReflector = this._injector.resolveInjectable(reflector_3.RouterReflector); this.routerReflector.reflectServerRoutes(this.app); } listen() { this.logger.info(`Serving`); let meta = this.injector.resolveInjectable(server_1.ServerMetadata); let sslMeta = this.injector.resolveInjectable(ssl_1.SSLMetadata); return new Promise((resolve, reject) => { let isResolved = false; try { if (sslMeta.enabled) { this.webServer = https.createServer({ key: sslMeta.privateKey, cert: sslMeta.certificate }, this.app); } else { this.webServer = http.createServer(this.app); } this.webServer.listen(meta.port, () => __awaiter(this, void 0, void 0, function* () { if (isResolved) return; isResolved = true; yield this.onListening(); resolve(); })); this.webServer.on("error", (err) => __awaiter(this, void 0, void 0, function* () { yield this.onError(err); if (!isResolved) { isResolved = true; reject(err); } })); } catch (e) { if (isResolved) throw e; isResolved = true; reject(e); } }); } stopListening() { return __awaiter(this, void 0, void 0, function* () { this.logger.verbose(`Closing HTTP server...`); yield wrap_promise_1.wrapPromise((cb) => { if (!this.webServer) return cb(); this.webServer.close(cb); }); this.logger.info(`Finished closing HTTP server.`); }); } onError(error) { return __awaiter(this, void 0, void 0, function* () { if (error.syscall !== "listen") { throw error; } let meta = this.injector.resolveInjectable(server_1.ServerMetadata); let bind = (typeof meta.port === "string") ? `pipe ${meta.port}` : `port ${meta.port}`; switch (error.code) { case "EACCES": this.logger.error(`${bind} requires elevated privileges`); break; case "EADDRINUSE": this.logger.error(`${bind} is already in use`); break; default: this.logger.error(`An unknown error occurred in the http server.`); this.logger.error(error); } this.errorCode = 1; this.webServer = undefined; yield this.shutdown(); throw error; }); } onListening() { return __awaiter(this, void 0, void 0, function* () { if (!this.webServer) throw new Error(`onListening called, but there is no httpServer!`); let addr = this.webServer.address(); let bind = (typeof addr === "string") ? `pipe ${addr}` : `port ${addr.port}`; this.logger.info(`Listening on ${bind}`); yield this.listenServices(); }); } }; Server = Server_1 = __decorate([ injectable_decorator_1.Injectable(), __metadata("design:paramtypes", [Object]) ], Server); exports.Server = Server; var Server_1; //# sourceMappingURL=server.js.map