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/lean/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/*6LEAN server7*/89const lean_files = {};1011import { lean_server, Lean } from "./lean";12import { init_global_packages } from "./global-packages";13import { isEqual } from "lodash";1415let the_lean_server: Lean | undefined = undefined;1617function init_lean_server(client: any, logger: any): void {18the_lean_server = lean_server(client);19the_lean_server.on("tasks", function (path: string, tasks: object[]) {20logger.debug("lean_server:websocket:tasks -- ", path, tasks);21const lean_file = lean_files[`lean:${path}`];22if (lean_file !== undefined && !isEqual(lean_file.tasks, tasks)) {23lean_file.tasks = tasks;24lean_file.channel.write({ tasks });25}26});2728the_lean_server.on("sync", function (path: string, hash: number) {29logger.debug("lean_server:websocket:sync -- ", path, hash);30const lean_file = lean_files[`lean:${path}`];31if (lean_file !== undefined && !isEqual(lean_file.sync, hash)) {32const sync = { hash: hash, time: Date.now() };33lean_file.sync = sync;34lean_file.channel.write({ sync });35}36});3738the_lean_server.on("messages", function (path: string, messages: object) {39logger.debug("lean_server:websocket:messages -- ", path, messages);40const lean_file = lean_files[`lean:${path}`];41if (lean_file !== undefined && !isEqual(lean_file.messages, messages)) {42lean_file.messages = messages;43lean_file.channel.write({ messages });44}45});46}4748export async function lean_channel(49client: any,50primus: any,51logger: any,52path: string53): Promise<string> {54if (the_lean_server === undefined) {55await init_global_packages();56init_lean_server(client, logger);57if (the_lean_server === undefined) {58// just to satisfy typescript.59throw Error("lean server not defined");60}61}62the_lean_server.register(path);6364// TODO: delete lean_files[name] under some condition.65const name = `lean:${path}`;66if (lean_files[name] !== undefined) {67return name;68}69const channel = primus.channel(name);70lean_files[name] = {71channel,72messages: [],73};7475channel.on("connection", function (spark: any): void {76// make sure lean server cares:77if (the_lean_server === undefined) {78// just to satisfy typescript.79throw Error("lean server not defined");80}81the_lean_server.register(path);8283const lean_file = lean_files[name];84if (lean_file === undefined) {85return;86}87// Now handle the connection88logger.debug(89"lean channel",90`new connection from ${spark.address.ip} -- ${spark.id}`91);92spark.write({93messages: lean_file.messages,94sync: lean_file.sync,95tasks: lean_file.tasks,96});97spark.on("end", function () {});98});99100return name;101}102103function assert_type(name: string, x: any, type: string): void {104if (typeof x != type) {105throw Error(`${name} must have type ${type}`);106}107}108109export async function lean(110client: any,111_: any,112logger: any,113opts: any114): Promise<any> {115if (the_lean_server === undefined) {116init_lean_server(client, logger);117if (the_lean_server === undefined) {118// just to satisfy typescript.119throw Error("lean server not defined");120}121}122if (opts == null || typeof opts.cmd != "string") {123throw Error("opts must be an object with cmd field a string");124}125// control message126logger.debug("lean command", JSON.stringify(opts));127switch (opts.cmd) {128case "info":129assert_type("path", opts.path, "string");130assert_type("line", opts.line, "number");131assert_type("column", opts.column, "number");132const r = (await the_lean_server.info(opts.path, opts.line, opts.column))133.record;134return r ? r : {};135136// get server version137case "version":138return await the_lean_server.version();139140// kill the LEAN server.141// this can help with, e.g., updating the LEAN_PATH142case "kill":143return the_lean_server.kill();144145case "restart":146return await the_lean_server.restart();147148case "complete":149assert_type("path", opts.path, "string");150assert_type("line", opts.line, "number");151assert_type("column", opts.column, "number");152const complete = await the_lean_server.complete(153opts.path,154opts.line,155opts.column,156opts.skipCompletions157);158if (complete == null || complete.completions == null) {159return [];160}161// delete the source fields -- they are LARGE and not used at all in the UI.162for (const c of complete.completions) {163delete (c as any).source; // cast because of mistake in upstream type def. sigh.164}165/*166complete.completions.sort(function(a, b): number {167if (a.text == null || b.text == null) {168// satisfy typescript null checks; shouldn't happen.169return 0;170}171return cmp(a.text.toLowerCase(), b.text.toLowerCase());172});173*/174return complete.completions;175176default:177throw Error(`unknown cmd ${opts.cmd}`);178}179}180181182