UNPKG

@angstone/monostone

Version:

monolitic event-sourced framework

223 lines 7.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ast = require("@angstone/node-util"); const error_1 = require("../error"); const bodyParser = require("body-parser"); const express = require("express"); const http = require("http"); const _1 = require("./"); const tools_1 = require("../tools"); const AuthTools = require("../features/auth/tools"); const messages_1 = require("../features/auth/messages"); const net = require("net"); const state = { apiPort: 0, expressApp: express().use(bodyParser.json()), httpServer: null, }; const config = () => { state.apiPort = +(process.env.API_PORT || 3002); state.expressApp = express().use(bodyParser.json()); state.httpServer = null; }; const loadFeatures = (features) => { ast.log("creating routes"); routeSystem(); routeFeatures(features); }; const routeSystem = () => { ast.log("adding system routes"); const router = express.Router(); router.get("/ping", (req, res) => { res.send("pong"); }); state.expressApp.use("/", router); ast.log("system routes added"); }; /** * Route each feature * @param features loaded features * @param eventReduced$ reduced events stream * @param viewData stored data from views */ const routeFeatures = (features) => { ast.log("adding the feature routes"); features.forEach((feature) => { ast.log("found feature: " + feature.featureName); const featureRouter = express.Router(); featureRouter.use(authMiddleware); if (feature.commands) { feature.commands.forEach((command) => { ast.log(" found command: " + command.commandName); featureRouter.post("/" + command.commandName, commandRequest(command)); ast.log(" routed command " + command.commandName); }); } if (feature.views) { feature.views.forEach((view) => { ast.log(" found view: " + view.viewName); featureRouter.get("/" + view.viewName, viewRequest(view)); ast.log(" routed view " + view.viewName); }); } state.expressApp.use("/" + feature.featureName, featureRouter); ast.log("routed feature " + feature.featureName); }); }; /** * Middleware to handle authentication * @param req the request * @param res the response * @param next called at end */ const authMiddleware = (req, res, next) => { const tokenHeader = req.get("token"); if (tokenHeader) { AuthTools.decodeToken(tokenHeader).then((decoded) => { req.token = decoded; next(); }).catch((err) => { res.status(401).send(err.message || err.msg || "unknown"); }); } else { next(); } }; /** * Generate the request for each command * @param command [description] * @param eventReduced$ stream of reduced events * @return express function midlleware */ const commandRequest = (command) => { return (req, res) => { req.body.token = req.token; tools_1.CommandTools.execute(command, req.body, _1.ReducerModule.getEventReducedStream()) .then((ans) => res.status(200).send(ans)) .catch((err) => { ast.dev(err); res.status(400).send(err); }); }; }; /** * Generate the request for each view * @param view [description] * @param viewTag [description] * @param viewData [description] * @return express function middleware */ const viewRequest = (view) => { if (view.renderPrivate && !view.renderPublic) { return (req, res) => { if (req.token && view.renderPrivate) { view.renderPrivate(_1.ViewModule.getViewData(view), req.token) .then((ans) => res.status(200).send(ans)) .catch((err) => res.status(400).send(err)); } else { res.status(401).send(messages_1.messages.NO_TOKEN_PROVIDED); } }; } else if (view.renderPrivate && view.renderPublic) { return (req, res) => { if (req.token && view.renderPrivate) { view.renderPrivate(_1.ViewModule.getViewData(view), req.token) .then((ans) => res.status(200).send(ans)) .catch((err) => res.status(400).send(err)); } else if (view.renderPublic) { view.renderPublic(_1.ViewModule.getViewData(view)) .then((ans) => res.status(200).send(ans)) .catch((err) => res.status(400).send(err)); } }; } else { if (view.renderPublic) { return (req, res) => { if (view.renderPublic) { view.renderPublic(_1.ViewModule.getViewData(view)) .then((ans) => res.status(200).send(ans)) .catch((err) => res.status(400).send(err)); } }; } else { return (req, res) => res.status(200).send({}); } } }; const start = () => { return new Promise((resolve, reject) => { ast.log("testing http port use"); isPortTaken(state.apiPort).then((isTaken) => { if (isTaken) { reject("The port '" + state.apiPort + "' is already being used!'"); } else { state.httpServer = http.createServer(state.expressApp); state.httpServer.once('listening', () => { ast.log("Express Server listening on port " + state.apiPort); resolve(); }); state.httpServer.on('error', (e) => { error_1.error.fatal(e); reject(); }); state.httpServer.listen.apply(state.httpServer, [{ host: 'localhost', port: state.apiPort, }]); } }).catch((err) => { reject("failure when testing http server api port"); }); }); }; const isPortTaken = (port) => { return new Promise((resolve) => { const tester = net.createServer() .once('error', (err) => { if (err.code == 'EADDRINUSE') resolve(true); else resolve(false); }) .once('listening', () => { tester.once('close', () => resolve(false)) .close(); }) .listen(port); resolve(false); }); }; const stop = () => { return new Promise((resolve, reject) => { if (state.httpServer) { state.httpServer.close((error) => { if (error) reject(error); else { ast.info("http server closed"); resolve(); } }); } else { ast.info("http server never started"); resolve(); } }); }; const getExpressApp = () => state.expressApp; const getApiPort = () => state.apiPort; exports.PortalModule = Object.assign({}, _1.BasicModule, { config, loadFeatures, start, stop, getExpressApp, getApiPort }); //# sourceMappingURL=portal.module.js.map