Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/project/named-servers/list.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45/*6This file defines all of the named servers we support.78To add another one, define a new entry in SPEC:910- The key is the name of the server.11- The value is a string this a function of (ip, port, basePath). The string12is a bash shell command that when run starts the server. It might optionally13use process.env so that the env can influence command line options.14*/1516import { exec } from "node:child_process";17import { mkdir, writeFile } from "node:fs/promises";18import { join } from "node:path";1920import { NamedServerName } from "@cocalc/util/types/servers";2122type CommandFunction = (23ip: string,24port: number,25basePath: string,26) => Promise<string>;2728// Disables JupyterLab RTC since it is still very buggy, unfortunately.29/*30Reported:311. The steps I’ve taken:32* Start a JupyterLabs Notebook server from my project settings33* In the server, open & edit a Jupyter Notebook w/ Python 3 system-wide kernel34* (Optional) Shutdown project/close browser tab35* Walk away, return 30+ minutes later36* (Optional) Restart project/server37* Edit already open notebook, try to save/export/download38392. What happened:40Editing the notebook behaves as usual (code runs), I can access the file system, interact with a terminal, but any changes I make to this already-open notebook won’t save.4142I also saw almost exactly this happen in the JupyterLab weekly meeting43with the latest beta in early November (that was even worse, since refreshing44maybe didn't even work).45*/4647// If you want to enable it, set the environment variable in Project Settings {"COCALC_JUPYTERLAB_RTC": "true"}48const JUPYTERLAB_RTC = process.env.COCALC_JUPYTERLAB_RTC === "true";4950// iopub params for jupyter notebook51const JUPYTERNB_DATA =52process.env.COCALC_JUPYTER_NOTEBOOK_iopub_data_rate_limit ?? 2000000;53const JUPYTERNB_MSGS =54process.env.COCALC_JUPYTER_NOTEBOOK_iopub_msg_rate_limit ?? 50;5556// iopub params for jupyter lab57const JUPYTERLAB_DATA =58process.env.COCALC_JUPYTER_LAB_iopub_data_rate_limit ?? 2000000;59const JUPYTERLAB_MSGS =60process.env.COCALC_JUPYTER_LAB_iopub_msg_rate_limit ?? 50;6162async function rserver(_ip: string, port: number, basePath: string) {63// tmp: this is used to write a small config file and then use it64const tmp = join(process.env.TMP ?? "/tmp", "rserver");65await mkdir(tmp, { recursive: true });66const home = process.env.HOME ?? "/home/user";67// ATTN: by trial and error I learned this must be in the home dir (not tmp) – otherwise silent crash68// Also, that dir name has a length limit (unknown), does not work for nested dev-in-project69const data = join(home, ".config", "rserver");70const data_db = join(data, "db");71// This creates the tmp dir, and the data dir, and the data/db dir72await mkdir(data_db, { recursive: true });73const db_conf = join(tmp, "db.conf");74await writeFile(db_conf, `provider=sqlite\ndirectory=${data_db}`);7576// ATTN: it's tempting to add --www-address=${ip} \77// to tell it where to listen to, but for some reason that doesn't work. Hence $ip is ignored.78// The default is 0.0.0.0, which works (and it's fine, because we proxy it anyway).7980// Check, if the user $USER exists in /etc/passwd using grep. If not, call the user "user".81// Just process.env.USER does not work in development, i.e. when the "random id" user does not exist.82const user = await new Promise<string>((resolve) => {83const name = process.env.USER ?? "user";84exec(`grep "^${name}:" /etc/passwd`, (err) => {85resolve(err ? "user" : name);86});87});8889// watch out, this will be prefixed with #!/bin/sh and piped into stdout/stderr files90// part from that, rserver must be in the $PATH91// see note at project/configuration::get_rserver92return [93`rserver`,94`--server-daemonize=0`,95`--auth-none=1`,96`--auth-encrypt-password=0`,97`--server-user=${user}`,98`--database-config-file="${db_conf}"`,99`--server-data-dir="${data}"`,100`--server-working-dir="${process.env.HOME}"`,101`--www-port=${port}`,102`--www-root-path="${basePath}/"`, // www-root-path needs the trailing slash and it must be "server", not "port"103`--server-pid-file="${join(tmp, "rserver.pid")}"`,104].join(" ");105}106107const SPEC: { [name in NamedServerName]: CommandFunction } = {108code: async (ip: string, port: number) =>109`code-server --bind-addr=${ip}:${port} --auth=none`,110jupyter: async (ip: string, port: number, basePath: string) =>111[112`jupyter notebook`,113`--port-retries=0`,114`--no-browser`,115`--NotebookApp.iopub_data_rate_limit=${JUPYTERNB_DATA}`,116`--NotebookApp.iopub_msg_rate_limit=${JUPYTERNB_MSGS}`,117// we run Jupyter NB without authentication, because everything is proxied through CoCalc anyway118`--NotebookApp.token='' --NotebookApp.password=''`,119`--NotebookApp.allow_remote_access=True`,120`--NotebookApp.mathjax_url=/cdn/mathjax/MathJax.js`,121`--NotebookApp.base_url=${basePath} --ip=${ip} --port=${port}`,122].join(" "),123jupyterlab: async (ip: string, port: number, basePath: string) =>124[125"jupyter lab",126`--port-retries=0`, // don't try another port, only the one we specified will work127`--no-browser`, // don't open a browser – the UI does this if appliable128`--NotebookApp.iopub_data_rate_limit=${JUPYTERLAB_DATA}`,129`--NotebookApp.iopub_msg_rate_limit=${JUPYTERLAB_MSGS}`,130// we run Jupyter Lab without authentication, because everything is proxied through CoCalc anyway131`--NotebookApp.token='' --NotebookApp.password=''`,132// additionally to the above, and since several Jupyter Lab across projects might interfere with each other, we disable XSRF protection133// see https://github.com/sagemathinc/cocalc/issues/6492134`--ServerApp.disable_check_xsrf=True`, // Ref: https://jupyter-server.readthedocs.io/en/latest/other/full-config.html135`--NotebookApp.allow_remote_access=True`,136`--NotebookApp.mathjax_url=/cdn/mathjax/MathJax.js`,137`--NotebookApp.base_url=${basePath}`,138`--ip=${ip}`,139`--port=${port}`,140`${JUPYTERLAB_RTC ? "--collaborative" : ""}`,141].join(" "),142pluto: async (ip: string, port: number) =>143`echo 'import Pluto; Pluto.run(launch_browser=false, require_secret_for_access=false, host="${ip}", port=${port})' | julia`,144rserver,145} as const;146147export default function getSpec(name: NamedServerName): CommandFunction {148const spec = SPEC[name];149if (spec == null) {150throw Error(`unknown named server: "${name}"`);151}152return spec;153}154155156