UNPKG

@cocalc/project

Version:
108 lines (101 loc) 3.14 kB
/* * This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. * License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details */ /* Support for the project's websocket-based request/response API, which is used for handling various messages related to working with Jupyter. */ import { get_existing_kernel } from "./jupyter"; import { get_kernel_data } from "./kernel-data"; export async function handle_request( path: string, endpoint: string, query?: any ): Promise<any> { // First handle endpoints that do not depend on a specific kernel. switch (endpoint) { case "kernels": return await get_kernel_data(); } // Now endpoints that do depend on a specific kernel. const kernel = get_existing_kernel(path); if (kernel == null) { if (endpoint == "signal") { // It's not a serious problem to try to send a signal to a non-existent kernel. A no-op // is completely reasonable, since you only send signals to kill or interrupt, and a non-existent // kernel is already killed or interrupted. See https://github.com/sagemathinc/cocalc/issues/4420 return {}; } throw Error(`api endpoint ${endpoint}: no kernel with path '${path}'`); } switch (endpoint) { case "save_ipynb_file": await kernel.save_ipynb_file(); return {}; case "signal": kernel.signal(query.signal); return {}; case "kernel_info": return await kernel.kernel_info(); case "more_output": return kernel.more_output(query.id); case "complete": return await kernel.complete(get_code_and_cursor_pos(query)); case "introspect": const { code, cursor_pos } = get_code_and_cursor_pos(query); let detail_level = 0; if (query.level != null) { try { detail_level = parseInt(query.level); if (detail_level < 0) { detail_level = 0; } else if (detail_level > 1) { detail_level = 1; } } catch (err) {} } return await kernel.introspect({ code, cursor_pos, detail_level, }); case "store": const { key, value } = query; if (value === undefined) { // undefined when getting the value return kernel.store.get(key); } else if (value === null) { // null is used for deleting the value kernel.store.delete(key); return {}; } else { kernel.store.set(key, value); return {}; } case "comm": const [msg_id, comm_id, data] = query; return kernel.send_comm_message_to_kernel(msg_id, comm_id, data); default: throw Error(`unknown endpoint "${endpoint}"`); } } function get_code_and_cursor_pos( query: any ): { code: string; cursor_pos: number } { const code: string = query.code; if (!code) { throw Error("must specify code"); } let cursor_pos: number; if (query.cursor_pos != null) { try { cursor_pos = parseInt(query.cursor_pos); } catch (error) { cursor_pos = code.length; } } else { cursor_pos = code.length; } return { code, cursor_pos }; }