Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/project/servers/browser/http-server.ts
1449 views
1
/*
2
* This file is part of CoCalc: Copyright © 2022 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
This is an express http server that is meant to receive connections
8
only from web browser clients that signed in as collaborators on
9
this projects. It serves both HTTP and websocket connections, which
10
should be proxied through some hub.
11
*/
12
13
import compression from "compression";
14
import express from "express";
15
import { createServer } from "http";
16
import { writeFile } from "node:fs/promises";
17
import { join } from "node:path";
18
19
import basePath from "@cocalc/backend/base-path";
20
import initWebsocket from "@cocalc/project/browser-websocket/server";
21
import initWebsocketFs from "../websocketfs";
22
import initSyncFs from "../sync-fs";
23
import { browserPortFile, project_id } from "@cocalc/project/data";
24
import initDirectoryListing from "@cocalc/project/directory-listing";
25
import { getOptions } from "@cocalc/project/init-program";
26
import * as kucalc from "@cocalc/project/kucalc";
27
import { getLogger } from "@cocalc/project/logger";
28
import { once } from "@cocalc/util/async-utils";
29
import initRootSymbolicLink from "./root-symlink";
30
31
const winston = getLogger("browser-http-server");
32
33
export default async function init(): Promise<void> {
34
winston.info("starting server...");
35
36
const base = join(basePath, project_id, "raw") + "/";
37
38
const app = express();
39
app.disable("x-powered-by"); // https://github.com/sagemathinc/cocalc/issues/6101
40
41
const server = createServer(app);
42
43
// WEBSOCKET SERVERS
44
// **CRITICAL:** This *must* be above the app.use(compression())
45
// middleware below, since compressing/uncompressing the websocket
46
// would otherwise happen, and that slows it down a lot.
47
// Setup the ws websocket server, which is used by clients
48
// for direct websocket connections to the project, and also
49
// serves primus.js, which is the relevant client library.
50
winston.info("initializing websocket server");
51
// We have to explicitly also include the base as a parameter
52
// to initWebsocket, since of course it makes deeper user of server.
53
app.use(base, initWebsocket(server, base));
54
initWebsocketFs(server, base);
55
// This uses its own internal lz4 compression:
56
initSyncFs(server, base);
57
58
// CRITICAL: keep this after the websocket stuff or anything you do not
59
// want to have compressed.
60
// suggested by http://expressjs.com/en/advanced/best-practice-performance.html#use-gzip-compression
61
app.use(compression());
62
63
winston.info("creating root symbolic link");
64
await initRootSymbolicLink();
65
66
if (kucalc.IN_KUCALC) {
67
// Add /health (used as a health check for Kubernetes) and /metrics (Prometheus)
68
winston.info("initializing KuCalc only health metrics server");
69
kucalc.init_health_metrics(app, project_id);
70
}
71
72
// Setup the directory_listing/... server, which is used to provide directory listings
73
// to the hub (at least in KuCalc). It is still used by HUB! But why? Maybe it is only
74
// for the deprecated public access to a project? If so, we can get rid of all of that.
75
winston.info("initializing directory listings server (DEPRECATED)");
76
app.use(base, initDirectoryListing());
77
78
const options = getOptions();
79
server.listen(options.browserPort, options.hostname);
80
await once(server, "listening");
81
const address = server.address();
82
if (address == null || typeof address == "string") {
83
// null = failed; string doesn't happen since that's for unix domain
84
// sockets, which we aren't using.
85
// This is probably impossible, but it makes typescript happier.
86
throw Error("failed to assign a port");
87
}
88
const assignedPort = address.port; // may be a server assigned random port.
89
winston.info(
90
`Started -- port=${assignedPort}, host='${options.hostname}', base='${base}'`,
91
);
92
93
winston.info(`Writing port to ${browserPortFile}`);
94
await writeFile(browserPortFile, `${assignedPort}`);
95
}
96
97