swaf/dist/Application.js

140 lines
18 KiB
JavaScript

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import express from 'express';
import { BadRequestError, HttpError, NotFoundHttpError, ServerError, ServiceUnavailableHttpError } from "./HttpError";
import { lib } from "nunjucks";
import Logger from "./Logger";
import WebSocketListener from "./WebSocketListener";
var TemplateError = lib.TemplateError;
import Controller from "./Controller";
export default class Application {
constructor(version) {
this.controllers = [];
this.webSocketListeners = {};
this.components = [];
this.ready = false;
this.version = version;
}
use(thing) {
if (thing instanceof Controller) {
this.controllers.push(thing);
}
else if (thing instanceof WebSocketListener) {
const path = thing.path();
this.webSocketListeners[path] = thing;
Logger.info(`Added websocket listener on ${path}`);
}
else {
this.components.push(thing);
}
}
start() {
return __awaiter(this, void 0, void 0, function* () {
Logger.info(`${this.constructor.name} v${this.version} - hi`);
process.once('SIGINT', () => {
this.stop().catch(console.error);
});
// Register all components and alike
yield this.init();
// Init express
const app = express();
const router = express.Router({});
app.use(router);
// Error handler
app.use((err, req, res, next) => {
if (res.headersSent) {
return next(err);
}
let errorID;
let logStr = `${req.method} ${req.originalUrl} - `;
if (err instanceof BadRequestError || err instanceof ServiceUnavailableHttpError) {
logStr += `${err.errorCode} ${err.name}`;
errorID = Logger.silentError(err, logStr);
}
else {
errorID = Logger.error(err, logStr + `500 Internal Error`, err);
}
let httpError;
if (err instanceof HttpError) {
httpError = err;
}
else if (err instanceof TemplateError && err.cause instanceof HttpError) {
httpError = err.cause;
}
else {
httpError = new ServerError('Internal server error.', err);
}
res.status(httpError.errorCode);
res.format({
html: () => {
res.render('errors/' + httpError.errorCode + '.njk', {
error_code: httpError.errorCode,
error_message: httpError.message,
error_instructions: httpError.instructions,
error_id: errorID,
});
},
json: () => {
res.json({
status: 'error',
code: httpError.errorCode,
message: httpError.message,
instructions: httpError.instructions,
error_id: errorID,
});
},
default: () => {
res.type('txt').send(`${httpError.errorCode} - ${httpError.message}\n\n${httpError.instructions}\n\nError ID: ${errorID}`);
}
});
});
// Start all components
for (const component of this.components) {
yield component.start(app, router);
}
// Routes
this.routes(router);
this.ready = true;
});
}
stop() {
return __awaiter(this, void 0, void 0, function* () {
Logger.info('Stopping application...');
for (const component of this.components) {
yield component.stop();
}
Logger.info(`${this.constructor.name} v${this.version} - bye`);
});
}
routes(rootRouter) {
for (const controller of this.controllers) {
if (controller.hasGlobalHandlers()) {
controller.setupGlobalHandlers(rootRouter);
Logger.info(`Registered global middlewares for controller ${controller.constructor.name}`);
}
}
for (const controller of this.controllers) {
const router = express.Router();
controller.setupRoutes(router);
rootRouter.use(controller.getRoutesPrefix(), router);
Logger.info(`> Registered routes for controller ${controller.constructor.name}`);
}
rootRouter.use((req) => {
throw new NotFoundHttpError('page', req.originalUrl);
});
}
getWebSocketListeners() {
return this.webSocketListeners;
}
isReady() {
return this.ready;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQXBwbGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbIkFwcGxpY2F0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sT0FBa0QsTUFBTSxTQUFTLENBQUM7QUFDekUsT0FBTyxFQUNILGVBQWUsRUFDZixTQUFTLEVBQ1QsaUJBQWlCLEVBQ2pCLFdBQVcsRUFDWCwyQkFBMkIsRUFDOUIsTUFBTSxhQUFhLENBQUM7QUFDckIsT0FBTyxFQUFDLEdBQUcsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUM3QixPQUFPLE1BQU0sTUFBTSxVQUFVLENBQUM7QUFDOUIsT0FBTyxpQkFBaUIsTUFBTSxxQkFBcUIsQ0FBQztBQUVwRCxJQUFPLGFBQWEsR0FBRyxHQUFHLENBQUMsYUFBYSxDQUFDO0FBQ3pDLE9BQU8sVUFBVSxNQUFNLGNBQWMsQ0FBQztBQUV0QyxNQUFNLENBQUMsT0FBTyxPQUFnQixXQUFXO0lBUXJDLFlBQXNCLE9BQWU7UUFOcEIsZ0JBQVcsR0FBaUIsRUFBRSxDQUFDO1FBQy9CLHVCQUFrQixHQUF1QyxFQUFFLENBQUM7UUFDNUQsZUFBVSxHQUFnQyxFQUFFLENBQUM7UUFFdEQsVUFBSyxHQUFZLEtBQUssQ0FBQztRQUczQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztJQUMzQixDQUFDO0lBSVMsR0FBRyxDQUFDLEtBQWlFO1FBQzNFLElBQUksS0FBSyxZQUFZLFVBQVUsRUFBRTtZQUM3QixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUNoQzthQUFNLElBQUksS0FBSyxZQUFZLGlCQUFpQixFQUFFO1lBQzNDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUMxQixJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDO1lBQ3RDLE1BQU0sQ0FBQyxJQUFJLENBQUMsK0JBQStCLElBQUksRUFB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QUFNLENBQUMsSUFBSSxDQUFDLGdEQUFnRCxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7YUFDOUY7U0FDSjtRQUVELEtBQUssTUFBTSxVQUFVLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUN2QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUMvQixVQUFVLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxlQUFlLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUVyRCxNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7U0FDcEY7UUFFRCxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBWSxFQUFFLEVBQUU7WUFDNUIsTUFBTSxJQUFJLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDekQsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRU0scUJBQXFCO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ25DLENBQUM7SUFFTSxPQUFPO1FBQ1YsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3RCLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBleHByZXNzLCB7TmV4dEZ1bmN0aW9uLCBSZXF1ZXN0LCBSZXNwb25zZSwgUm91dGVyfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7XG4gICAgQmFkUmVxdWVzdEVycm9yLFxuICAgIEh0dHBFcnJvcixcbiAgICBOb3RGb3VuZEh0dHBFcnJvcixcbiAgICBTZXJ2ZXJFcnJvcixcbiAgICBTZXJ2aWNlVW5hdmFpbGFibGVIdHRwRXJyb3Jcbn0gZnJvbSBcIi4vSHR0cEVycm9yXCI7XG5pbXBvcnQge2xpYn0gZnJvbSBcIm51bmp1Y2tzXCI7XG5pbXBvcnQgTG9nZ2VyIGZyb20gXCIuL0xvZ2dlclwiO1xuaW1wb3J0IFdlYlNvY2tldExpc3RlbmVyIGZyb20gXCIuL1dlYlNvY2tldExpc3RlbmVyXCI7XG5pbXBvcnQgQXBwbGljYXRpb25Db21wb25lbnQgZnJvbSBcIi4vQXBwbGljYXRpb25Db21wb25lbnRcIjtcbmltcG9ydCBUZW1wbGF0ZUVycm9yID0gbGliLlRlbXBsYXRlRXJyb3I7XG5pbXBvcnQgQ29udHJvbGxlciBmcm9tIFwiLi9Db250cm9sbGVyXCI7XG5cbmV4cG9ydCBkZWZhdWx0IGFic3RyYWN0IGNsYXNzIEFwcGxpY2F0aW9uIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHZlcnNpb246IHN0cmluZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbnRyb2xsZXJzOiBDb250cm9sbGVyW10gPSBbXTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHdlYlNvY2tldExpc3RlbmVyczogeyBbcDogc3RyaW5nXTogV2ViU29ja2V0TGlzdGVuZXIgfSA9IHt9O1xuICAgIHByaXZhdGUgcmVhZG9ubHkgY29tcG9uZW50czogQXBwbGljYXRpb25Db21wb25lbnQ8YW55PltdID0gW107XG5cbiAgICBwcml2YXRlIHJlYWR5OiBib29sZWFuID0gZmFsc2U7XG5cbiAgICBwcm90ZWN0ZWQgY29uc3RydWN0b3IodmVyc2lvbjogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMudmVyc2lvbiA9IHZlcnNpb247XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGFic3RyYWN0IGFzeW5jIGluaXQoKTogUHJvbWlzZTx2b2lkPjtcblxuICAgIHByb3RlY3RlZCB1c2UodGhpbmc6IENvbnRyb2xsZXIgfCBXZWJTb2NrZXRMaXN0ZW5lciB8IEFwcGxpY2F0aW9uQ29tcG9uZW50PGFueT4pIHtcbiAgICAgICAgaWYgKHRoaW5nIGluc3RhbmNlb2YgQ29udHJvbGxlcikge1xuICAgICAgICAgICAgdGhpcy5jb250cm9sbGVycy5wdXNoKHRoaW5nKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGluZyBpbnN0YW5jZW9mIFdlYlNvY2tldExpc3RlbmVyKSB7XG4gICAgICAgICAgICBjb25zdCBwYXRoID0gdGhpbmcucGF0aCgpO1xuICAgICAgICAgICAgdGhpcy53ZWJTb2NrZXRMaXN0ZW5lcnNbcGF0aF0gPSB0aGluZztcbiAgICAgICAgICAgIExvZ2dlci5pbmZvKGBBZGRlZCB3ZWJzb2NrZXQgbGlzdGVuZXIgb24gJHtwYXRofWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jb21wb25lbnRzLnB1c2godGhpbmcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBMb2dnZXIuaW5mbyhgJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9IHYke3RoaXMudmVyc2lvbn0gLSBoaWApO1xuICAgICAgICBwcm9jZXNzLm9uY2UoJ1NJR0lOVCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuc3RvcCgpLmNhdGNoKGNvbnNvbGUuZXJyb3IpO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBSZWdpc3RlciBhbGwgY29tcG9uZW50cyBhbmQgYWxpa2VcbiAgICAgICAgYXdhaXQgdGhpcy5pbml0KCk7XG5cbiAgICAgICAgLy8gSW5pdCBleHByZXNzXG4gICAgICAgIGNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcbiAgICAgICAgY29uc3Qgcm91dGVyID0gZXhwcmVzcy5Sb3V0ZXIoe30pO1xuICAgICAgICBhcHAudXNlKHJvdXRlcik7XG5cbiAgICAgICAgLy8gRXJyb3IgaGFuZGxlclxuICAgICAgICBhcHAudXNlKChlcnI6IGFueSwgcmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pID0+IHtcbiAgICAgICAgICAgIGlmIChyZXMuaGVhZGVyc1NlbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV4dChlcnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgZXJyb3JJRDogc3RyaW5nO1xuXG4gICAgICAgICAgICBsZXQgbG9nU3RyID0gYCR7cmVxLm1ldGhvZH0gJHtyZXEub3JpZ2luYWxVcmx9IC0gYDtcbiAgICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBCYWRSZXF1ZXN0RXJyb3IgfHwgZXJyIGluc3RhbmNlb2YgU2VydmljZVVuYXZhaWxhYmxlSHR0cEVycm9yKSB7XG4gICAgICAgICAgICAgICAgbG9nU3RyICs9IGAke2Vyci5lcnJvckNvZGV9ICR7ZXJyLm5hbWV9YDtcbiAgICAgICAgICAgICAgICBlcnJvcklEID0gTG9nZ2VyLnNpbGVudEVycm9yKGVyciwgbG9nU3RyKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXJyb3JJRCA9IExvZ2dlci5lcnJvcihlcnIsIGxvZ1N0ciArIGA1MDAgSW50ZXJuYWwgRXJyb3JgLCBlcnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgaHR0cEVycm9yOiBIdHRwRXJyb3I7XG5cbiAgICAgICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBIdHRwRXJyb3IpIHtcbiAgICAgICAgICAgICAgICBodHRwRXJyb3IgPSBlcnI7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGVyciBpbnN0YW5jZW9mIFRlbXBsYXRlRXJyb3IgJiYgZXJyLmNhdXNlIGluc3RhbmNlb2YgSHR0cEVycm9yKSB7XG4gICAgICAgICAgICAgICAgaHR0cEVycm9yID0gZXJyLmNhdXNlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBodHRwRXJyb3IgPSBuZXcgU2VydmVyRXJyb3IoJ0ludGVybmFsIHNlcnZlciBlcnJvci4nLCBlcnIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXMuc3RhdHVzKGh0dHBFcnJvci5lcnJvckNvZGUpO1xuICAgICAgICAgICAgcmVzLmZvcm1hdCh7XG4gICAgICAgICAgICAgICAgaHRtbDogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXMucmVuZGVyKCdlcnJvcnMvJyArIGh0dHBFcnJvci5lcnJvckNvZGUgKyAnLm5qaycsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2NvZGU6IGh0dHBFcnJvci5lcnJvckNvZGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvcl9tZXNzYWdlOiBodHRwRXJyb3IubWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2luc3RydWN0aW9uczogaHR0cEVycm9yLmluc3RydWN0aW9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yX2lkOiBlcnJvcklELFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGpzb246ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgcmVzLmpzb24oe1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHVzOiAnZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29kZTogaHR0cEVycm9yLmVycm9yQ29kZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGh0dHBFcnJvci5tZXNzYWdlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW5zdHJ1Y3Rpb25zOiBodHRwRXJyb3IuaW5zdHJ1Y3Rpb25zLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3JfaWQ6IGVycm9ySUQsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZXMudHlwZSgndHh0Jykuc2VuZChgJHtodHRwRXJyb3IuZXJyb3JDb2RlfSAtICR7aHR0cEVycm9yLm1lc3NhZ2V9XFxuXFxuJHtodHRwRXJyb3IuaW5zdHJ1Y3Rpb25zfVxcblxcbkVycm9yIElEOiAke2Vycm9ySUR9YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFN0YXJ0IGFsbCBjb21wb25lbnRzXG4gICAgICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICAgICAgYXdhaXQgY29tcG9uZW50LnN0YXJ0KGFwcCwgcm91dGVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFJvdXRlc1xuICAgICAgICB0aGlzLnJvdXRlcyhyb3V0ZXIpO1xuXG4gICAgICAgIHRoaXMucmVhZHkgPSB0cnVlO1xuICAgIH1cblxuICAgIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIExvZ2dlci5pbmZvKCdTdG9wcGluZyBhcHBsaWNhdGlvbi4uLicpO1xuXG4gICAgICAgIGZvciAoY29uc3QgY29tcG9uZW50IG9mIHRoaXMuY29tcG9uZW50cykge1xuICAgICAgICAgICAgYXdhaXQgY29tcG9uZW50LnN0b3AoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIExvZ2dlci5pbmZvKGAke3RoaXMuY29uc3RydWN0b3IubmFtZX0gdiR7dGhpcy52ZXJzaW9ufSAtIGJ5ZWApO1xuICAgIH1cblxuICAgIHByaXZhdGUgcm91dGVzKHJvb3RSb3V0ZXI6IFJvdXRlcikge1xuICAgICAgICBmb3IgKGNvbnN0IGNvbnRyb2xsZXIgb2YgdGhpcy5jb250cm9sbGVycykge1xuICAgICAgICAgICAgaWYgKGNvbnRyb2xsZXIuaGFzR2xvYmFsSGFuZGxlcnMoKSkge1xuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXIuc2V0dXBHbG9iYWxIYW5kbGVycyhyb290Um91dGVyKTtcblxuICAgICAgICAgICAgICAgIExvZ2dlci5pbmZvKGBSZWdpc3RlcmVkIGdsb2JhbCBtaWRkbGV3YXJlcyBmb3IgY29udHJvbGxlciAke2NvbnRyb2xsZXIuY29uc3RydWN0b3IubmFtZX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZvciAoY29uc3QgY29udHJvbGxlciBvZiB0aGlzLmNvbnRyb2xsZXJzKSB7XG4gICAgICAgICAgICBjb25zdCByb3V0ZXIgPSBleHByZXNzLlJvdXRlcigpO1xuICAgICAgICAgICAgY29udHJvbGxlci5zZXR1cFJvdXRlcyhyb3V0ZXIpO1xuICAgICAgICAgICAgcm9vdFJvdXRlci51c2UoY29udHJvbGxlci5nZXRSb3V0ZXNQcmVmaXgoKSwgcm91dGVyKTtcblxuICAgICAgICAgICAgTG9nZ2VyLmluZm8oYD4gUmVnaXN0ZXJlZCByb3V0ZXMgZm9yIGNvbnRyb2xsZXIgJHtjb250cm9sbGVyLmNvbnN0cnVjdG9yLm5hbWV9YCk7XG4gICAgICAgIH1cblxuICAgICAgICByb290Um91dGVyLnVzZSgocmVxOiBSZXF1ZXN0KSA9PiB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgTm90Rm91bmRIdHRwRXJyb3IoJ3BhZ2UnLCByZXEub3JpZ2luYWxVcmwpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0V2ViU29ja2V0TGlzdGVuZXJzKCk6IHsgW3A6IHN0cmluZ106IFdlYlNvY2tldExpc3RlbmVyIH0ge1xuICAgICAgICByZXR1cm4gdGhpcy53ZWJTb2NrZXRMaXN0ZW5lcnM7XG4gICAgfVxuXG4gICAgcHVibGljIGlzUmVhZHkoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWR5O1xuICAgIH1cbn0iXX0=