UNPKG

@cocalc/hub

Version:
137 lines 6.74 kB
"use strict"; /* The main hub express app. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const assets_1 = require("@cocalc/assets"); const base_path_1 = __importDefault(require("@cocalc/backend/base-path")); const cdn_1 = require("@cocalc/cdn"); const virtual_hosts_1 = __importDefault(require("@cocalc/next/lib/share/virtual-hosts")); const static_1 = require("@cocalc/static"); const compression_1 = __importDefault(require("compression")); const cookie_parser_1 = __importDefault(require("cookie-parser")); const express_1 = __importDefault(require("express")); const ms_1 = __importDefault(require("ms")); const path_1 = require("path"); const url_1 = require("url"); const analytics_1 = require("../analytics"); const health_checks_1 = require("../health-checks"); const logger_1 = require("../logger"); const proxy_1 = __importDefault(require("../proxy")); const api_1 = __importDefault(require("./app/api")); const app_redirect_1 = __importDefault(require("./app/app-redirect")); const blobs_1 = __importDefault(require("./app/blobs")); const customize_1 = __importDefault(require("./app/customize")); const metrics_1 = require("./app/metrics"); const next_1 = __importDefault(require("./app/next")); const set_cookies_1 = __importDefault(require("./app/set-cookies")); const stats_1 = __importDefault(require("./app/stats")); const database_1 = require("./database"); const http_1 = __importDefault(require("./http")); const robots_1 = __importDefault(require("./robots")); // Used for longterm caching of files. This should be in units of seconds. const MAX_AGE = Math.round((0, ms_1.default)("10 days") / 1000); const SHORT_AGE = Math.round((0, ms_1.default)("10 seconds") / 1000); async function init(opts) { const winston = (0, logger_1.getLogger)("express-app"); winston.info("creating express app"); // Create an express application const app = (0, express_1.default)(); app.disable("x-powered-by"); // https://github.com/sagemathinc/cocalc/issues/6101 // healthchecks are for internal use, no basePath prefix // they also have to come first, since e.g. the vhost depends // on the DB, which could be down const basicEndpoints = express_1.default.Router(); await (0, health_checks_1.setup_health_checks)({ router: basicEndpoints, db: database_1.database }); app.use(basicEndpoints); // also, for the same reasons as above, setup the /metrics endpoint (0, metrics_1.initMetricsEndpoint)(basicEndpoints); // now, we build the router for all other endpoints const router = express_1.default.Router(); // This must go very early - we handle virtual hosts, like wstein.org // before any other routes or middleware interfere. if (opts.nextServer) { app.use((0, virtual_hosts_1.default)()); } // Enable compression, as suggested by // http://expressjs.com/en/advanced/best-practice-performance.html#use-gzip-compression // NOTE "Express runs everything in order" -- // https://github.com/expressjs/compression/issues/35#issuecomment-77076170 app.use((0, compression_1.default)()); app.use((0, cookie_parser_1.default)()); // Install custom middleware to track response time metrics via prometheus (0, metrics_1.setupInstrumentation)(router); // see http://stackoverflow.com/questions/10849687/express-js-how-to-get-remote-client-address app.enable("trust proxy"); // Various files such as the webpack static content should be cached long-term, // and we use this function to set appropriate headers at various points below. const cacheLongTerm = (res) => { res.setHeader("Cache-Control", `public, max-age=${MAX_AGE}, must-revalidate'`); res.setHeader("Expires", new Date(Date.now().valueOf() + MAX_AGE).toUTCString()); }; const cacheShortTerm = (res) => { res.setHeader("Cache-Control", `public, max-age=${SHORT_AGE}, must-revalidate`); res.setHeader("Expires", new Date(Date.now().valueOf() + SHORT_AGE).toUTCString()); }; router.use("/robots.txt", (0, robots_1.default)()); // setup the analytics.js endpoint await (0, analytics_1.initAnalytics)(router, database_1.database); (0, api_1.default)(router, opts.projectControl); // The /static content, used by docker, development, etc. // This is the stuff that's packaged up via webpack in packages/static. router.use((0, path_1.join)("/static", static_1.path, "app.html"), express_1.default.static((0, path_1.join)(static_1.path, "app.html"), { setHeaders: cacheShortTerm, })); router.use("/static", express_1.default.static(static_1.path, { setHeaders: cacheLongTerm })); // Static assets that are used by the webapp, the landing page, etc. router.use("/webapp", express_1.default.static(assets_1.path, { setHeaders: cacheLongTerm })); // This is @cocalc/cdn – cocalc serves everything it might get from a CDN on its own. // This is defined in the @cocalc/cdn package. See the comments in packages/cdn. router.use("/cdn", express_1.default.static(cdn_1.path, { setHeaders: cacheLongTerm })); // Redirect requests to /app to /static/app.html. // TODO: this will likely go away when rewrite the landing pages to not // redirect users to /app in the first place. router.get("/app", (req, res) => { // query is exactly "?key=value,key=..." const query = (0, url_1.parse)(req.url, true).search || ""; res.redirect((0, path_1.join)(base_path_1.default, "static/app.html") + query); }); (0, blobs_1.default)(router); (0, set_cookies_1.default)(router); (0, customize_1.default)(router, opts.isPersonal); (0, stats_1.default)(router); (0, app_redirect_1.default)(router); if (base_path_1.default !== "/") { app.use(base_path_1.default, router); } else { app.use(router); } const httpServer = (0, http_1.default)({ cert: opts.cert, key: opts.key, app, }); if (opts.proxyServer) { winston.info(`initializing the http proxy server`); (0, proxy_1.default)({ projectControl: opts.projectControl, isPersonal: opts.isPersonal, httpServer, app, }); } // IMPORTANT: // The nextjs server must be **LAST** (!), since it takes // all routes not otherwise handled above. if (opts.nextServer) { // The Next.js server await (0, next_1.default)(app); } return { httpServer, router }; } exports.default = init; //# sourceMappingURL=express-app.js.map