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/jupyter/kernel/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/*6Support for the project's websocket-based request/response API, which is used for handling7various messages related to working with Jupyter.8*/910import { get_existing_kernel } from "@cocalc/jupyter/kernel";11import { get_kernel_data } from "@cocalc/jupyter/kernel/kernel-data";12import { bufferToBase64 } from "@cocalc/util/base64";1314export async function handleApiRequest(15path: string,16endpoint: string,17query?: any,18): Promise<any> {19// First handle endpoints that do not depend on a specific kernel.20switch (endpoint) {21case "kernels":22return await get_kernel_data();23}2425// Now endpoints that do depend on a specific kernel.26const kernel = get_existing_kernel(path);27if (kernel == null) {28if (endpoint == "signal") {29// It's not a serious problem to try to send a signal to a non-existent kernel. A no-op30// is completely reasonable, since you only send signals to kill or interrupt, and a non-existent31// kernel is already killed or interrupted. See https://github.com/sagemathinc/cocalc/issues/442032return {};33}34throw Error(`api endpoint ${endpoint}: no kernel with path '${path}'`);35}36switch (endpoint) {37case "save_ipynb_file":38await kernel.save_ipynb_file();39return {};4041case "signal":42kernel.signal(query.signal);43return {};4445case "kernel_info":46return await kernel.kernel_info();4748case "more_output":49return kernel.more_output(query.id);5051case "complete":52return await kernel.complete(get_code_and_cursor_pos(query));5354case "introspect":55const { code, cursor_pos } = get_code_and_cursor_pos(query);56let detail_level = 0;57if (query.level != null) {58try {59detail_level = parseInt(query.level);60if (detail_level < 0) {61detail_level = 0;62} else if (detail_level > 1) {63detail_level = 1;64}65} catch (err) {}66}67return await kernel.introspect({68code,69cursor_pos,70detail_level,71});7273case "store":74const { key, value } = query;75if (value === undefined) {76// undefined when getting the value77return kernel.store.get(key);78} else if (value === null) {79// null is used for deleting the value80kernel.store.delete(key);81return {};82} else {83kernel.store.set(key, value);84return {};85}8687case "comm":88return kernel.send_comm_message_to_kernel(query);8990case "ipywidgets-get-buffer":91const { model_id, buffer_path } = query;92const buffer = kernel.ipywidgetsGetBuffer(model_id, buffer_path);93if (buffer == null) {94throw Error(95`no buffer for model=${model_id}, buffer_path=${JSON.stringify(96buffer_path,97)}`,98);99}100return { buffer64: bufferToBase64(buffer) };101default:102throw Error(`unknown endpoint "${endpoint}"`);103}104}105106function get_code_and_cursor_pos(query: any): {107code: string;108cursor_pos: number;109} {110const code: string = query.code;111if (!code) {112throw Error("must specify code");113}114let cursor_pos: number;115if (query.cursor_pos != null) {116try {117cursor_pos = parseInt(query.cursor_pos);118} catch (error) {119cursor_pos = code.length;120}121} else {122cursor_pos = code.length;123}124125return { code, cursor_pos };126}127128129