stabilize, add daemon state, add base build script

This commit is contained in:
JOLIMAITRE Matthieu 2023-12-10 22:04:40 +01:00
parent a1963cf491
commit 241d50e42a
12 changed files with 512 additions and 46 deletions

View file

@ -1,50 +1,127 @@
#!/bin/env -S deno run -A --unstable
import { daemon_listen, Runner, start_runner } from "./src/lib.ts";
import { new_container_config } from "./src/lib/config.ts";
import { socket_path } from "./src/lib/paths.ts";
import { load_container_config } from "./src/lib/config.ts";
import { socket_path, state_path } from "./src/lib/paths.ts";
import { log_from, sleep } from "./src/lib/utils.ts";
await main();
const log = log_from("daemon");
if (import.meta.main) await main();
async function main() {
const server = daemon_listen(socket_path());
const enabled = new Map<string, Runner>();
const state = await create_state();
const server = await daemon_listen(socket_path());
log("listening to", socket_path());
async function finish() {
log("stopping");
server.server.close();
for (const runner of state.enabled.values()) {
try {
await runner.stop();
} catch (_) { /* on s'en fou */ }
}
await Deno.remove(socket_path());
for (const runner of enabled.values()) await runner.stop();
Deno.exit(0);
}
Deno.addSignalListener("SIGINT", finish);
console.log("listening to", socket_path());
for await (const { cmd, respond } of server) {
console.log("received", { cmd });
log("received", cmd);
if (cmd.kind === "status") {
await respond(JSON.stringify(Array.from(enabled.keys())));
await respond(JSON.stringify(state.list()));
continue;
}
if (cmd.kind === "enable") {
const config = new_container_config(cmd.name); // TODO
const runner = start_runner(config);
enabled.set(cmd.name, runner);
await respond("enabled");
(async () => {
try {
await state.enable(cmd.name);
await state.save();
await respond("enabled");
} catch (error) {
log("experienced failure", error);
await respond(`${error}`);
}
})();
continue;
}
if (cmd.kind === "disable") {
await enabled.get(cmd.name)?.stop();
enabled.delete(cmd.name);
await respond("disabled");
(async () => {
try {
await state.disable(cmd.name);
await state.save();
await respond("disabled");
} catch (error) {
log("experienced failure", error);
await respond(`${error}`);
}
})();
continue;
}
if (cmd.kind === "reload") {
(async () => {
try {
await state.disable(cmd.name);
await sleep(500);
await state.enable(cmd.name);
await respond("reloaded");
} catch (error) {
log("experienced failure", error);
await respond(`${error}`);
}
})();
continue;
}
if (cmd.kind === "stop") {
await respond(JSON.stringify("stopping, ++"));
await state.save();
await respond("adios");
await finish();
}
await respond("unknown");
await respond("unknown command");
}
}
async function create_state() {
const self = {
enabled: new Map<string, Runner>(),
async enable(name: string) {
if (self.enabled.has(name)) throw new Error("Container already enabled");
log("loading container", name);
const config = await load_container_config(name); // TODO
if (config === null) throw new Error("can't read config");
log("starting container", name);
self.enabled.set(name, await start_runner(config));
log("container", name, "started");
},
async disable(name: string) {
const container = self.enabled.get(name);
if (container === undefined) throw new Error("Container not found");
await container.stop();
self.enabled.delete(name);
},
list() {
return Array.from(self.enabled.keys());
},
async save() {
const content = JSON.stringify({ enabled: self.list() });
await Deno.writeTextFile(state_path(), content);
},
};
try {
log("trying to recover state from", state_path());
const loaded = JSON.parse(await Deno.readTextFile(state_path()));
for (const name of loaded.enabled ?? []) {
await self.enable(name);
}
log("successfully loaded from", state_path());
} catch (error) {
log("experienced failure", error);
}
return self;
}