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/browser-websocket/api.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45/*6* License7*/89// Websocket based request/response api.10//11// All functionality here is of the form:12//13// -- one request14// -- one response1516import { getClient } from "@cocalc/project/client";17import { get_configuration } from "../configuration";18import { run_formatter, run_formatter_string } from "../formatters";19import { nbconvert as jupyter_nbconvert } from "../jupyter/convert";20import { lean, lean_channel } from "../lean/server";21import { jupyter_strip_notebook } from "@cocalc/jupyter/nbgrader/jupyter-parse";22import { jupyter_run_notebook } from "@cocalc/jupyter/nbgrader/jupyter-run";23import { synctable_channel } from "../sync/server";24import { syncdoc_call } from "../sync/sync-doc";25import { terminal } from "@cocalc/terminal";26import { x11_channel } from "../x11/server";27import { canonical_paths } from "./canonical-path";28import { delete_files } from "@cocalc/backend/files/delete-files";29import { eval_code } from "./eval-code";30import computeFilesystemCache from "./compute-filesystem-cache";31import { move_files } from "@cocalc/backend/files/move-files";32import { rename_file } from "@cocalc/backend/files/rename-file";33import { realpath } from "./realpath";34import { project_info_ws } from "../project-info";35import query from "./query";36import { browser_symmetric_channel } from "./symmetric_channel";37import type { Mesg } from "@cocalc/comm/websocket/types";38import handleSyncFsApiCall, {39handleSyncFsRequestCall,40handleComputeServerSyncRegister,41handleCopy,42handleSyncFsGetListing,43handleComputeServerDeleteFiles,44handleComputeServerMoveFiles,45handleComputeServerRenameFile,46handleComputeServerComputeRegister,47} from "@cocalc/sync-fs/lib/handle-api-call";48import { version } from "@cocalc/util/smc-version";49import { getLogger } from "@cocalc/project/logger";50import execCode from "./exec-code";5152const log = getLogger("websocket-api");5354let primus: any = undefined;55export function init_websocket_api(_primus: any): void {56primus = _primus;5758primus.on("connection", function (spark) {59// Now handle the connection, which can be either from a web browser, or60// from a compute server.61log.debug(`new connection from ${spark.address.ip} -- ${spark.id}`);6263spark.on("request", async (data, done) => {64log.debug("primus-api", "request", data, "REQUEST");65const t0 = Date.now();66try {67const resp = await handleApiCall(data, spark);68//log.debug("primus-api", "response", resp);69done(resp);70} catch (err) {71// put this in for debugging...72// It's normal to sometimes get errors, e.g., when a Jupyter kernel73// isn't yet available.74// console.trace(); log.debug("primus-api error stacktrack", err.stack, err);75done({ error: err.toString(), status: "error" });76}77log.debug(78"primus-api",79"request",80data,81`FINISHED: time=${Date.now() - t0}ms`,82);83});84});8586primus.on("disconnection", function (spark) {87log.debug(88"primus-api",89`end connection from ${spark.address.ip} -- ${spark.id}`,90);91});92}9394async function handleApiCall(data: Mesg, spark): Promise<any> {95const client = getClient();96switch (data.cmd) {97case "version":98return version;99case "listing":100return await listing(data.path, data.hidden, data.compute_server_id);101case "delete_files":102const { compute_server_id, paths } = data;103if (compute_server_id) {104return await handleComputeServerDeleteFiles({105paths,106compute_server_id,107});108} else {109return await delete_files(data.paths);110}111case "move_files":112if (data.compute_server_id) {113return await handleComputeServerMoveFiles(data);114} else {115return await move_files(data.paths, data.dest, (path) =>116client.set_deleted(path),117);118}119case "rename_file":120if (data.compute_server_id) {121return await handleComputeServerRenameFile(data);122} else {123return await rename_file(data.src, data.dest, (path) =>124client.set_deleted(path),125);126}127case "canonical_paths":128return await canonical_paths(data.paths);129case "configuration":130return await get_configuration(data.aspect, data.no_cache);131case "prettier": // deprecated132case "formatter":133return await run_formatter(client, data.path, data.options, log);134case "prettier_string": // deprecated135case "formatter_string":136return await run_formatter_string(data.path, data.str, data.options, log);137case "exec":138if (data.opts == null) {139throw Error("opts must not be null");140}141return await execCode(data.opts);142case "query":143return await query(client, data.opts);144case "eval_code":145return await eval_code(data.code);146case "terminal":147return await terminal(primus, data.path, data.options);148case "lean":149return await lean(client, primus, log, data.opts);150case "jupyter_strip_notebook":151return await jupyter_strip_notebook(data.ipynb_path);152case "jupyter_nbconvert":153return await jupyter_nbconvert(data.opts);154case "jupyter_run_notebook":155return await jupyter_run_notebook(log, data.opts);156case "lean_channel":157return await lean_channel(client, primus, log, data.path);158case "x11_channel":159return await x11_channel(client, primus, log, data.path, data.display);160case "synctable_channel":161return await synctable_channel(162client,163primus,164log,165data.query,166data.options,167);168case "syncdoc_call":169return await syncdoc_call(data.path, data.mesg);170case "symmetric_channel":171return await browser_symmetric_channel(client, primus, log, data.name);172case "realpath":173return realpath(data.path);174case "project_info":175return await project_info_ws(primus, log);176case "compute_filesystem_cache":177return await computeFilesystemCache(data.opts);178case "sync_fs":179return await handleSyncFsApiCall(data.opts);180case "compute_server_sync_register":181// register filesystem container182return await handleComputeServerSyncRegister(data.opts, spark);183case "compute_server_compute_register":184// register compute container185return await handleComputeServerComputeRegister(data.opts, spark);186case "compute_server_sync_request":187return await handleSyncFsRequestCall(data.opts);188case "copy_from_project_to_compute_server":189case "copy_from_compute_server_to_project":190return await handleCopy({ event: data.cmd, ...data.opts });191default:192throw Error(193`command "${194(data as any).cmd195}" not implemented -- restart your project (in Project --> Settings)`,196);197}198}199/* implementation of the api calls */200201import { DirectoryListingEntry } from "@cocalc/util/types";202import getListing from "@cocalc/backend/get-listing";203async function listing(204path: string,205hidden: boolean,206compute_server_id?: number,207): Promise<DirectoryListingEntry[]> {208if (!compute_server_id) {209return await getListing(path, hidden);210} else {211return await handleSyncFsGetListing({ path, hidden, compute_server_id });212}213}214215216