diff --git a/server/routes/actions.ts b/server/routes/actions.ts new file mode 100644 index 0000000..ba858d7 --- /dev/null +++ b/server/routes/actions.ts @@ -0,0 +1,32 @@ +// server/routes/actions.ts +import { Hono } from "hono"; +import { readFileSync } from "node:fs"; +import { runAction, listExecutions, getExecution } from "../services/execute.js"; +import type { ActionType } from "@shared/types.js"; + +export const actionsRoutes = new Hono(); + +actionsRoutes.post("/:id/actions", async (c) => { + const { action } = (await c.req.json()) as { action: ActionType }; + if (action !== "apt_full_upgrade" && action !== "reboot") { + return c.json({ error: "Action non autorisée" }, 400); + } + // Exécution lancée en arrière-plan; le suivi se fait via WebSocket. + runAction(c.req.param("id"), action).catch((err) => + console.error("[action]", (err as Error).message), + ); + return c.json({ ok: true, action }, 202); +}); + +actionsRoutes.get("/:id/executions", (c) => c.json(listExecutions(c.req.param("id")))); + +actionsRoutes.get("/:id/executions/:execId", (c) => { + const e = getExecution(c.req.param("execId")); + return e ? c.json(e) : c.json({ error: "Exécution introuvable" }, 404); +}); + +actionsRoutes.get("/:id/executions/:execId/report", (c) => { + const e = getExecution(c.req.param("execId")); + if (!e?.reportPath) return c.json({ error: "Rapport introuvable" }, 404); + return c.text(readFileSync(e.reportPath, "utf8")); +}); diff --git a/server/routes/index.ts b/server/routes/index.ts new file mode 100644 index 0000000..f399bcb --- /dev/null +++ b/server/routes/index.ts @@ -0,0 +1,8 @@ +// server/routes/index.ts +import { Hono } from "hono"; +import { machinesRoutes } from "./machines.js"; +import { actionsRoutes } from "./actions.js"; + +export const api = new Hono(); +api.route("/machines", machinesRoutes); +api.route("/machines", actionsRoutes); diff --git a/server/routes/machines.ts b/server/routes/machines.ts new file mode 100644 index 0000000..169d71d --- /dev/null +++ b/server/routes/machines.ts @@ -0,0 +1,49 @@ +// server/routes/machines.ts +import { Hono } from "hono"; +import { + listMachines, createMachine, deleteMachine, getMachineRow, getCreds, testConnection, + type CreateMachineInput, +} from "../services/machines.js"; +import { refreshMachine, getLatestSnapshot } from "../services/refresh.js"; + +export const machinesRoutes = new Hono(); + +machinesRoutes.get("/", (c) => c.json(listMachines())); + +machinesRoutes.post("/", async (c) => { + const body = (await c.req.json()) as CreateMachineInput; + try { + const m = await createMachine(body); + return c.json(m, 201); + } catch (err) { + return c.json({ error: `Connexion échouée: ${(err as Error).message}` }, 400); + } +}); + +machinesRoutes.post("/:id/test-connection", async (c) => { + const m = getMachineRow(c.req.param("id")); + if (!m) return c.json({ error: "Machine introuvable" }, 404); + try { + return c.json(await testConnection(getCreds(m))); + } catch (err) { + return c.json({ error: (err as Error).message }, 400); + } +}); + +machinesRoutes.get("/:id/snapshot", (c) => { + const snap = getLatestSnapshot(c.req.param("id")); + return snap ? c.json(snap) : c.json({ error: "Aucun snapshot" }, 404); +}); + +machinesRoutes.post("/:id/refresh", async (c) => { + try { + return c.json(await refreshMachine(c.req.param("id"))); + } catch (err) { + return c.json({ error: (err as Error).message }, 400); + } +}); + +machinesRoutes.delete("/:id", (c) => { + deleteMachine(c.req.param("id")); + return c.json({ ok: true }); +});