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/frontend/compute/manager.ts
Views: 687
/*1Client side compute servers manager23Used from a browser client frontend to manage what compute servers4are available and how they are used for a given project.56When doing dev from the browser console, do:78cc.client.project_client.computeServers('...project_id...')9*/1011import { SYNCDB_PARAMS, decodeUUIDtoNum } from "@cocalc/util/compute/manager";12import { webapp_client } from "@cocalc/frontend/webapp-client";13import debug from "debug";14import { once } from "@cocalc/util/async-utils";15import { EventEmitter } from "events";16import { excludeFromComputeServer } from "@cocalc/frontend/file-associations";1718const log = debug("cocalc:frontend:compute:manager");1920export class ComputeServersManager extends EventEmitter {21private sync_db;22private project_id;2324constructor(project_id: string) {25super();26this.project_id = project_id;27this.sync_db = webapp_client.sync_db({28project_id,29...SYNCDB_PARAMS,30});31this.sync_db.on("change", () => {32this.emit("change");33});34// It's reasonable to have many clients, e.g., one for each open file35this.setMaxListeners(100);36log("created", this.project_id);37}3839close = () => {40delete computeServerManagerCache[this.project_id];41this.sync_db.close();42};4344// save the current state to the backend. This is critical to do, e.g., before45// opening a file and after calling connectComputeServerToPath, since otherwise46// the project doesn't even know that the file should open on the compute server47// until after it has opened it, which is disconcerting and not efficient (but48// does mostly work, though it is intentionally making things really hard on ourselves).49save = async () => {50await this.sync_db.save();51};5253getComputeServers = () => {54const servers = {};55const cursors = this.sync_db.get_cursors({ excludeSelf: 'never' }).toJS();56for (const client_id in cursors) {57const server = cursors[client_id];58servers[decodeUUIDtoNum(client_id)] = {59time: server.time,60...server.locs[0],61};62}63return servers;64};6566// Call this if you want the compute server with given id to67// connect and handle being the server for the given path.68connectComputeServerToPath = ({ id, path }: { id: number; path: string }) => {69if (id == 0) {70this.disconnectComputeServer({ path });71return;72}73assertSupportedPath(path);74this.sync_db.set({ id, path, open: true });75this.sync_db.commit();76};7778// Call this if you want no compute servers to provide the backend server79// for given path.80disconnectComputeServer = ({ path }: { path: string }) => {81this.sync_db.delete({ path });82this.sync_db.commit();83};8485// For interactive debugging -- display in the console how things are configured.86showStatus = () => {87console.log(JSON.stringify(this.sync_db.get().toJS(), undefined, 2));88};8990// Returns the explicitly set server id for the given91// path, if one is set. Otherwise, return undefined92// if nothing is explicitly set for this path.93getServerIdForPath = async (path: string): Promise<number | undefined> => {94const { sync_db } = this;95if (sync_db.get_state() == "init") {96await once(sync_db, "ready");97}98if (sync_db.get_state() != "ready") {99throw Error("syncdb not ready");100}101return sync_db.get_one({ path })?.get("id");102};103}104105function assertSupportedPath(path: string) {106if (excludeFromComputeServer(path)) {107throw Error(108`Opening '${path}' on a compute server is not yet supported -- copy it to the project and open it there instead`,109);110}111}112113const computeServerManagerCache: {114[project_id: string]: ComputeServersManager;115} = {};116117export const computeServers = (project_id: string) => {118if (computeServerManagerCache[project_id]) {119return computeServerManagerCache[project_id];120}121const m = new ComputeServersManager(project_id);122computeServerManagerCache[project_id] = m;123return m;124};125126export default computeServers;127128129