miter
Version:
A typescript web framework based on ExpressJs based loosely on SailsJs
287 lines • 12.5 kB
JavaScript
"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