@cocalc/project
Version:
CoCalc: project daemon
104 lines • 4.04 kB
JavaScript
;
/*
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
* License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.status = exports.start = void 0;
const base_path_1 = __importDefault(require("@cocalc/backend/base-path"));
const data_1 = require("@cocalc/backend/data");
const data_2 = require("@cocalc/project/data");
const info_json_1 = require("@cocalc/project/info-json");
const logger_1 = require("@cocalc/project/logger");
const child_process_1 = require("child_process");
const fs_1 = require("fs");
const get_port_1 = __importDefault(require("get-port"));
const path_1 = require("path");
const util_1 = require("util");
const list_1 = __importDefault(require("./list"));
const mkdir = (0, util_1.promisify)(fs_1.mkdir);
const readFile = (0, util_1.promisify)(fs_1.readFile);
const writeFile = (0, util_1.promisify)(fs_1.writeFile);
const winston = (0, logger_1.getLogger)("named-servers:control");
// Returns the port or throws an exception.
async function start(name) {
winston.debug(`start ${name}`);
const s = await status(name);
if (s.status == "running") {
winston.debug(`${name} is already running`);
return s.port;
}
const port = await (0, get_port_1.default)({ port: preferredPort(name) });
// For servers that need a basePath, they will use this one.
// Other servers (e.g., Pluto, code-server) that don't need
// a basePath because they use only relative URL's are accessed
// via .../project_id/server/${port}.
let ip = info_json_1.INFO.location.host ?? "127.0.0.1";
if (ip == "localhost") {
ip = "127.0.0.1";
}
const base = (0, path_1.join)(base_path_1.default, `/${data_2.project_id}/port/${name}`);
const cmd = await getCommand(name, ip, port, base);
winston.debug(`will start ${name} by running "${cmd}"`);
const child = (0, child_process_1.exec)(cmd, { cwd: process.env.HOME });
const p = await paths(name);
await writeFile(p.port, `${port}`);
await writeFile(p.pid, `${child.pid}`);
await writeFile(p.command, `$!/bin/sh\n${cmd}\n`);
return port;
}
exports.start = start;
async function getCommand(name, ip, port, base) {
const { stdout, stderr } = await paths(name);
const spec = (0, list_1.default)(name);
const cmd = spec(ip, port, base);
return `${cmd} 1>${stdout} 2>${stderr}`;
}
// Returns the status and port (if defined).
async function status(name) {
const { pid, port } = await paths(name);
try {
const pidValue = parseInt((await readFile(pid)).toString());
// it might be running
process.kill(pidValue, 0); // throws error if NOT running
// it is running
const portValue = parseInt((await readFile(port)).toString());
// and there is a port file,
// and the port is a number.
if (!Number.isInteger(portValue)) {
throw Error("invalid port");
}
return { status: "running", port: portValue };
}
catch (_err) {
// it's not running or the port isn't valid
return { status: "stopped" };
}
}
exports.status = status;
async function paths(name) {
const path = (0, path_1.join)(data_1.data, "named_servers", name);
try {
await mkdir(path, { recursive: true });
}
catch (_err) {
// probably already exists
}
return {
pid: (0, path_1.join)(path, "pid"),
stderr: (0, path_1.join)(path, "stderr"),
stdout: (0, path_1.join)(path, "stdout"),
port: (0, path_1.join)(path, "port"),
command: (0, path_1.join)(path, "command.sh"),
};
}
function preferredPort(name) {
const p = process.env[`COCALC_${name.toUpperCase()}_PORT`];
if (p == null)
return p;
return parseInt(p);
}
//# sourceMappingURL=control.js.map