Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli refactor #924

Merged
merged 28 commits into from
Nov 14, 2022
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0b1c27e
main menu for cli
adrianmroz-allegro Oct 27, 2022
ad2ff34
utils for commander
adrianmroz-allegro Nov 3, 2022
37b5372
create server as a function with explicit dependencies
adrianmroz-allegro Nov 3, 2022
daee927
util for loading file, soon will talk to commander
adrianmroz-allegro Nov 3, 2022
6762ded
explicit default value
adrianmroz-allegro Nov 3, 2022
071eb9e
explicit dependencie on timekeeper getter
adrianmroz-allegro Nov 3, 2022
595f97d
we always post process loaded files so enforce that intypes
adrianmroz-allegro Nov 3, 2022
728b892
create express app in function with explicit dependencies
adrianmroz-allegro Nov 3, 2022
e15686e
implement commands
adrianmroz-allegro Nov 3, 2022
42dcf79
be careful to what "this" is bound
adrianmroz-allegro Nov 7, 2022
6bf4d07
use relative path because sources endpoint is placed on server-root d…
adrianmroz-allegro Nov 7, 2022
03aadce
add required option for time attribute for json files
adrianmroz-allegro Nov 7, 2022
5a7ee5b
columns from json files are loaded later so we can't check for time c…
adrianmroz-allegro Nov 7, 2022
d9cb767
add verbose option for config verification
adrianmroz-allegro Nov 7, 2022
8a26004
refactor a little
adrianmroz-allegro Nov 7, 2022
187af65
handle version read failure
adrianmroz-allegro Nov 7, 2022
4624297
pass command to server so we can recover from errors
adrianmroz-allegro Nov 7, 2022
62d3f9d
lint fixes
adrianmroz-allegro Nov 8, 2022
797031e
native data cubes dimensions are loaded after introspection so we can…
adrianmroz-allegro Nov 8, 2022
b53f60c
auth is optional
adrianmroz-allegro Nov 9, 2022
3824804
pass parsed cluster credentials to sources config
adrianmroz-allegro Nov 9, 2022
a5074a1
add "Basic" prefix to encoded credentials header
adrianmroz-allegro Nov 9, 2022
5c06a04
handle errors when loading config file
adrianmroz-allegro Nov 9, 2022
db3f0df
remove config.ts file
adrianmroz-allegro Nov 9, 2022
2086543
remove old comments
adrianmroz-allegro Nov 9, 2022
968c487
"generic" parse credentials
adrianmroz-allegro Nov 14, 2022
317bbc1
remove port from introspection
adrianmroz-allegro Nov 14, 2022
2ad61df
runTurnilo util
adrianmroz-allegro Nov 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
create express app in function with explicit dependencies
adrianmroz-allegro committed Nov 8, 2022
commit 728b892214429900a321f104c9318919ce6ca4d4
215 changes: 109 additions & 106 deletions src/server/app.ts
Original file line number Diff line number Diff line change
@@ -17,13 +17,12 @@

import * as bodyParser from "body-parser";
import compress from "compression";
import express from "express";
import express, { Express } from "express";
import { Handler, Request, Response, Router } from "express";
import { hsts } from "helmet";
import { join } from "path";
import { LOGGER } from "../common/logger/logger";
import { SERVER_SETTINGS, SETTINGS_MANAGER, VERSION } from "./config";
import { PluginSettings } from "./models/plugin-settings/plugin-settings";
import { ServerSettings } from "./models/server-settings/server-settings";
import { livenessRouter } from "./routes/liveness/liveness";
import { mkurlRouter } from "./routes/mkurl/mkurl";
import { plyqlRouter } from "./routes/plyql/plyql";
@@ -33,6 +32,7 @@ import { shortenRouter } from "./routes/shorten/shorten";
import { sourcesRouter } from "./routes/sources/sources";
import { turniloRouter } from "./routes/turnilo/turnilo";
import { loadPlugin } from "./utils/plugin-loader/load-plugin";
import { SettingsManager } from "./utils/settings-manager/settings-manager";
import { errorLayout } from "./views";

declare module "express" {
@@ -41,128 +41,131 @@ declare module "express" {
}
}

