diff --git a/instance/daemon.ts b/instance/daemon.ts index 53364eb..ce14c0b 100755 --- a/instance/daemon.ts +++ b/instance/daemon.ts @@ -9,21 +9,11 @@ const log = log_from("daemon"); if (import.meta.main) await main(); async function main() { - const state = await create_state(); + const state = await State.load(); 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()); - Deno.exit(0); - } + const finish = termination_function(state, server.server); Deno.addSignalListener("SIGINT", finish); for await (const { cmd, respond } of server) { @@ -87,43 +77,67 @@ async function main() { } } -async function create_state() { - const self = { - enabled: new Map(), - async enable(name: string) { - if (self.enabled.has(name)) throw new Error("Container already enabled"); - log("loading container", name); - const config = await ContainerConfig.load(name); // TODO - if (config === null) throw new Error("can't read config"); - log("starting container", name); - const runner = new Runner(config); - runner.start(); - self.enabled.set(name, runner); - 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); +class State { + enabled; + + constructor() { + this.enabled = new Map(); + } + + static async load() { + const result = new State(); + 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 result.enable(name); + } + log("successfully loaded from", state_path()); + } catch (error) { + log("experienced failure", error); + } + return result; + } + + async enable(name: string) { + if (this.enabled.has(name)) throw new Error("Container already enabled"); + log("loading container", name); + const config = await ContainerConfig.load(name); // TODO + if (config === null) throw new Error("can't read config"); + log("starting container", name); + const runner = new Runner(config); + runner.start(); + this.enabled.set(name, runner); + log("container", name, "started"); + } + + async disable(name: string) { + const container = this.enabled.get(name); + if (container === undefined) throw new Error("Container not found"); + await container.stop(); + this.enabled.delete(name); + } + + list() { + return Array.from(this.enabled.keys()); + } + + async save() { + const content = JSON.stringify({ enabled: this.list() }); + await Deno.writeTextFile(state_path(), content); } - return self; +} + +function termination_function(state: State, server: Deno.Listener) { + return async function finish() { + log("stopping"); + server.close(); + for (const runner of state.enabled.values()) { + try { + await runner.stop(); + } catch (_) { /* on s'en fou */ } + } + await Deno.remove(socket_path()); + Deno.exit(0); + }; }