2025-10-19 12:57:17 +00:00
|
|
|
import process from 'node:process';
|
2025-10-19 13:14:18 +00:00
|
|
|
import { promises as fs } from 'node:fs';
|
|
|
|
import { execSync } from 'node:child_process';
|
2025-10-20 12:27:02 +00:00
|
|
|
import { NupstDaemon, type IUpsConfig } from './daemon.ts';
|
|
|
|
import { NupstSnmp } from './snmp/manager.ts';
|
2025-10-18 11:59:55 +00:00
|
|
|
import { logger } from './logger.ts';
|
2025-10-19 21:50:31 +00:00
|
|
|
import { theme, symbols, getBatteryColor, getRuntimeColor, formatPowerStatus } from './colors.ts';
|
2025-03-25 09:06:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class for managing systemd service
|
|
|
|
* Handles installation, removal, and control of the NUPST systemd service
|
|
|
|
*/
|
|
|
|
export class NupstSystemd {
|
|
|
|
/** Path to the systemd service file */
|
|
|
|
private readonly serviceFilePath = '/etc/systemd/system/nupst.service';
|
|
|
|
private readonly daemon: NupstDaemon;
|
|
|
|
|
|
|
|
/** Template for the systemd service file */
|
|
|
|
private readonly serviceTemplate = `[Unit]
|
2025-10-19 14:37:32 +00:00
|
|
|
Description=NUPST - Deno-powered UPS Monitoring Tool
|
2025-03-25 09:06:23 +00:00
|
|
|
After=network.target
|
|
|
|
|
|
|
|
[Service]
|
2025-10-19 14:37:32 +00:00
|
|
|
ExecStart=/usr/local/bin/nupst service start-daemon
|
2025-03-25 09:06:23 +00:00
|
|
|
Restart=always
|
2025-10-19 14:37:32 +00:00
|
|
|
RestartSec=10
|
2025-03-25 09:06:23 +00:00
|
|
|
User=root
|
|
|
|
Group=root
|
|
|
|
Environment=PATH=/usr/bin:/usr/local/bin
|
2025-10-19 14:37:32 +00:00
|
|
|
WorkingDirectory=/opt/nupst
|
2025-03-25 09:06:23 +00:00
|
|
|
|
|
|
|
[Install]
|
|
|
|
WantedBy=multi-user.target
|
|
|
|
`;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new systemd manager
|
|
|
|
* @param daemon The daemon instance to manage
|
|
|
|
*/
|
|
|
|
constructor(daemon: NupstDaemon) {
|
|
|
|
this.daemon = daemon;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a configuration file exists
|
|
|
|
* @private
|
|
|
|
* @throws Error if configuration not found
|
|
|
|
*/
|
|
|
|
private async checkConfigExists(): Promise<void> {
|
|
|
|
const configPath = '/etc/nupst/config.json';
|
|
|
|
try {
|
|
|
|
await fs.access(configPath);
|
|
|
|
} catch (error) {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
|
|
|
logger.error('No configuration found');
|
|
|
|
logger.log(` ${theme.dim('Config file:')} ${configPath}`);
|
|
|
|
logger.log(` ${theme.dim('Run')} ${theme.command('nupst ups add')} ${theme.dim('to create a configuration')}`);
|
|
|
|
logger.log('');
|
2025-03-25 09:06:23 +00:00
|
|
|
throw new Error('Configuration not found');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Install the systemd service file
|
|
|
|
* @throws Error if installation fails
|
|
|
|
*/
|
|
|
|
public async install(): Promise<void> {
|
|
|
|
try {
|
|
|
|
// Check if configuration exists before installing
|
|
|
|
await this.checkConfigExists();
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-25 09:06:23 +00:00
|
|
|
// Write the service file
|
|
|
|
await fs.writeFile(this.serviceFilePath, this.serviceTemplate);
|
2025-03-26 22:28:38 +00:00
|
|
|
const boxWidth = 50;
|
|
|
|
logger.logBoxTitle('Service Installation', boxWidth);
|
|
|
|
logger.logBoxLine(`Service file created at ${this.serviceFilePath}`);
|
2025-03-25 09:06:23 +00:00
|
|
|
|
|
|
|
// Reload systemd daemon
|
|
|
|
execSync('systemctl daemon-reload');
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.logBoxLine('Systemd daemon reloaded');
|
2025-03-25 09:06:23 +00:00
|
|
|
|
|
|
|
// Enable the service
|
|
|
|
execSync('systemctl enable nupst.service');
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.logBoxLine('Service enabled to start on boot');
|
|
|
|
logger.logBoxEnd();
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-10-18 21:07:57 +00:00
|
|
|
if (error instanceof Error && error.message === 'Configuration not found') {
|
2025-03-25 09:06:23 +00:00
|
|
|
// Just rethrow the error as the message has already been displayed
|
|
|
|
throw error;
|
|
|
|
}
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.error(`Failed to install systemd service: ${error}`);
|
2025-03-25 09:06:23 +00:00
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start the systemd service
|
|
|
|
* @throws Error if start fails
|
|
|
|
*/
|
|
|
|
public async start(): Promise<void> {
|
|
|
|
try {
|
|
|
|
// Check if configuration exists before starting
|
|
|
|
await this.checkConfigExists();
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-25 09:06:23 +00:00
|
|
|
execSync('systemctl start nupst.service');
|
2025-03-26 22:28:38 +00:00
|
|
|
const boxWidth = 45;
|
|
|
|
logger.logBoxTitle('Service Status', boxWidth);
|
|
|
|
logger.logBoxLine('NUPST service started successfully');
|
|
|
|
logger.logBoxEnd();
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-10-18 21:07:57 +00:00
|
|
|
if (error instanceof Error && error.message === 'Configuration not found') {
|
2025-03-25 09:06:23 +00:00
|
|
|
// Exit with error code since configuration is required
|
|
|
|
process.exit(1);
|
|
|
|
}
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.error(`Failed to start service: ${error}`);
|
2025-03-25 09:06:23 +00:00
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the systemd service
|
|
|
|
* @throws Error if stop fails
|
|
|
|
*/
|
2025-10-19 13:25:01 +00:00
|
|
|
public stop(): void {
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
|
|
|
execSync('systemctl stop nupst.service');
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.success('NUPST service stopped');
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.error(`Failed to stop service: ${error}`);
|
2025-03-25 09:06:23 +00:00
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get status of the systemd service and UPS
|
2025-03-25 10:27:08 +00:00
|
|
|
* @param debugMode Whether to enable debug mode for SNMP
|
2025-03-25 09:06:23 +00:00
|
|
|
*/
|
2025-10-20 01:01:06 +00:00
|
|
|
/**
|
|
|
|
* Display version information and update status
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
private async displayVersionInfo(): Promise<void> {
|
|
|
|
try {
|
|
|
|
const nupst = this.daemon.getNupstSnmp().getNupst();
|
|
|
|
const version = nupst.getVersion();
|
|
|
|
|
|
|
|
// Check for updates
|
|
|
|
const updateAvailable = await nupst.checkForUpdates();
|
|
|
|
|
|
|
|
// Display version info
|
|
|
|
if (updateAvailable) {
|
|
|
|
const updateStatus = nupst.getUpdateStatus();
|
|
|
|
logger.log('');
|
|
|
|
logger.log(
|
|
|
|
`${theme.dim('NUPST')} ${theme.dim('v' + version)} ${symbols.warning} ${theme.statusWarning(`Update available: v${updateStatus.latestVersion}`)}`,
|
|
|
|
);
|
|
|
|
logger.log(` ${theme.dim('Run')} ${theme.command('sudo nupst update')} ${theme.dim('to upgrade')}`);
|
|
|
|
} else {
|
|
|
|
logger.log('');
|
|
|
|
logger.log(
|
|
|
|
`${theme.dim('NUPST')} ${theme.dim('v' + version)} ${symbols.success} ${theme.success('Up to date')}`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
// If version check fails, show at least the current version
|
|
|
|
try {
|
|
|
|
const nupst = this.daemon.getNupstSnmp().getNupst();
|
|
|
|
const version = nupst.getVersion();
|
|
|
|
logger.log('');
|
|
|
|
logger.log(`${theme.dim('NUPST')} ${theme.dim('v' + version)}`);
|
|
|
|
} catch (_innerError) {
|
|
|
|
// Silently fail if we can't even get the version
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-25 10:27:08 +00:00
|
|
|
public async getStatus(debugMode: boolean = false): Promise<void> {
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
2025-03-25 10:27:08 +00:00
|
|
|
// Enable debug mode if requested
|
|
|
|
if (debugMode) {
|
2025-10-19 23:01:25 +00:00
|
|
|
console.log('');
|
|
|
|
logger.info('Debug Mode: SNMP debugging enabled');
|
|
|
|
console.log('');
|
2025-03-25 10:27:08 +00:00
|
|
|
this.daemon.getNupstSnmp().enableDebug();
|
|
|
|
}
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-10-20 01:01:06 +00:00
|
|
|
// Display version and update status first
|
|
|
|
await this.displayVersionInfo();
|
|
|
|
|
|
|
|
// Check if config exists
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
|
|
|
await this.checkConfigExists();
|
|
|
|
} catch (error) {
|
|
|
|
// Error message already displayed by checkConfigExists
|
|
|
|
return;
|
|
|
|
}
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-25 09:06:23 +00:00
|
|
|
await this.displayServiceStatus();
|
2025-03-28 16:19:43 +00:00
|
|
|
await this.displayAllUpsStatus();
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-10-19 13:14:18 +00:00
|
|
|
logger.error(
|
|
|
|
`Failed to get status: ${error instanceof Error ? error.message : String(error)}`,
|
|
|
|
);
|
2025-03-25 09:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Display the systemd service status
|
|
|
|
* @private
|
|
|
|
*/
|
2025-10-19 13:25:01 +00:00
|
|
|
private displayServiceStatus(): void {
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
|
|
|
const serviceStatus = execSync('systemctl status nupst.service').toString();
|
2025-10-19 21:50:31 +00:00
|
|
|
const lines = serviceStatus.split('\n');
|
|
|
|
|
|
|
|
// Parse key information from systemctl output
|
|
|
|
let isActive = false;
|
|
|
|
let pid = '';
|
|
|
|
let memory = '';
|
|
|
|
let cpu = '';
|
|
|
|
|
|
|
|
for (const line of lines) {
|
|
|
|
if (line.includes('Active:')) {
|
|
|
|
isActive = line.includes('active (running)');
|
|
|
|
} else if (line.includes('Main PID:')) {
|
|
|
|
const match = line.match(/Main PID:\s+(\d+)/);
|
|
|
|
if (match) pid = match[1];
|
|
|
|
} else if (line.includes('Memory:')) {
|
|
|
|
const match = line.match(/Memory:\s+([\d.]+[A-Z])/);
|
|
|
|
if (match) memory = match[1];
|
|
|
|
} else if (line.includes('CPU:')) {
|
|
|
|
const match = line.match(/CPU:\s+([\d.]+(?:ms|s))/);
|
|
|
|
if (match) cpu = match[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display beautiful status
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
2025-10-19 21:50:31 +00:00
|
|
|
if (isActive) {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(`${symbols.running} ${theme.success('Service:')} ${theme.statusActive('active (running)')}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
} else {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(`${symbols.stopped} ${theme.dim('Service:')} ${theme.statusInactive('inactive')}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pid || memory || cpu) {
|
|
|
|
const details = [];
|
|
|
|
if (pid) details.push(`PID: ${theme.dim(pid)}`);
|
|
|
|
if (memory) details.push(`Memory: ${theme.dim(memory)}`);
|
|
|
|
if (cpu) details.push(`CPU: ${theme.dim(cpu)}`);
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(` ${details.join(' ')}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
}
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
2025-10-19 21:50:31 +00:00
|
|
|
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
|
|
|
logger.log(`${symbols.stopped} ${theme.dim('Service:')} ${theme.statusInactive('not installed')}`);
|
|
|
|
logger.log('');
|
2025-03-25 09:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-03-28 16:19:43 +00:00
|
|
|
* Display all UPS statuses
|
2025-03-25 09:06:23 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2025-03-28 16:19:43 +00:00
|
|
|
private async displayAllUpsStatus(): Promise<void> {
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
2025-03-25 10:27:08 +00:00
|
|
|
// Explicitly load the configuration first to ensure it's up-to-date
|
|
|
|
await this.daemon.loadConfig();
|
2025-03-25 09:49:30 +00:00
|
|
|
const config = this.daemon.getConfig();
|
2025-03-25 09:06:23 +00:00
|
|
|
const snmp = this.daemon.getNupstSnmp();
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-28 16:19:43 +00:00
|
|
|
// Check if we have the new multi-UPS config format
|
|
|
|
if (config.upsDevices && Array.isArray(config.upsDevices) && config.upsDevices.length > 0) {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.info(`UPS Devices (${config.upsDevices.length}):`);
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-28 16:19:43 +00:00
|
|
|
// Show status for each UPS
|
|
|
|
for (const ups of config.upsDevices) {
|
|
|
|
await this.displaySingleUpsStatus(ups, snmp);
|
|
|
|
}
|
|
|
|
} else if (config.snmp) {
|
2025-10-20 12:27:02 +00:00
|
|
|
// Legacy single UPS configuration (v1/v2 format)
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.info('UPS Devices (1):');
|
2025-10-20 12:27:02 +00:00
|
|
|
const legacyUps: IUpsConfig = {
|
2025-03-28 16:19:43 +00:00
|
|
|
id: 'default',
|
|
|
|
name: 'Default UPS',
|
|
|
|
snmp: config.snmp,
|
2025-10-19 13:14:18 +00:00
|
|
|
groups: [],
|
2025-10-20 12:27:02 +00:00
|
|
|
actions: config.thresholds
|
|
|
|
? [
|
|
|
|
{
|
|
|
|
type: 'shutdown',
|
|
|
|
thresholds: config.thresholds,
|
|
|
|
triggerMode: 'onlyThresholds',
|
|
|
|
shutdownDelay: 5,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
: [],
|
2025-03-28 16:19:43 +00:00
|
|
|
};
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-28 16:19:43 +00:00
|
|
|
await this.displaySingleUpsStatus(legacyUps, snmp);
|
|
|
|
} else {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
|
|
|
logger.warn('No UPS devices configured');
|
|
|
|
logger.log(` ${theme.dim('Run')} ${theme.command('nupst ups add')} ${theme.dim('to add a device')}`);
|
|
|
|
logger.log('');
|
2025-03-28 16:19:43 +00:00
|
|
|
}
|
|
|
|
} catch (error) {
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
|
|
|
logger.error('Failed to retrieve UPS status');
|
|
|
|
logger.log(` ${theme.dim(error instanceof Error ? error.message : String(error))}`);
|
|
|
|
logger.log('');
|
2025-03-28 16:19:43 +00:00
|
|
|
}
|
|
|
|
}
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-28 16:19:43 +00:00
|
|
|
/**
|
|
|
|
* Display status of a single UPS
|
|
|
|
* @param ups UPS configuration
|
|
|
|
* @param snmp SNMP manager
|
|
|
|
*/
|
2025-10-20 12:27:02 +00:00
|
|
|
private async displaySingleUpsStatus(ups: IUpsConfig, snmp: NupstSnmp): Promise<void> {
|
2025-03-28 16:19:43 +00:00
|
|
|
try {
|
|
|
|
// Create a test config with a short timeout
|
|
|
|
const testConfig = {
|
|
|
|
...ups.snmp,
|
2025-10-19 13:14:18 +00:00
|
|
|
timeout: Math.min(ups.snmp.timeout, 10000), // Use at most 10 seconds for status check
|
2025-03-28 16:19:43 +00:00
|
|
|
};
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-28 16:19:43 +00:00
|
|
|
const status = await snmp.getUpsStatus(testConfig);
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-10-19 21:50:31 +00:00
|
|
|
// Determine status symbol based on power status
|
|
|
|
let statusSymbol = symbols.unknown;
|
|
|
|
if (status.powerStatus === 'online') {
|
|
|
|
statusSymbol = symbols.running;
|
|
|
|
} else if (status.powerStatus === 'onBattery') {
|
|
|
|
statusSymbol = symbols.warning;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display UPS name and power status
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(` ${statusSymbol} ${theme.highlight(ups.name)} - ${formatPowerStatus(status.powerStatus)}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
|
|
|
|
// Display battery with color coding
|
|
|
|
const batteryColor = getBatteryColor(status.batteryCapacity);
|
2025-10-20 12:20:40 +00:00
|
|
|
|
|
|
|
// Get threshold from actions (if any action has thresholds defined)
|
2025-10-20 12:27:02 +00:00
|
|
|
const actionWithThresholds = ups.actions?.find((action) => action.thresholds);
|
2025-10-20 12:20:40 +00:00
|
|
|
const batteryThreshold = actionWithThresholds?.thresholds?.battery;
|
|
|
|
const batterySymbol = batteryThreshold !== undefined && status.batteryCapacity >= batteryThreshold
|
|
|
|
? symbols.success
|
|
|
|
: batteryThreshold !== undefined
|
|
|
|
? symbols.warning
|
|
|
|
: '';
|
|
|
|
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(` Battery: ${batteryColor(status.batteryCapacity + '%')} ${batterySymbol} Runtime: ${getRuntimeColor(status.batteryRuntime)(status.batteryRuntime + ' min')}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
|
|
|
|
// Display host info
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(` ${theme.dim(`Host: ${ups.snmp.host}:${ups.snmp.port}`)}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
|
|
|
|
// Display groups if any
|
|
|
|
if (ups.groups && ups.groups.length > 0) {
|
|
|
|
const config = this.daemon.getConfig();
|
|
|
|
const groupNames = ups.groups.map((groupId: string) => {
|
|
|
|
const group = config.groups?.find((g: { id: string }) => g.id === groupId);
|
|
|
|
return group ? group.name : groupId;
|
|
|
|
});
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(` ${theme.dim(`Groups: ${groupNames.join(', ')}`)}`);
|
2025-10-19 21:50:31 +00:00
|
|
|
}
|
|
|
|
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log('');
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-10-19 21:50:31 +00:00
|
|
|
// Display error for this UPS
|
2025-10-20 00:32:06 +00:00
|
|
|
logger.log(` ${symbols.error} ${theme.highlight(ups.name)} - ${theme.error('Connection failed')}`);
|
|
|
|
logger.log(` ${theme.dim(error instanceof Error ? error.message : String(error))}`);
|
|
|
|
logger.log(` ${theme.dim(`Host: ${ups.snmp.host}:${ups.snmp.port}`)}`);
|
|
|
|
logger.log('');
|
2025-03-25 09:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disable and uninstall the systemd service
|
|
|
|
* @throws Error if disabling fails
|
|
|
|
*/
|
|
|
|
public async disable(): Promise<void> {
|
|
|
|
try {
|
|
|
|
await this.stopService();
|
|
|
|
await this.disableService();
|
|
|
|
await this.removeServiceFile();
|
2025-10-19 13:14:18 +00:00
|
|
|
|
2025-03-25 09:06:23 +00:00
|
|
|
// Reload systemd daemon
|
|
|
|
execSync('systemctl daemon-reload');
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Systemd daemon reloaded');
|
|
|
|
logger.success('NUPST service has been successfully uninstalled');
|
2025-03-25 09:06:23 +00:00
|
|
|
} catch (error) {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.error(`Failed to disable and uninstall service: ${error}`);
|
2025-03-25 09:06:23 +00:00
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the service if it's running
|
|
|
|
* @private
|
|
|
|
*/
|
2025-10-19 13:25:01 +00:00
|
|
|
private stopService(): void {
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Stopping NUPST service...');
|
2025-03-25 09:06:23 +00:00
|
|
|
execSync('systemctl stop nupst.service');
|
|
|
|
} catch (error) {
|
|
|
|
// Service might not be running, that's okay
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Service was not running or could not be stopped');
|
2025-03-25 09:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disable the service
|
|
|
|
* @private
|
|
|
|
*/
|
2025-10-19 13:25:01 +00:00
|
|
|
private disableService(): void {
|
2025-03-25 09:06:23 +00:00
|
|
|
try {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Disabling NUPST service...');
|
2025-03-25 09:06:23 +00:00
|
|
|
execSync('systemctl disable nupst.service');
|
|
|
|
} catch (error) {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Service was not enabled or could not be disabled');
|
2025-03-25 09:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove the service file if it exists
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
private async removeServiceFile(): Promise<void> {
|
|
|
|
if (await fs.stat(this.serviceFilePath).catch(() => null)) {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log(`Removing service file ${this.serviceFilePath}...`);
|
2025-03-25 09:06:23 +00:00
|
|
|
await fs.unlink(this.serviceFilePath);
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Service file removed');
|
2025-03-25 09:06:23 +00:00
|
|
|
} else {
|
2025-03-26 22:28:38 +00:00
|
|
|
logger.log('Service file did not exist');
|
2025-03-25 09:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
2025-10-19 13:14:18 +00:00
|
|
|
}
|