let app = express();
app.disable("x-powered-by");
export default function createApp(serverSettings: ServerSettings, settingsManager: SettingsManager, version: string): Express {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is just a refactor, from module scope variable to function that creates this variable with explicit dependencies

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I trust you :) The modifications in app.ts file are not possible to review.


const isDev = app.get("env") === "development";
const isTrustedProxy = SERVER_SETTINGS.trustProxy === "always";
let app = express();
app.disable("x-powered-by");

if (isTrustedProxy) {
app.set("trust proxy", true); // trust X-Forwarded-*, use left-most entry as the client
}

const timeout = SERVER_SETTINGS.serverTimeout;
app.use((req, res, next) => {
res.setTimeout(timeout);
next();
});
const isDev = app.get("env") === "development";
const isTrustedProxy = serverSettings.trustProxy === "always";

function getRoutePath(route: string): string {
const serverRoot = SERVER_SETTINGS.serverRoot;
const prefix = serverRoot.length > 0 ? `/${serverRoot}` : "";
return `${prefix}${route}`;
}
if (isTrustedProxy) {
app.set("trust proxy", true); // trust X-Forwarded-*, use left-most entry as the client
}

function attachRouter(route: string, router: Router | Handler): void {
app.use(getRoutePath(route), router);
}
const timeout = serverSettings.serverTimeout;
app.use((req, res, next) => {
res.setTimeout(timeout);
next();
});

// Add compression
app.use(compress());
function getRoutePath(route: string): string {
const serverRoot = serverSettings.serverRoot;
const prefix = serverRoot.length > 0 ? `/${serverRoot}` : "";
return `${prefix}${route}`;
}

// Add Strict Transport Security
if (SERVER_SETTINGS.strictTransportSecurity === "always") {
app.use(hsts({
maxAge: 10886400000, // Must be at least 18 weeks to be approved by Google
includeSubdomains: true, // Must be enabled to be approved by Google
preload: true
}));
}
function attachRouter(route: string, router: Router | Handler): void {
app.use(getRoutePath(route), router);
}

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Add compression
app.use(compress());

if (SERVER_SETTINGS.iframe === "deny") {
app.use((req: Request, res: Response, next: Function) => {
res.setHeader("X-Frame-Options", "DENY");
res.setHeader("Content-Security-Policy", "frame-ancestors 'none'");
next();
});
}

app.use((req: Request, res: Response, next: Function) => {
req.turniloMetadata = {};
next();
});

