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/jupyter/http-server.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45/*6HTTP server for getting various information from Jupyter, without7having to go through the websocket connection and messaging. This is8useful, e.g., for big images, general info about all available9kernels, sending signals, doing tab completions, and so on.10*/1112import { Router } from "express";13import * as os_path from "node:path";14import getLogger from "@cocalc/backend/logger";15import { BlobStoreInterface } from "@cocalc/jupyter/types/project-interface";16import { startswith, to_json } from "@cocalc/util/misc";17import { exists } from "@cocalc/backend/misc/async-utils-node";18import { get_existing_kernel } from "@cocalc/jupyter/kernel";19import {20BlobStoreDisk,21get_blob_store,22BlobStoreSqlite,23} from "@cocalc/jupyter/blobs";24import { get_kernel_data } from "@cocalc/jupyter/kernel/kernel-data";25import { get_ProjectStatusServer } from "@cocalc/project/project-status/server";26import { delay } from "awaiting";2728const log = getLogger("jupyter-http-server");2930const BASE = "/.smc/jupyter/";3132function get_kernel(kernel_data, name) {33for (const k of kernel_data) {34if (k.name == name) return k;35}36return null;37}3839function jupyter_kernel_info_handler(router): void {40router.get(41BASE + "ipywidgets-get-buffer",42async function (req, res): Promise<void> {43try {44const { path, model_id, buffer_path } = req.query;45const kernel = get_existing_kernel(path);46if (kernel == null) {47res.status(404).send(`kernel associated to ${path} does not exist`);48return;49}50const buffer = kernel.ipywidgetsGetBuffer(model_id, buffer_path);51if (buffer == null) {52res53.status(404)54.send(55`buffer associated to model ${model_id} at ${buffer_path} not known`56);57return;58}59res.status(200).send(buffer);60} catch (err) {61res.status(500).send(`Error getting ipywidgets buffer - ${err}`);62}63}64);6566// we are only actually using this to serve up the logo.67router.get(BASE + "kernelspecs/*", async function (req, res): Promise<void> {68try {69const kernel_data = await get_kernel_data();70let path = req.path.slice((BASE + "kernelspecs/").length).trim();71if (path.length === 0) {72res.json(kernel_data);73return;74}75const segments = path.split("/");76const name = segments[0];77const kernel = get_kernel(kernel_data, name);78if (kernel == null) {79const msg = `no such kernel '${name}'`;80throw Error(msg);81}82const resource_dir = kernel.resource_dir;83path = os_path.join(resource_dir, segments.slice(1).join("/"));84path = os_path.resolve(path);8586if (!startswith(path, resource_dir)) {87// don't let user use .. or something to get any file on the server...!88// (this really can't happen due to url rules already; just being super paranoid.)89throw Error(`suspicious path '${path}'`);90}91if (await exists(path)) {92res.sendFile(path);93} else {94throw Error(`no such path '${path}'`);95}96} catch (err) {97res.status(500).send(err.toString());98}99});100}101102export default async function init(): Promise<Router> {103// this might take infinitely long, obviously:104let blob_store: BlobStoreSqlite | BlobStoreDisk;105let d = 3000;106while (true) {107try {108// This call right here causes the configured blobstore to be initialized in the file109// packages/jupyter/blobs/get.ts110blob_store = await get_blob_store();111get_ProjectStatusServer().clearComponentAlert("BlobStore");112break;113} catch (err) {114get_ProjectStatusServer().setComponentAlert("BlobStore");115log.warn(`unable to instantiate BlobStore -- ${err}`);116}117await delay(d);118d = Math.min(30000, 1.2 * d);119}120121log.debug("got blob store, setting up jupyter http server");122const router = Router();123124// Install handling for the blob store125jupyter_blobstore_handler(router, blob_store);126127// Handler for Jupyter kernel info128jupyter_kernel_info_handler(router);129130return router;131}132133function jupyter_blobstore_handler(134router: Router,135blob_store: BlobStoreInterface136): void {137const base = BASE + "blobs/";138139router.get(base, async (_, res) => {140res.setHeader("Content-Type", "application/json");141res.end(to_json(await blob_store.keys()));142});143144router.get(base + "*", async (req, res) => {145const filename: string = req.path.slice(base.length);146const sha1: string = `${req.query.sha1}`;147res.type(filename);148res.send(await blob_store.get(sha1));149});150}151152153