124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
export type { Base, BaseContext } from "./lib/create.ts";
|
|
|
|
import { toText } from "https://deno.land/std@0.208.0/streams/to_text.ts";
|
|
import { lines, log_from, loop_process, LoopProcess, run } from "./lib/utils.ts";
|
|
import { ContainerConfig } from "./lib/config.ts";
|
|
import { container_paths } from "./lib/paths.ts";
|
|
import { container_command, stop_container } from "./lib/nspawn.ts";
|
|
import { NginxController } from "./lib/nginx.ts";
|
|
|
|
const log = log_from("lib");
|
|
|
|
export type CmdStatus = ReturnType<typeof new_cmd_status>;
|
|
export function new_cmd_status() {
|
|
return { kind: "status" as const };
|
|
}
|
|
|
|
export type CmdEnable = ReturnType<typeof new_cmd_enable>;
|
|
export function new_cmd_enable(name: string) {
|
|
return { kind: "enable" as const, name };
|
|
}
|
|
|
|
export type CmdDisable = ReturnType<typeof new_cmd_disable>;
|
|
export function new_cmd_disable(name: string) {
|
|
return { kind: "disable" as const, name };
|
|
}
|
|
|
|
export type CmdReload = ReturnType<typeof new_cmd_reload>;
|
|
export function new_cmd_reload(name: string) {
|
|
return { kind: "reload" as const, name };
|
|
}
|
|
|
|
export type CmdStop = ReturnType<typeof new_cmd_stop>;
|
|
export function new_cmd_stop() {
|
|
return { kind: "stop" as const };
|
|
}
|
|
|
|
export type Cmd = CmdStatus | CmdEnable | CmdDisable | CmdReload | CmdStop;
|
|
|
|
export async function daemon_listen(sock_path: string) {
|
|
const server = Deno.listen({ transport: "unix", path: sock_path });
|
|
await Deno.chmod(sock_path, 0o775);
|
|
await run("chgrp", "wheel", sock_path);
|
|
const generator = async function* () {
|
|
for await (const request of server) {
|
|
const respond = async (message: string) => {
|
|
try {
|
|
await request.write(new TextEncoder().encode(message));
|
|
} catch (_) { /* bof mais bon */ }
|
|
};
|
|
try {
|
|
for await (const line of lines(request.readable)) {
|
|
const cmd = JSON.parse(line) as Cmd;
|
|
yield { cmd, respond };
|
|
}
|
|
} catch (_) { /* ok tier */ }
|
|
}
|
|
};
|
|
const result = generator() as ReturnType<typeof generator> & { server: typeof server };
|
|
result.server = server;
|
|
return result;
|
|
}
|
|
|
|
export async function daemon_send(sock_path: string, command: Cmd) {
|
|
const request = await Deno.connect({ transport: "unix", path: sock_path });
|
|
const text = JSON.stringify(command) + "\r\n\r\n";
|
|
await request.write(new TextEncoder().encode(text));
|
|
return await toText(request.readable);
|
|
}
|
|
|
|
export class Runner {
|
|
name;
|
|
config;
|
|
nginx;
|
|
loop;
|
|
|
|
constructor(config: ContainerConfig, nginx: NginxController) {
|
|
this.name = config.name;
|
|
this.config = config;
|
|
this.nginx = nginx;
|
|
this.loop = null as LoopProcess | null;
|
|
}
|
|
|
|
async start() {
|
|
await stop_container(this.name);
|
|
await this.update_proxies();
|
|
this.start_process();
|
|
}
|
|
|
|
private start_process() {
|
|
const paths = container_paths(this.name);
|
|
const command = container_command(this.name, paths.root, {
|
|
boot: true,
|
|
veth: true,
|
|
redirections: this.config.redirections,
|
|
cmd_opts: {
|
|
stdin: "null",
|
|
stdout: "null",
|
|
},
|
|
syscall_filter: ["add_key", "keyctl", "bpf"],
|
|
});
|
|
this.loop = loop_process(command, {
|
|
on_start: () => log("container", this.name, "started"),
|
|
on_stop: () => log("container", this.name, "stopped"),
|
|
});
|
|
}
|
|
|
|
async stop() {
|
|
await this.loop?.kill();
|
|
}
|
|
|
|
async update_proxies() {
|
|
const paths = container_paths(this.name);
|
|
await Deno.mkdir(paths.sites, { recursive: true });
|
|
const sites = new Set<string>();
|
|
for (const redir of this.config.redirections) {
|
|
if (redir.kind !== "http") continue;
|
|
await this.nginx.add_proxy(redir.domain, redir.port, paths.sites, redir.tls);
|
|
sites.add(redir.domain);
|
|
}
|
|
for await (const domains of this.nginx.read_all_in_dir(paths.sites)) {
|
|
if (!sites.has(domains)) this.nginx.remove_proxy(domains, paths.sites);
|
|
}
|
|
}
|
|
}
|