SERVER_SETTINGS.plugins.forEach(({ path, name, settings }: PluginSettings) => {
try {
LOGGER.log(`Loading plugin ${name} module`);
const module = loadPlugin(path, SETTINGS_MANAGER.anchorPath);
LOGGER.log(`Invoking plugin ${name}`);
module.plugin(app,
settings,
SERVER_SETTINGS,
SETTINGS_MANAGER.appSettings,
SETTINGS_MANAGER.sourcesGetter,
LOGGER.addPrefix(name));
} catch (e) {
LOGGER.warn(`Plugin ${name} threw an error: ${e.message}`);
// Add Strict Transport Security
if (serverSettings.strictTransportSecurity === "always") {
app.use(hsts({
maxAge: 10886400000, // Must be at least 18 weeks to be approved by Google
includeSubdomains: true, // Must be enabled to be approved by Google
preload: true
}));
}
});

// development HMR
if (app.get("env") === "dev-hmr") {
// add hot module replacement
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

const webpack = require("webpack");
const webpackConfig = require("../../config/webpack.dev");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
if (serverSettings.iframe === "deny") {
app.use((req: Request, res: Response, next: Function) => {
res.setHeader("X-Frame-Options", "DENY");
res.setHeader("Content-Security-Policy", "frame-ancestors 'none'");
next();
});
}

if (webpack && webpackDevMiddleware && webpackHotMiddleware) {
const webpackCompiler = webpack(webpackConfig);
app.use((req: Request, res: Response, next: Function) => {
req.turniloMetadata = {};
next();
});

app.use(webpackDevMiddleware(webpackCompiler, {
hot: true,
noInfo: true,
publicPath: webpackConfig.output.publicPath
}));
serverSettings.plugins.forEach(({ path, name, settings }: PluginSettings) => {
try {
settingsManager.logger.log(`Loading plugin ${name} module`);
const module = loadPlugin(path, settingsManager.anchorPath);
settingsManager.logger.log(`Invoking plugin ${name}`);
module.plugin(app,
settings,
serverSettings,
settingsManager.appSettings,
settingsManager.sourcesGetter,
settingsManager.logger.addPrefix(name));
} catch (e) {
settingsManager.logger.warn(`Plugin ${name} threw an error: ${e.message}`);
}
});

app.use(webpackHotMiddleware(webpackCompiler, {
log: console.log,
path: "/__webpack_hmr"
}));
// development HMR
if (app.get("env") === "dev-hmr") {
// add hot module replacement

const webpack = require("webpack");
const webpackConfig = require("../../config/webpack.dev");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");

if (webpack && webpackDevMiddleware && webpackHotMiddleware) {
const webpackCompiler = webpack(webpackConfig);

app.use(webpackDevMiddleware(webpackCompiler, {
hot: true,
noInfo: true,
publicPath: webpackConfig.output.publicPath
}));

app.use(webpackHotMiddleware(webpackCompiler, {
log: console.log,
path: "/__webpack_hmr"
}));
}
}
}

attachRouter("/", express.static(join(__dirname, "../../build/public")));
attachRouter("/", express.static(join(__dirname, "../../assets")));
attachRouter("/", express.static(join(__dirname, "../../build/public")));
attachRouter("/", express.static(join(__dirname, "../../assets")));

attachRouter(SERVER_SETTINGS.readinessEndpoint, readinessRouter(SETTINGS_MANAGER.sourcesGetter));
attachRouter(SERVER_SETTINGS.livenessEndpoint, livenessRouter);
attachRouter(serverSettings.readinessEndpoint, readinessRouter(settingsManager.sourcesGetter));
attachRouter(serverSettings.livenessEndpoint, livenessRouter);

// Data routes
attachRouter("/sources", sourcesRouter(SETTINGS_MANAGER.sourcesGetter));
attachRouter("/plywood", plywoodRouter(SETTINGS_MANAGER));
attachRouter("/plyql", plyqlRouter(SETTINGS_MANAGER.sourcesGetter));
attachRouter("/mkurl", mkurlRouter(SETTINGS_MANAGER.sourcesGetter));
attachRouter("/shorten", shortenRouter(SETTINGS_MANAGER.appSettings, isTrustedProxy));
// Data routes
attachRouter("/sources", sourcesRouter(settingsManager.sourcesGetter));
attachRouter("/plywood", plywoodRouter(settingsManager));
attachRouter("/plyql", plyqlRouter(settingsManager.sourcesGetter));
attachRouter("/mkurl", mkurlRouter(settingsManager.sourcesGetter));
attachRouter("/shorten", shortenRouter(settingsManager.appSettings, isTrustedProxy));

attachRouter("/", turniloRouter(SETTINGS_MANAGER.appSettings, VERSION));
attachRouter("/", turniloRouter(settingsManager.appSettings, settingsManager.getTimekeeper, version));

// Catch 404 and redirect to /
app.use((req: Request, res: Response) => {
res.redirect(getRoutePath("/"));
});
// Catch 404 and redirect to /
app.use((req: Request, res: Response) => {
res.redirect(getRoutePath("/"));
});

app.use((err: any, req: Request, res: Response, next: Function) => {
LOGGER.error(`Server Error: ${err.message}`);
LOGGER.error(err.stack);
res.status(err.status || 500);
// no stacktraces leaked to user
const error = isDev ? err : null;
res.send(errorLayout({ version: VERSION, title: "Error" }, err.message, error));
});
app.use((err: any, req: Request, res: Response, next: Function) => {
settingsManager.logger.error(`Server Error: ${err.message}`);
settingsManager.logger.error(err.stack);
res.status(err.status || 500);
// no stacktraces leaked to user
const error = isDev ? err : null;
res.send(errorLayout({ version, title: "Error" }, err.message, error));
});

export default app;
return app;
}