mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-01 12:52:11 +03:00
Extrai 7 grupos de comandos do monolito bin/cli-commands.mjs (2853 linhas)
para módulos individuais em bin/cli/commands/, registrados via Commander.
- stop.mjs: SIGTERM/SIGKILL via process.kill(); fallback por porta usa execFile
com array de args (evita injeção de shell / Semgrep CWE-78)
- restart.mjs: delega para runStopCommand + runServe
- dashboard.mjs: alias "open", fallback nativo por plataforma via execFile
- keys.mjs: server-first (POST /api/v1/providers/keys) → DB fallback; valida
provider via loadAvailableProviders(); suporte a --stdin
- models.mjs: GET /api/models → fallback /api/v1/models; filtro por provider e --search
- combo.mjs: list/switch/create/delete; switch server-first → DB fallback via key_value;
TODO(1.5) marcados para substituir SQL cru por src/lib/db/combos.ts
- serve.mjs: escreve PID via writePidFile() no spawn; limpa no shutdown; suporte daemon
utils/pid.mjs e i18n keys (en.json + pt-BR.json) já criados em iteração anterior.
Testes: cli-keys-command.test.ts atualizado para novos runners;
cli-serve-stop-command.test.ts, cli-combo-command.test.ts,
cli-models-command.test.ts adicionados (23 testes, 0 falhas).
66 lines
1.5 KiB
JavaScript
66 lines
1.5 KiB
JavaScript
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
import { dirname, join } from "node:path";
|
|
import { resolveDataDir } from "../data-dir.mjs";
|
|
|
|
export function getPidFilePath() {
|
|
return join(resolveDataDir(), "server.pid");
|
|
}
|
|
|
|
export function writePidFile(pid) {
|
|
try {
|
|
const pidPath = getPidFilePath();
|
|
const dir = dirname(pidPath);
|
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
writeFileSync(pidPath, String(pid), "utf8");
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function readPidFile() {
|
|
try {
|
|
const pidPath = getPidFilePath();
|
|
if (!existsSync(pidPath)) return null;
|
|
const content = readFileSync(pidPath, "utf8").trim();
|
|
return content ? parseInt(content, 10) : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function isPidRunning(pid) {
|
|
if (!pid) return false;
|
|
try {
|
|
process.kill(pid, 0);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function cleanupPidFile() {
|
|
try {
|
|
const pidPath = getPidFilePath();
|
|
if (existsSync(pidPath)) unlinkSync(pidPath);
|
|
} catch {}
|
|
}
|
|
|
|
export function sleep(ms) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
export async function waitForServer(port, timeout = 15000) {
|
|
const start = Date.now();
|
|
while (Date.now() - start < timeout) {
|
|
try {
|
|
const res = await fetch(`http://localhost:${port}/api/health`, {
|
|
signal: AbortSignal.timeout(2000),
|
|
});
|
|
if (res.ok) return true;
|
|
} catch {}
|
|
await sleep(500);
|
|
}
|
|
return false;
|
|
}
|