Files
2026-04-29 19:48:14 +00:00

78 lines
2.2 KiB
TypeScript

import { DEFAULT_CONFIG_PATH } from './config.ts';
const SERVICE_FILE_PATH = '/etc/systemd/system/uptimerunner.service';
export class UptimeRunnerSystemd {
private readonly serviceTemplate = `[Unit]
Description=uptime.link Runner Agent
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/uptimerunner run --config ${DEFAULT_CONFIG_PATH}
Restart=always
RestartSec=10
User=root
Group=root
Environment=PATH=/usr/bin:/usr/local/bin
WorkingDirectory=/opt/uptimerunner
[Install]
WantedBy=multi-user.target
`;
public async install(): Promise<void> {
this.assertRoot();
await Deno.writeTextFile(SERVICE_FILE_PATH, this.serviceTemplate);
await run('systemctl', ['daemon-reload']);
await run('systemctl', ['enable', 'uptimerunner.service']);
console.log(`Service installed: ${SERVICE_FILE_PATH}`);
}
public async uninstall(): Promise<void> {
this.assertRoot();
await run('systemctl', ['disable', '--now', 'uptimerunner.service']).catch(() => null);
await Deno.remove(SERVICE_FILE_PATH).catch(() => null);
await run('systemctl', ['daemon-reload']);
console.log('Service removed.');
}
public async start(): Promise<void> {
await run('systemctl', ['start', 'uptimerunner.service']);
}
public async stop(): Promise<void> {
await run('systemctl', ['stop', 'uptimerunner.service']);
}
public async restart(): Promise<void> {
await run('systemctl', ['restart', 'uptimerunner.service']);
}
public async status(): Promise<void> {
await run('systemctl', ['status', 'uptimerunner.service', '--no-pager']);
}
public async logs(): Promise<void> {
await run('journalctl', ['-u', 'uptimerunner.service', '-n', '120', '--no-pager']);
}
private assertRoot(): void {
if (Deno.uid && Deno.uid() !== 0) {
throw new Error('This service command must run as root.');
}
}
}
async function run(commandArg: string, argsArg: string[]): Promise<void> {
const command = new Deno.Command(commandArg, {
args: argsArg,
stdout: 'inherit',
stderr: 'inherit',
});
const output = await command.output();
if (!output.success) {
throw new Error(`${commandArg} ${argsArg.join(' ')} exited with ${output.code}`);
}
}