1import { execFile, spawn } from "node:child_process";
2import { watch } from "node:fs";
3import { promisify } from "node:util";
4
5const host = process.env.STUDIO_DEPLOY_HOST ?? "root@127.0.0.1";
6const ssh = ["-p", process.env.STUDIO_DEPLOY_PORT ?? "2222", "-o", "BatchMode=yes", "-o", "ConnectTimeout=8"];
7const dir = "/root/studio-dashboard-dev";
8const run = promisify(execFile);
9const quote = (value: string) => "'" + value.replaceAll("'", "'\\''") + "'";
10const restart = `import os, shlex, subprocess
11variables = dict(item.split("=", 1) for item in shlex.split(subprocess.check_output(["systemctl", "show", "-P", "Environment", "studio-dashboard"], text=True)))
12for key in ["STUDIO_INDEX_POOL", "STUDIO_YT_STATE", "STUDIO_FILES_WRITABLE"]: variables.pop(key, None)
13variables.update(PORT="7070", STUDIO_METRICS="follow", STUDIO_DATA_DIR="${dir}/data")
14subprocess.run(["systemctl", "stop", "studio-dashboard-dev"], check=False)
15subprocess.run(["systemd-run", "--unit=studio-dashboard-dev", "--collect", "--property=WorkingDirectory=${dir}/result/lib/home-dashboard", *["--setenv="+key+"="+value for key,value in variables.items()], "${dir}/result/bin/home-dashboard"], check=True)`;
16let pending = false;
17let rebuilding = false;
18async function rebuild() {
19 pending = true;
20 if (rebuilding) return;
21 rebuilding = true;
22 try {
23 while (pending) {
24 pending = false;
25 await run("rsync", ["-a", "--delete", ...[".jj", ".git", "node_modules", "target", "dist", ".cache", "data", "result"].map(name => "--exclude=" + name), "-e", ["ssh", ...ssh].join(" "), "../", `${host}:${dir}/`]);
26 await run("ssh", [...ssh, host, `cd ${dir} && nix --extra-experimental-features 'nix-command flakes' build path:.#dashboard --cores 2 --max-jobs 1 -o result && python3 -c ${quote(restart)}`], { maxBuffer: 16 * 1024 * 1024 });
27 console.log("Rust dashboard ready");
28 }
29 } finally { rebuilding = false; }
30}
31await rebuild();
32watch("src", { recursive: true }, () => rebuild().catch(console.error));
33const tunnel = spawn("ssh", [...ssh, "-N", "-o", "ExitOnForwardFailure=yes", "-L", "7070:127.0.0.1:7070", host], { stdio: "inherit" });
34tunnel.on("exit", code => process.exit(code ?? 1));
35for (const signal of ["SIGINT", "SIGTERM"] as const) process.on(signal, () => {
36 run("ssh", [...ssh, host, "systemctl stop studio-dashboard-dev"]).finally(() => tunnel.kill());
37});