mirror of
https://github.com/logos-storage/logos-storage-installer.git
synced 2026-01-05 23:13:06 +00:00
cleanup processControl
This commit is contained in:
parent
7661d829cb
commit
5fcb55015a
@ -15,6 +15,7 @@ export const mockConfigService = {
|
|||||||
get: vi.fn(),
|
get: vi.fn(),
|
||||||
saveConfig: vi.fn(),
|
saveConfig: vi.fn(),
|
||||||
loadConfig: vi.fn(),
|
loadConfig: vi.fn(),
|
||||||
|
writeCodexConfigFile: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockFsService = {
|
export const mockFsService = {
|
||||||
@ -32,6 +33,7 @@ export const mockFsService = {
|
|||||||
|
|
||||||
export const mockShellService = {
|
export const mockShellService = {
|
||||||
run: vi.fn(),
|
run: vi.fn(),
|
||||||
|
spawnDetachedProcess: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockOsService = {
|
export const mockOsService = {
|
||||||
@ -39,4 +41,10 @@ export const mockOsService = {
|
|||||||
isDarwin: vi.fn(),
|
isDarwin: vi.fn(),
|
||||||
isLinux: vi.fn(),
|
isLinux: vi.fn(),
|
||||||
getWorkingDir: vi.fn(),
|
getWorkingDir: vi.fn(),
|
||||||
|
listProcesses: vi.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mockCodexGlobals = {
|
||||||
|
getPublicIp: vi.fn(),
|
||||||
|
getTestnetSPRs: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,95 +1,49 @@
|
|||||||
import fs from "fs";
|
|
||||||
import { spawn, exec } from "child_process";
|
|
||||||
import psList from 'ps-list';
|
|
||||||
|
|
||||||
export class ProcessControl {
|
export class ProcessControl {
|
||||||
constructor(configService, shellService, osService, fsService) {
|
constructor(configService, shellService, osService, fsService, codexGlobals) {
|
||||||
this.configService = configService;
|
this.configService = configService;
|
||||||
this.config = configService.get();
|
this.config = configService.get();
|
||||||
this.shell = shellService;
|
this.shell = shellService;
|
||||||
this.os = osService;
|
this.os = osService;
|
||||||
this.fs = fsService;
|
this.fs = fsService;
|
||||||
|
this.codexGlobals;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPublicIp = async () => {
|
getCodexProcesses = async () => {
|
||||||
|
const processes = await this.os.listProcesses();
|
||||||
if (this.os.isWindows()) {
|
if (this.os.isWindows()) {
|
||||||
const result = await this.shell.run(
|
return processes.filter((p) => p.name === "codex.exe");
|
||||||
"for /f \"delims=\" %a in ('curl -s --ssl-reqd ip.codex.storage') do @echo %a",
|
|
||||||
);
|
|
||||||
return result.trim();
|
|
||||||
} else {
|
} else {
|
||||||
return await this.shell.run("curl -s https://ip.codex.storage");
|
return processes.filter((p) => p.name === "codex");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
detectThing = async () => {
|
getNumberOfCodexProcesses = async () => {
|
||||||
console.log("detecting...");
|
return (await this.getCodexProcesses()).length;
|
||||||
|
};
|
||||||
|
|
||||||
const processes = await psList();
|
stopCodexProcess = async () => {
|
||||||
const codexProcesses = processes.filter((p) => p.name === "codex.exe");
|
const processes = await this.getCodexProcesses();
|
||||||
if (codexProcesses.length > 0) {
|
if (processes.length < 1) throw new Error("No codex process found");
|
||||||
console.log("Codex is already running.");
|
|
||||||
codexProcesses.forEach((p) => {
|
|
||||||
console.log(`PID: ${JSON.stringify(p)}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Stopping codex...");
|
|
||||||
await this.stopThing(codexProcesses[0].pid);
|
|
||||||
await this.detectThing();
|
|
||||||
} else {
|
|
||||||
console.log("Codex is not running.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stopThing = async (pid) => {
|
|
||||||
console.log("stopping process...");
|
|
||||||
|
|
||||||
|
const pid = processes[0].pid;
|
||||||
process.kill(pid, "SIGINT");
|
process.kill(pid, "SIGINT");
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
}
|
};
|
||||||
|
|
||||||
doThing = async () => {
|
startCodexProcess = async () => {
|
||||||
if (this.config.dataDir.length < 1)
|
this.saveCodexConfigFile();
|
||||||
throw new Error("Missing config: dataDir");
|
this.startCodex();
|
||||||
if (this.config.logsDir.length < 1)
|
};
|
||||||
throw new Error("Missing config: logsDir");
|
|
||||||
|
|
||||||
console.log("start a codex detached");
|
saveCodexConfigFile = async () => {
|
||||||
|
const publicIp = await this.codexGlobals.getPublicIp();
|
||||||
|
const bootstrapNodes = await this.codexGlobals.getTestnetSPRs();
|
||||||
|
this.configService.writeCodexConfigFile(publicIp, bootstrapNodes);
|
||||||
|
};
|
||||||
|
|
||||||
|
startCodex = async () => {
|
||||||
const executable = this.config.codexExe;
|
const executable = this.config.codexExe;
|
||||||
const args = [`--config-file=${this.config.codexConfigFilePath}`];
|
const args = [`--config-file=${this.config.codexConfigFilePath}`];
|
||||||
const bootstrapNodes = [
|
await this.shell.spawnDetachedProcess(executable, args);
|
||||||
"spr:CiUIAhIhAiJvIcA_ZwPZ9ugVKDbmqwhJZaig5zKyLiuaicRcCGqLEgIDARo8CicAJQgCEiECIm8hwD9nA9n26BUoNuarCEllqKDnMrIuK5qJxFwIaosQ3d6esAYaCwoJBJ_f8zKRAnU6KkYwRAIgM0MvWNJL296kJ9gWvfatfmVvT-A7O2s8Mxp8l9c8EW0CIC-h-H-jBVSgFjg3Eny2u33qF7BDnWFzo7fGfZ7_qc9P",
|
|
||||||
];
|
|
||||||
const publicIp = await this.getPublicIp();
|
|
||||||
|
|
||||||
this.configService.writeCodexConfigFile(publicIp, bootstrapNodes);
|
|
||||||
|
|
||||||
const command = `"${executable}" ${args.join(" ")}`;
|
|
||||||
console.log("command: " + command);
|
|
||||||
console.log("\n\n");
|
|
||||||
|
|
||||||
var child = spawn(executable, args, {
|
|
||||||
detached: true,
|
|
||||||
//stdio: ["ignore", "ignore", "ignore"],
|
|
||||||
});
|
|
||||||
|
|
||||||
child.stdout.on("data", (data) => {
|
|
||||||
console.log(`stdout: ${data}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.stderr.on("data", (data) => {
|
|
||||||
console.error(`stderr: ${data}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.on("close", (code) => {
|
|
||||||
console.log(`child process exited with code ${code}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
child.unref();
|
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,7 @@ import { Installer } from "./handlers/installer.js";
|
|||||||
import { ShellService } from "./services/shellService.js";
|
import { ShellService } from "./services/shellService.js";
|
||||||
import { OsService } from "./services/osService.js";
|
import { OsService } from "./services/osService.js";
|
||||||
import { ProcessControl } from "./handlers/processControl.js";
|
import { ProcessControl } from "./handlers/processControl.js";
|
||||||
|
import { CodexGlobals } from "./services/codexGlobals.js";
|
||||||
|
|
||||||
async function showNavigationMenu() {
|
async function showNavigationMenu() {
|
||||||
console.log("\n");
|
console.log("\n");
|
||||||
@ -133,14 +134,20 @@ export async function main() {
|
|||||||
new DataDirMover(fsService, uiService),
|
new DataDirMover(fsService, uiService),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const codexGlobals = new CodexGlobals();
|
||||||
|
|
||||||
const processControl = new ProcessControl(
|
const processControl = new ProcessControl(
|
||||||
configService,
|
configService,
|
||||||
shellService,
|
shellService,
|
||||||
osService,
|
osService,
|
||||||
fsService,
|
fsService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log("ip: " + (await codexGlobals.getPublicIp()));
|
||||||
|
console.log("spr: " + (await codexGlobals.getTestnetSprs()));
|
||||||
|
|
||||||
//await processControl.doThing();
|
//await processControl.doThing();
|
||||||
await processControl.detectThing();
|
// await processControl.detectThing();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await mainMenu.show();
|
await mainMenu.show();
|
||||||
|
|||||||
12
src/services/codexGlobals.js
Normal file
12
src/services/codexGlobals.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export class CodexGlobals {
|
||||||
|
getPublicIp = async () => {
|
||||||
|
return (await axios.get(`https://ip.codex.storage`)).data;
|
||||||
|
};
|
||||||
|
|
||||||
|
getTestnetSPRs = async () => {
|
||||||
|
const result = (await axios.get(`https://spr.codex.storage/testnet`)).data;
|
||||||
|
return result.split("\n").filter((line) => line.length > 0);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -77,7 +77,23 @@ export class ConfigService {
|
|||||||
return this.fs.pathJoin([this.config.logsDir, "codex.log"]);
|
return this.fs.pathJoin([this.config.logsDir, "codex.log"]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
missing = (name) => {
|
||||||
|
throw new Error(`Missing config value: ${name}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
validateConfiguration = () => {
|
||||||
|
if (this.config.codexExe.length < 1) this.missing("codexExe");
|
||||||
|
if (this.config.codexConfigFilePath.length < 1)
|
||||||
|
this.missing("codexConfigFilePath");
|
||||||
|
if (this.config.dataDir.length < 1) this.missing("dataDir");
|
||||||
|
if (this.config.logsDir.length < 1) this.missing("logsDir");
|
||||||
|
if (this.config.storageQuota < 1024 * 1024 * 100)
|
||||||
|
throw new Error("Storage quota must be at least 100MB");
|
||||||
|
};
|
||||||
|
|
||||||
writeCodexConfigFile = (publicIp, bootstrapNodes) => {
|
writeCodexConfigFile = (publicIp, bootstrapNodes) => {
|
||||||
|
this.validateConfiguration();
|
||||||
|
|
||||||
const nl = "\n";
|
const nl = "\n";
|
||||||
const bootNodes = bootstrapNodes.map((v) => `"${v}"`).join(",");
|
const bootNodes = bootstrapNodes.map((v) => `"${v}"`).join(",");
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import os from "os";
|
import os from "os";
|
||||||
|
import psList from "ps-list";
|
||||||
|
|
||||||
export class OsService {
|
export class OsService {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -20,4 +21,8 @@ export class OsService {
|
|||||||
getWorkingDir = () => {
|
getWorkingDir = () => {
|
||||||
return process.cwd();
|
return process.cwd();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
listProcesses = async () => {
|
||||||
|
await psList();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { exec } from "child_process";
|
import { exec, spawn } from "child_process";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
|
|
||||||
export class ShellService {
|
export class ShellService {
|
||||||
@ -6,7 +6,7 @@ export class ShellService {
|
|||||||
this.execAsync = promisify(exec);
|
this.execAsync = promisify(exec);
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(command) {
|
run = async (command) => {
|
||||||
try {
|
try {
|
||||||
const { stdout, stderr } = await this.execAsync(command);
|
const { stdout, stderr } = await this.execAsync(command);
|
||||||
return stdout;
|
return stdout;
|
||||||
@ -14,5 +14,28 @@ export class ShellService {
|
|||||||
console.error("Error:", error.message);
|
console.error("Error:", error.message);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
spawnDetachedProcess = async (cmd, args) => {
|
||||||
|
var child = spawn(cmd, args, {
|
||||||
|
detached: true,
|
||||||
|
stdio: ["ignore", "ignore", "ignore"],
|
||||||
|
});
|
||||||
|
|
||||||
|
// child.stdout.on("data", (data) => {
|
||||||
|
// console.log(`stdout: ${data}`);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// child.stderr.on("data", (data) => {
|
||||||
|
// console.error(`stderr: ${data}`);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// child.on("close", (code) => {
|
||||||
|
// console.log(`child process exited with code ${code}`);
|
||||||
|
// });
|
||||||
|
|
||||||
|
child.unref();
|
||||||
|
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user