986 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			986 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { execSync } from 'child_process';
 | 
						|
import { Nupst } from '../nupst.js';
 | 
						|
import { logger } from '../logger.js';
 | 
						|
import * as helpers from '../helpers/index.js';
 | 
						|
 | 
						|
/**
 | 
						|
 * Class for handling UPS-related CLI commands
 | 
						|
 * Provides interface for managing UPS devices
 | 
						|
 */
 | 
						|
export class UpsHandler {
 | 
						|
  private readonly nupst: Nupst;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a new UPS handler
 | 
						|
   * @param nupst Reference to the main Nupst instance
 | 
						|
   */
 | 
						|
  constructor(nupst: Nupst) {
 | 
						|
    this.nupst = nupst;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Add a new UPS configuration
 | 
						|
   */
 | 
						|
  public async add(): Promise<void> {
 | 
						|
    try {
 | 
						|
      // Import readline module for user input
 | 
						|
      const readline = await import('readline');
 | 
						|
 | 
						|
      const rl = readline.createInterface({
 | 
						|
        input: process.stdin,
 | 
						|
        output: process.stdout,
 | 
						|
      });
 | 
						|
 | 
						|
      // Helper function to prompt for input
 | 
						|
      const prompt = (question: string): Promise<string> => {
 | 
						|
        return new Promise((resolve) => {
 | 
						|
          rl.question(question, (answer: string) => {
 | 
						|
            resolve(answer);
 | 
						|
          });
 | 
						|
        });
 | 
						|
      };
 | 
						|
 | 
						|
      try {
 | 
						|
        await this.runAddProcess(prompt);
 | 
						|
      } finally {
 | 
						|
        rl.close();
 | 
						|
      }
 | 
						|
    } catch (error) {
 | 
						|
      logger.error(`Add UPS error: ${error.message}`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Run the interactive process to add a new UPS
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  public async runAddProcess(prompt: (question: string) => Promise<string>): Promise<void> {
 | 
						|
    logger.log('\nNUPST Add UPS');
 | 
						|
    logger.log('=============\n');
 | 
						|
    logger.log('This will guide you through configuring a new UPS.\n');
 | 
						|
 | 
						|
    // Try to load existing config if available
 | 
						|
    let config;
 | 
						|
    try {
 | 
						|
      await this.nupst.getDaemon().loadConfig();
 | 
						|
      config = this.nupst.getDaemon().getConfig();
 | 
						|
      
 | 
						|
      // Convert old format to new format if needed
 | 
						|
      if (!config.upsDevices) {
 | 
						|
        // Initialize with the current config as the first UPS
 | 
						|
        config = {
 | 
						|
          checkInterval: config.checkInterval,
 | 
						|
          upsDevices: [{
 | 
						|
            id: 'default',
 | 
						|
            name: 'Default UPS',
 | 
						|
            snmp: config.snmp,
 | 
						|
            thresholds: config.thresholds,
 | 
						|
            groups: []
 | 
						|
          }],
 | 
						|
          groups: []
 | 
						|
        };
 | 
						|
        logger.log('Converting existing configuration to multi-UPS format.');
 | 
						|
      }
 | 
						|
    } catch (error) {
 | 
						|
      // If config doesn't exist, initialize with empty config
 | 
						|
      config = {
 | 
						|
        checkInterval: 30000, // Default check interval
 | 
						|
        upsDevices: [],
 | 
						|
        groups: []
 | 
						|
      };
 | 
						|
      logger.log('No existing configuration found. Creating a new configuration.');
 | 
						|
    }
 | 
						|
 | 
						|
    // Get UPS ID and name
 | 
						|
    const upsId = helpers.shortId();
 | 
						|
    const name = await prompt('UPS Name: ');
 | 
						|
 | 
						|
    // Create a new UPS configuration object with defaults
 | 
						|
    const newUps = {
 | 
						|
      id: upsId,
 | 
						|
      name: name || `UPS-${upsId}`,
 | 
						|
      snmp: {
 | 
						|
        host: '127.0.0.1',
 | 
						|
        port: 161,
 | 
						|
        community: 'public',
 | 
						|
        version: 1,
 | 
						|
        timeout: 5000,
 | 
						|
        upsModel: 'cyberpower'
 | 
						|
      },
 | 
						|
      thresholds: {
 | 
						|
        battery: 60,
 | 
						|
        runtime: 20
 | 
						|
      },
 | 
						|
      groups: []
 | 
						|
    };
 | 
						|
 | 
						|
    // Gather SNMP settings
 | 
						|
    await this.gatherSnmpSettings(newUps.snmp, prompt);
 | 
						|
 | 
						|
    // Gather threshold settings
 | 
						|
    await this.gatherThresholdSettings(newUps.thresholds, prompt);
 | 
						|
 | 
						|
    // Gather UPS model settings
 | 
						|
    await this.gatherUpsModelSettings(newUps.snmp, prompt);
 | 
						|
 | 
						|
    // Get access to GroupHandler for group assignments
 | 
						|
    const groupHandler = this.nupst.getGroupHandler();
 | 
						|
 | 
						|
    // Assign to groups if any exist
 | 
						|
    if (config.groups && config.groups.length > 0) {
 | 
						|
      await groupHandler.assignUpsToGroups(newUps, config.groups, prompt);
 | 
						|
    }
 | 
						|
 | 
						|
    // Add the new UPS to the config
 | 
						|
    config.upsDevices.push(newUps);
 | 
						|
 | 
						|
    // Save the configuration
 | 
						|
    await this.nupst.getDaemon().saveConfig(config);
 | 
						|
 | 
						|
    this.displayUpsConfigSummary(newUps);
 | 
						|
 | 
						|
    // Test the connection if requested
 | 
						|
    await this.optionallyTestConnection(newUps.snmp, prompt);
 | 
						|
    
 | 
						|
    // Check if service is running and restart it if needed
 | 
						|
    await this.restartServiceIfRunning();
 | 
						|
    
 | 
						|
    logger.log('\nSetup complete!');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Edit an existing UPS configuration
 | 
						|
   * @param upsId ID of the UPS to edit (undefined for default UPS)
 | 
						|
   */
 | 
						|
  public async edit(upsId?: string): Promise<void> {
 | 
						|
    try {
 | 
						|
      // Import readline module for user input
 | 
						|
      const readline = await import('readline');
 | 
						|
 | 
						|
      const rl = readline.createInterface({
 | 
						|
        input: process.stdin,
 | 
						|
        output: process.stdout,
 | 
						|
      });
 | 
						|
 | 
						|
      // Helper function to prompt for input
 | 
						|
      const prompt = (question: string): Promise<string> => {
 | 
						|
        return new Promise((resolve) => {
 | 
						|
          rl.question(question, (answer: string) => {
 | 
						|
            resolve(answer);
 | 
						|
          });
 | 
						|
        });
 | 
						|
      };
 | 
						|
 | 
						|
      try {
 | 
						|
        await this.runEditProcess(upsId, prompt);
 | 
						|
      } finally {
 | 
						|
        rl.close();
 | 
						|
      }
 | 
						|
    } catch (error) {
 | 
						|
      logger.error(`Edit UPS error: ${error.message}`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Run the interactive process to edit a UPS
 | 
						|
   * @param upsId ID of the UPS to edit (undefined for default UPS)
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  public async runEditProcess(upsId: string | undefined, prompt: (question: string) => Promise<string>): Promise<void> {
 | 
						|
    logger.log('\nNUPST Edit UPS');
 | 
						|
    logger.log('=============\n');
 | 
						|
    
 | 
						|
    // Try to load existing config
 | 
						|
    try {
 | 
						|
      await this.nupst.getDaemon().loadConfig();
 | 
						|
    } catch (error) {
 | 
						|
      if (!upsId) {
 | 
						|
        // For default UPS (no ID specified), run setup if no config exists
 | 
						|
        logger.log('No existing configuration found. Running setup for new UPS.');
 | 
						|
        await this.runAddProcess(prompt);
 | 
						|
        return;
 | 
						|
      } else {
 | 
						|
        // For specific UPS ID, error if config doesn't exist
 | 
						|
        logger.error('No configuration found. Please run "nupst setup" first.');
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Get the config
 | 
						|
    const config = this.nupst.getDaemon().getConfig();
 | 
						|
    
 | 
						|
    // Convert old format to new format if needed
 | 
						|
    if (!config.upsDevices) {
 | 
						|
      // Initialize with the current config as the first UPS
 | 
						|
      config.upsDevices = [{
 | 
						|
        id: 'default',
 | 
						|
        name: 'Default UPS',
 | 
						|
        snmp: config.snmp,
 | 
						|
        thresholds: config.thresholds,
 | 
						|
        groups: []
 | 
						|
      }];
 | 
						|
      config.groups = [];
 | 
						|
      logger.log('Converting existing configuration to multi-UPS format.');
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Find the UPS to edit
 | 
						|
    let upsToEdit;
 | 
						|
    if (upsId) {
 | 
						|
      // Find specific UPS by ID
 | 
						|
      upsToEdit = config.upsDevices.find(ups => ups.id === upsId);
 | 
						|
      if (!upsToEdit) {
 | 
						|
        logger.error(`UPS with ID "${upsId}" not found.`);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      logger.log(`Editing UPS: ${upsToEdit.name} (${upsToEdit.id})\n`);
 | 
						|
    } else {
 | 
						|
      // For backward compatibility, edit the first UPS if no ID specified
 | 
						|
      if (config.upsDevices.length === 0) {
 | 
						|
        logger.error('No UPS devices configured. Please run "nupst add" to add a UPS.');
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      upsToEdit = config.upsDevices[0];
 | 
						|
      logger.log(`Editing default UPS: ${upsToEdit.name} (${upsToEdit.id})\n`);
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Allow editing UPS name
 | 
						|
    const newName = await prompt(`UPS Name [${upsToEdit.name}]: `);
 | 
						|
    if (newName.trim()) {
 | 
						|
      upsToEdit.name = newName;
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Edit SNMP settings
 | 
						|
    await this.gatherSnmpSettings(upsToEdit.snmp, prompt);
 | 
						|
    
 | 
						|
    // Edit threshold settings
 | 
						|
    await this.gatherThresholdSettings(upsToEdit.thresholds, prompt);
 | 
						|
    
 | 
						|
    // Edit UPS model settings
 | 
						|
    await this.gatherUpsModelSettings(upsToEdit.snmp, prompt);
 | 
						|
    
 | 
						|
    // Get access to GroupHandler for group assignments
 | 
						|
    const groupHandler = this.nupst.getGroupHandler();
 | 
						|
    
 | 
						|
    // Edit group assignments
 | 
						|
    if (config.groups && config.groups.length > 0) {
 | 
						|
      await groupHandler.assignUpsToGroups(upsToEdit, config.groups, prompt);
 | 
						|
    }
 | 
						|
    
 | 
						|
    // Save the configuration
 | 
						|
    await this.nupst.getDaemon().saveConfig(config);
 | 
						|
    
 | 
						|
    this.displayUpsConfigSummary(upsToEdit);
 | 
						|
    
 | 
						|
    // Test the connection if requested
 | 
						|
    await this.optionallyTestConnection(upsToEdit.snmp, prompt);
 | 
						|
    
 | 
						|
    // Check if service is running and restart it if needed
 | 
						|
    await this.restartServiceIfRunning();
 | 
						|
    
 | 
						|
    logger.log('\nEdit complete!');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Delete a UPS by ID
 | 
						|
   * @param upsId ID of the UPS to delete
 | 
						|
   */
 | 
						|
  public async delete(upsId: string): Promise<void> {
 | 
						|
    try {
 | 
						|
      // Try to load configuration
 | 
						|
      try {
 | 
						|
        await this.nupst.getDaemon().loadConfig();
 | 
						|
      } catch (error) {
 | 
						|
        const errorBoxWidth = 45;
 | 
						|
        logger.logBoxTitle('Configuration Error', errorBoxWidth);
 | 
						|
        logger.logBoxLine('No configuration found.');
 | 
						|
        logger.logBoxLine("Please run 'nupst setup' first to create a configuration.");
 | 
						|
        logger.logBoxEnd();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Get current configuration
 | 
						|
      const config = this.nupst.getDaemon().getConfig();
 | 
						|
      
 | 
						|
      // Check if multi-UPS config
 | 
						|
      if (!config.upsDevices || !Array.isArray(config.upsDevices)) {
 | 
						|
        logger.error('Legacy single-UPS configuration detected. Cannot delete UPS.');
 | 
						|
        logger.log('Use "nupst add" to migrate to multi-UPS configuration format first.');
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Find the UPS to delete
 | 
						|
      const upsIndex = config.upsDevices.findIndex(ups => ups.id === upsId);
 | 
						|
      if (upsIndex === -1) {
 | 
						|
        logger.error(`UPS with ID "${upsId}" not found.`);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
      const upsToDelete = config.upsDevices[upsIndex];
 | 
						|
      
 | 
						|
      // Get confirmation before deleting
 | 
						|
      const readline = await import('readline');
 | 
						|
      const rl = readline.createInterface({
 | 
						|
        input: process.stdin,
 | 
						|
        output: process.stdout,
 | 
						|
      });
 | 
						|
      
 | 
						|
      const confirm = await new Promise<string>(resolve => {
 | 
						|
        rl.question(`Are you sure you want to delete UPS "${upsToDelete.name}" (${upsId})? [y/N]: `, answer => {
 | 
						|
          resolve(answer.toLowerCase());
 | 
						|
        });
 | 
						|
      });
 | 
						|
      
 | 
						|
      rl.close();
 | 
						|
      
 | 
						|
      if (confirm !== 'y' && confirm !== 'yes') {
 | 
						|
        logger.log('Deletion cancelled.');
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Remove the UPS from the array
 | 
						|
      config.upsDevices.splice(upsIndex, 1);
 | 
						|
      
 | 
						|
      // Save the configuration
 | 
						|
      await this.nupst.getDaemon().saveConfig(config);
 | 
						|
      
 | 
						|
      logger.log(`UPS "${upsToDelete.name}" (${upsId}) has been deleted.`);
 | 
						|
      
 | 
						|
      // Check if service is running and restart it if needed
 | 
						|
      await this.restartServiceIfRunning();
 | 
						|
    } catch (error) {
 | 
						|
      logger.error(`Failed to delete UPS: ${error.message}`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * List all configured UPS devices
 | 
						|
   */
 | 
						|
  public async list(): Promise<void> {
 | 
						|
    try {
 | 
						|
      // Try to load configuration
 | 
						|
      try {
 | 
						|
        await this.nupst.getDaemon().loadConfig();
 | 
						|
      } catch (error) {
 | 
						|
        const errorBoxWidth = 45;
 | 
						|
        logger.logBoxTitle('Configuration Error', errorBoxWidth);
 | 
						|
        logger.logBoxLine('No configuration found.');
 | 
						|
        logger.logBoxLine("Please run 'nupst setup' first to create a configuration.");
 | 
						|
        logger.logBoxEnd();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Get current configuration
 | 
						|
      const config = this.nupst.getDaemon().getConfig();
 | 
						|
      
 | 
						|
      // Check if multi-UPS config
 | 
						|
      if (!config.upsDevices || !Array.isArray(config.upsDevices)) {
 | 
						|
        // Legacy single UPS configuration
 | 
						|
        const boxWidth = 45;
 | 
						|
        logger.logBoxTitle('UPS Devices', boxWidth);
 | 
						|
        logger.logBoxLine('Legacy single-UPS configuration detected.');
 | 
						|
        logger.logBoxLine('');
 | 
						|
        logger.logBoxLine('Default UPS:');
 | 
						|
        logger.logBoxLine(`  Host: ${config.snmp.host}:${config.snmp.port}`);
 | 
						|
        logger.logBoxLine(`  Model: ${config.snmp.upsModel || 'cyberpower'}`);
 | 
						|
        logger.logBoxLine(`  Thresholds: ${config.thresholds.battery}% battery, ${config.thresholds.runtime} min runtime`);
 | 
						|
        logger.logBoxLine('');
 | 
						|
        logger.logBoxLine('Use "nupst add" to add more UPS devices and migrate');
 | 
						|
        logger.logBoxLine('to the multi-UPS configuration format.');
 | 
						|
        logger.logBoxEnd();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
      // Display UPS list
 | 
						|
      const boxWidth = 60;
 | 
						|
      logger.logBoxTitle('UPS Devices', boxWidth);
 | 
						|
      
 | 
						|
      if (config.upsDevices.length === 0) {
 | 
						|
        logger.logBoxLine('No UPS devices configured.');
 | 
						|
        logger.logBoxLine('Use "nupst add" to add a UPS device.');
 | 
						|
      } else {
 | 
						|
        logger.logBoxLine(`Found ${config.upsDevices.length} UPS device(s)`);
 | 
						|
        logger.logBoxLine('');
 | 
						|
        logger.logBoxLine('ID         | Name                 | Host            | Mode         | Groups');
 | 
						|
        logger.logBoxLine('-----------+----------------------+-----------------+--------------+----------------');
 | 
						|
        
 | 
						|
        for (const ups of config.upsDevices) {
 | 
						|
          const id = ups.id.padEnd(10, ' ').substring(0, 10);
 | 
						|
          const name = (ups.name || '').padEnd(20, ' ').substring(0, 20);
 | 
						|
          const host = `${ups.snmp.host}:${ups.snmp.port}`.padEnd(15, ' ').substring(0, 15);
 | 
						|
          const model = (ups.snmp.upsModel || 'cyberpower').padEnd(12, ' ').substring(0, 12);
 | 
						|
          const groups = ups.groups.length > 0 ? ups.groups.join(', ') : 'None';
 | 
						|
          
 | 
						|
          logger.logBoxLine(`${id} | ${name} | ${host} | ${model} | ${groups}`);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      
 | 
						|
      logger.logBoxEnd();
 | 
						|
    } catch (error) {
 | 
						|
      logger.error(`Failed to list UPS devices: ${error.message}`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Test the current configuration by connecting to the UPS
 | 
						|
   * @param debugMode Whether to enable debug mode
 | 
						|
   */
 | 
						|
  public async test(debugMode: boolean = false): Promise<void> {
 | 
						|
    try {
 | 
						|
      // Debug mode is now handled in parseAndExecute
 | 
						|
      if (debugMode) {
 | 
						|
        const boxWidth = 45;
 | 
						|
        logger.logBoxTitle('Debug Mode', boxWidth);
 | 
						|
        logger.logBoxLine('SNMP debugging enabled - detailed logs will be shown');
 | 
						|
        logger.logBoxEnd();
 | 
						|
      }
 | 
						|
 | 
						|
      // Try to load the configuration
 | 
						|
      try {
 | 
						|
        await this.nupst.getDaemon().loadConfig();
 | 
						|
      } catch (error) {
 | 
						|
        const errorBoxWidth = 45;
 | 
						|
        logger.logBoxTitle('Configuration Error', errorBoxWidth);
 | 
						|
        logger.logBoxLine('No configuration found.');
 | 
						|
        logger.logBoxLine("Please run 'nupst setup' first to create a configuration.");
 | 
						|
        logger.logBoxEnd();
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      // Get current configuration
 | 
						|
      const config = this.nupst.getDaemon().getConfig();
 | 
						|
 | 
						|
      // Handle new multi-UPS configuration format
 | 
						|
      if (config.upsDevices && config.upsDevices.length > 0) {
 | 
						|
        logger.log(`Found ${config.upsDevices.length} UPS devices in configuration.`);
 | 
						|
        
 | 
						|
        for (let i = 0; i < config.upsDevices.length; i++) {
 | 
						|
          const ups = config.upsDevices[i];
 | 
						|
          logger.log(`\nTesting UPS: ${ups.name} (${ups.id})`);
 | 
						|
          this.displayTestConfig(ups);
 | 
						|
          await this.testConnection(ups);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        // Legacy configuration format
 | 
						|
        this.displayTestConfig(config);
 | 
						|
        await this.testConnection(config);
 | 
						|
      }
 | 
						|
    } catch (error) {
 | 
						|
      logger.error(`Test failed: ${error.message}`);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Display the configuration for testing
 | 
						|
   * @param config Current configuration or individual UPS configuration
 | 
						|
   */
 | 
						|
  private displayTestConfig(config: any): void {
 | 
						|
    // Check if this is a UPS device or full configuration
 | 
						|
    const isUpsConfig = config.snmp && config.thresholds;
 | 
						|
    const snmpConfig = isUpsConfig ? config.snmp : config.snmp || {};
 | 
						|
    const thresholds = isUpsConfig ? config.thresholds : config.thresholds || {};
 | 
						|
    const checkInterval = config.checkInterval || 30000;
 | 
						|
    
 | 
						|
    // Get UPS name and ID if available
 | 
						|
    const upsName = config.name ? config.name : 'Default UPS';
 | 
						|
    const upsId = config.id ? config.id : 'default';
 | 
						|
    
 | 
						|
    const boxWidth = 45;
 | 
						|
    logger.logBoxTitle(`Testing Configuration: ${upsName}`, boxWidth);
 | 
						|
    logger.logBoxLine(`UPS ID: ${upsId}`);
 | 
						|
    logger.logBoxLine('SNMP Settings:');
 | 
						|
    logger.logBoxLine(`  Host: ${snmpConfig.host}`);
 | 
						|
    logger.logBoxLine(`  Port: ${snmpConfig.port}`);
 | 
						|
    logger.logBoxLine(`  Version: ${snmpConfig.version}`);
 | 
						|
    logger.logBoxLine(`  UPS Model: ${snmpConfig.upsModel || 'cyberpower'}`);
 | 
						|
 | 
						|
    if (snmpConfig.version === 1 || snmpConfig.version === 2) {
 | 
						|
      logger.logBoxLine(`  Community: ${snmpConfig.community}`);
 | 
						|
    } else if (snmpConfig.version === 3) {
 | 
						|
      logger.logBoxLine(`  Security Level: ${snmpConfig.securityLevel}`);
 | 
						|
      logger.logBoxLine(`  Username: ${snmpConfig.username}`);
 | 
						|
 | 
						|
      // Show auth and privacy details based on security level
 | 
						|
      if (snmpConfig.securityLevel === 'authNoPriv' || snmpConfig.securityLevel === 'authPriv') {
 | 
						|
        logger.logBoxLine(`  Auth Protocol: ${snmpConfig.authProtocol || 'None'}`);
 | 
						|
      }
 | 
						|
 | 
						|
      if (snmpConfig.securityLevel === 'authPriv') {
 | 
						|
        logger.logBoxLine(`  Privacy Protocol: ${snmpConfig.privProtocol || 'None'}`);
 | 
						|
      }
 | 
						|
 | 
						|
      // Show timeout value
 | 
						|
      logger.logBoxLine(`  Timeout: ${snmpConfig.timeout / 1000} seconds`);
 | 
						|
    }
 | 
						|
 | 
						|
    // Show OIDs if custom model is selected
 | 
						|
    if (snmpConfig.upsModel === 'custom' && snmpConfig.customOIDs) {
 | 
						|
      logger.logBoxLine('Custom OIDs:');
 | 
						|
      logger.logBoxLine(`  Power Status: ${snmpConfig.customOIDs.POWER_STATUS || 'Not set'}`);
 | 
						|
      logger.logBoxLine(`  Battery Capacity: ${snmpConfig.customOIDs.BATTERY_CAPACITY || 'Not set'}`);
 | 
						|
      logger.logBoxLine(`  Battery Runtime: ${snmpConfig.customOIDs.BATTERY_RUNTIME || 'Not set'}`);
 | 
						|
    }
 | 
						|
    logger.logBoxLine('Thresholds:');
 | 
						|
    logger.logBoxLine(`  Battery: ${thresholds.battery}%`);
 | 
						|
    logger.logBoxLine(`  Runtime: ${thresholds.runtime} minutes`);
 | 
						|
    
 | 
						|
    // Show group assignments if this is a UPS config
 | 
						|
    if (config.groups && Array.isArray(config.groups)) {
 | 
						|
      logger.logBoxLine(`Group Assignments: ${config.groups.length === 0 ? 'None' : config.groups.join(', ')}`);
 | 
						|
    }
 | 
						|
    
 | 
						|
    logger.logBoxLine(`Check Interval: ${checkInterval / 1000} seconds`);
 | 
						|
    logger.logBoxEnd();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Test connection to the UPS
 | 
						|
   * @param config Current UPS configuration or legacy config
 | 
						|
   */
 | 
						|
  private async testConnection(config: any): Promise<void> {
 | 
						|
    const upsId = config.id || 'default';
 | 
						|
    const upsName = config.name || 'Default UPS';
 | 
						|
    logger.log(`\nTesting connection to UPS: ${upsName} (${upsId})...`);
 | 
						|
    
 | 
						|
    try {
 | 
						|
      // Create a test config with a short timeout
 | 
						|
      const snmpConfig = config.snmp ? config.snmp : config.snmp;
 | 
						|
      const thresholds = config.thresholds ? config.thresholds : config.thresholds;
 | 
						|
      
 | 
						|
      const testConfig = {
 | 
						|
        ...snmpConfig,
 | 
						|
        timeout: Math.min(snmpConfig.timeout, 10000), // Use at most 10 seconds for testing
 | 
						|
      };
 | 
						|
 | 
						|
      const status = await this.nupst.getSnmp().getUpsStatus(testConfig);
 | 
						|
 | 
						|
      const boxWidth = 45;
 | 
						|
      logger.logBoxTitle(`Connection Successful: ${upsName}`, boxWidth);
 | 
						|
      logger.logBoxLine('UPS Status:');
 | 
						|
      logger.logBoxLine(`  Power Status: ${status.powerStatus}`);
 | 
						|
      logger.logBoxLine(`  Battery Capacity: ${status.batteryCapacity}%`);
 | 
						|
      logger.logBoxLine(`  Runtime Remaining: ${status.batteryRuntime} minutes`);
 | 
						|
      logger.logBoxEnd();
 | 
						|
 | 
						|
      // Check status against thresholds if on battery
 | 
						|
      if (status.powerStatus === 'onBattery') {
 | 
						|
        this.analyzeThresholds(status, thresholds);
 | 
						|
      }
 | 
						|
    } catch (error) {
 | 
						|
      const errorBoxWidth = 45;
 | 
						|
      logger.logBoxTitle(`Connection Failed: ${upsName}`, errorBoxWidth);
 | 
						|
      logger.logBoxLine(`Error: ${error.message}`);
 | 
						|
      logger.logBoxEnd();
 | 
						|
      logger.log("\nPlease check your settings and run 'nupst edit' to reconfigure this UPS.");
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Analyze UPS status against thresholds
 | 
						|
   * @param status UPS status
 | 
						|
   * @param thresholds Threshold configuration
 | 
						|
   */
 | 
						|
  private analyzeThresholds(status: any, thresholds: any): void {
 | 
						|
    const boxWidth = 45;
 | 
						|
    logger.logBoxTitle('Threshold Analysis', boxWidth);
 | 
						|
 | 
						|
    if (status.batteryCapacity < thresholds.battery) {
 | 
						|
      logger.logBoxLine('⚠️ WARNING: Battery capacity below threshold');
 | 
						|
      logger.logBoxLine(
 | 
						|
        `  Current: ${status.batteryCapacity}% | Threshold: ${thresholds.battery}%`
 | 
						|
      );
 | 
						|
      logger.logBoxLine('  System would initiate shutdown');
 | 
						|
    } else {
 | 
						|
      logger.logBoxLine('✓ Battery capacity above threshold');
 | 
						|
      logger.logBoxLine(
 | 
						|
        `  Current: ${status.batteryCapacity}% | Threshold: ${thresholds.battery}%`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    if (status.batteryRuntime < thresholds.runtime) {
 | 
						|
      logger.logBoxLine('⚠️ WARNING: Runtime below threshold');
 | 
						|
      logger.logBoxLine(
 | 
						|
        `  Current: ${status.batteryRuntime} min | Threshold: ${thresholds.runtime} min`
 | 
						|
      );
 | 
						|
      logger.logBoxLine('  System would initiate shutdown');
 | 
						|
    } else {
 | 
						|
      logger.logBoxLine('✓ Runtime above threshold');
 | 
						|
      logger.logBoxLine(
 | 
						|
        `  Current: ${status.batteryRuntime} min | Threshold: ${thresholds.runtime} min`
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    logger.logBoxEnd();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gather SNMP settings
 | 
						|
   * @param snmpConfig SNMP configuration object to update
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async gatherSnmpSettings(
 | 
						|
    snmpConfig: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    // SNMP IP Address
 | 
						|
    const defaultHost = snmpConfig.host || '127.0.0.1';
 | 
						|
    const host = await prompt(`UPS IP Address [${defaultHost}]: `);
 | 
						|
    snmpConfig.host = host.trim() || defaultHost;
 | 
						|
 | 
						|
    // SNMP Port
 | 
						|
    const defaultPort = snmpConfig.port || 161;
 | 
						|
    const portInput = await prompt(`SNMP Port [${defaultPort}]: `);
 | 
						|
    const port = parseInt(portInput, 10);
 | 
						|
    snmpConfig.port = portInput.trim() && !isNaN(port) ? port : defaultPort;
 | 
						|
 | 
						|
    // SNMP Version
 | 
						|
    const defaultVersion = snmpConfig.version || 1;
 | 
						|
    console.log('\nSNMP Version:');
 | 
						|
    console.log('  1) SNMPv1');
 | 
						|
    console.log('  2) SNMPv2c');
 | 
						|
    console.log('  3) SNMPv3 (with security features)');
 | 
						|
    const versionInput = await prompt(`Select SNMP version [${defaultVersion}]: `);
 | 
						|
    const version = parseInt(versionInput, 10);
 | 
						|
    snmpConfig.version =
 | 
						|
      versionInput.trim() && (version === 1 || version === 2 || version === 3)
 | 
						|
        ? version
 | 
						|
        : defaultVersion;
 | 
						|
 | 
						|
    if (snmpConfig.version === 1 || snmpConfig.version === 2) {
 | 
						|
      // SNMP Community String (for v1/v2c)
 | 
						|
      const defaultCommunity = snmpConfig.community || 'public';
 | 
						|
      const community = await prompt(`SNMP Community String [${defaultCommunity}]: `);
 | 
						|
      snmpConfig.community = community.trim() || defaultCommunity;
 | 
						|
    } else if (snmpConfig.version === 3) {
 | 
						|
      // SNMP v3 settings
 | 
						|
      await this.gatherSnmpV3Settings(snmpConfig, prompt);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gather SNMPv3 specific settings
 | 
						|
   * @param snmpConfig SNMP configuration object to update
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async gatherSnmpV3Settings(
 | 
						|
    snmpConfig: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    console.log('\nSNMPv3 Security Settings:');
 | 
						|
 | 
						|
    // Security Level
 | 
						|
    console.log('\nSecurity Level:');
 | 
						|
    console.log('  1) noAuthNoPriv (No Authentication, No Privacy)');
 | 
						|
    console.log('  2) authNoPriv (Authentication, No Privacy)');
 | 
						|
    console.log('  3) authPriv (Authentication and Privacy)');
 | 
						|
    const defaultSecLevel = snmpConfig.securityLevel
 | 
						|
      ? snmpConfig.securityLevel === 'noAuthNoPriv'
 | 
						|
        ? 1
 | 
						|
        : snmpConfig.securityLevel === 'authNoPriv'
 | 
						|
        ? 2
 | 
						|
        : 3
 | 
						|
      : 3;
 | 
						|
    const secLevelInput = await prompt(`Select Security Level [${defaultSecLevel}]: `);
 | 
						|
    const secLevel = parseInt(secLevelInput, 10) || defaultSecLevel;
 | 
						|
 | 
						|
    if (secLevel === 1) {
 | 
						|
      snmpConfig.securityLevel = 'noAuthNoPriv';
 | 
						|
      // No auth, no priv - clear out authentication and privacy settings
 | 
						|
      snmpConfig.authProtocol = '';
 | 
						|
      snmpConfig.authKey = '';
 | 
						|
      snmpConfig.privProtocol = '';
 | 
						|
      snmpConfig.privKey = '';
 | 
						|
      // Set appropriate timeout for security level
 | 
						|
      snmpConfig.timeout = 5000; // 5 seconds for basic security
 | 
						|
    } else if (secLevel === 2) {
 | 
						|
      snmpConfig.securityLevel = 'authNoPriv';
 | 
						|
      // Auth, no priv - clear out privacy settings
 | 
						|
      snmpConfig.privProtocol = '';
 | 
						|
      snmpConfig.privKey = '';
 | 
						|
      // Set appropriate timeout for security level
 | 
						|
      snmpConfig.timeout = 10000; // 10 seconds for authentication
 | 
						|
    } else {
 | 
						|
      snmpConfig.securityLevel = 'authPriv';
 | 
						|
      // Set appropriate timeout for security level
 | 
						|
      snmpConfig.timeout = 15000; // 15 seconds for full encryption
 | 
						|
    }
 | 
						|
 | 
						|
    // Username
 | 
						|
    const defaultUsername = snmpConfig.username || '';
 | 
						|
    const username = await prompt(`SNMPv3 Username [${defaultUsername}]: `);
 | 
						|
    snmpConfig.username = username.trim() || defaultUsername;
 | 
						|
 | 
						|
    if (secLevel >= 2) {
 | 
						|
      // Authentication settings
 | 
						|
      await this.gatherAuthenticationSettings(snmpConfig, prompt);
 | 
						|
 | 
						|
      if (secLevel === 3) {
 | 
						|
        // Privacy settings
 | 
						|
        await this.gatherPrivacySettings(snmpConfig, prompt);
 | 
						|
      }
 | 
						|
 | 
						|
      // Allow customizing the timeout value
 | 
						|
      const defaultTimeout = snmpConfig.timeout / 1000; // Convert from ms to seconds for display
 | 
						|
      console.log(
 | 
						|
        '\nSNMPv3 operations with authentication and privacy may require longer timeouts.'
 | 
						|
      );
 | 
						|
      const timeoutInput = await prompt(`SNMP Timeout in seconds [${defaultTimeout}]: `);
 | 
						|
      const timeout = parseInt(timeoutInput, 10);
 | 
						|
      if (timeoutInput.trim() && !isNaN(timeout)) {
 | 
						|
        snmpConfig.timeout = timeout * 1000; // Convert to ms
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gather authentication settings for SNMPv3
 | 
						|
   * @param snmpConfig SNMP configuration object to update
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async gatherAuthenticationSettings(
 | 
						|
    snmpConfig: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    // Authentication protocol
 | 
						|
    console.log('\nAuthentication Protocol:');
 | 
						|
    console.log('  1) MD5');
 | 
						|
    console.log('  2) SHA');
 | 
						|
    const defaultAuthProtocol = snmpConfig.authProtocol === 'SHA' ? 2 : 1;
 | 
						|
    const authProtocolInput = await prompt(
 | 
						|
      `Select Authentication Protocol [${defaultAuthProtocol}]: `
 | 
						|
    );
 | 
						|
    const authProtocol = parseInt(authProtocolInput, 10) || defaultAuthProtocol;
 | 
						|
    snmpConfig.authProtocol = authProtocol === 2 ? 'SHA' : 'MD5';
 | 
						|
 | 
						|
    // Authentication Key/Password
 | 
						|
    const defaultAuthKey = snmpConfig.authKey || '';
 | 
						|
    const authKey = await prompt(`Authentication Password ${defaultAuthKey ? '[*****]' : ''}: `);
 | 
						|
    snmpConfig.authKey = authKey.trim() || defaultAuthKey;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gather privacy settings for SNMPv3
 | 
						|
   * @param snmpConfig SNMP configuration object to update
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async gatherPrivacySettings(
 | 
						|
    snmpConfig: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    // Privacy protocol
 | 
						|
    console.log('\nPrivacy Protocol:');
 | 
						|
    console.log('  1) DES');
 | 
						|
    console.log('  2) AES');
 | 
						|
    const defaultPrivProtocol = snmpConfig.privProtocol === 'AES' ? 2 : 1;
 | 
						|
    const privProtocolInput = await prompt(`Select Privacy Protocol [${defaultPrivProtocol}]: `);
 | 
						|
    const privProtocol = parseInt(privProtocolInput, 10) || defaultPrivProtocol;
 | 
						|
    snmpConfig.privProtocol = privProtocol === 2 ? 'AES' : 'DES';
 | 
						|
 | 
						|
    // Privacy Key/Password
 | 
						|
    const defaultPrivKey = snmpConfig.privKey || '';
 | 
						|
    const privKey = await prompt(`Privacy Password ${defaultPrivKey ? '[*****]' : ''}: `);
 | 
						|
    snmpConfig.privKey = privKey.trim() || defaultPrivKey;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gather threshold settings
 | 
						|
   * @param thresholds Thresholds configuration object to update
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async gatherThresholdSettings(
 | 
						|
    thresholds: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    console.log('\nShutdown Thresholds:');
 | 
						|
 | 
						|
    // Battery threshold
 | 
						|
    const defaultBatteryThreshold = thresholds.battery || 60;
 | 
						|
    const batteryThresholdInput = await prompt(
 | 
						|
      `Battery percentage threshold [${defaultBatteryThreshold}%]: `
 | 
						|
    );
 | 
						|
    const batteryThreshold = parseInt(batteryThresholdInput, 10);
 | 
						|
    thresholds.battery =
 | 
						|
      batteryThresholdInput.trim() && !isNaN(batteryThreshold)
 | 
						|
        ? batteryThreshold
 | 
						|
        : defaultBatteryThreshold;
 | 
						|
 | 
						|
    // Runtime threshold
 | 
						|
    const defaultRuntimeThreshold = thresholds.runtime || 20;
 | 
						|
    const runtimeThresholdInput = await prompt(
 | 
						|
      `Runtime minutes threshold [${defaultRuntimeThreshold} minutes]: `
 | 
						|
    );
 | 
						|
    const runtimeThreshold = parseInt(runtimeThresholdInput, 10);
 | 
						|
    thresholds.runtime =
 | 
						|
      runtimeThresholdInput.trim() && !isNaN(runtimeThreshold)
 | 
						|
        ? runtimeThreshold
 | 
						|
        : defaultRuntimeThreshold;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gather UPS model settings
 | 
						|
   * @param snmpConfig SNMP configuration object to update
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async gatherUpsModelSettings(
 | 
						|
    snmpConfig: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    console.log('\nUPS Model Selection:');
 | 
						|
    console.log('  1) CyberPower');
 | 
						|
    console.log('  2) APC');
 | 
						|
    console.log('  3) Eaton');
 | 
						|
    console.log('  4) TrippLite');
 | 
						|
    console.log('  5) Liebert/Vertiv');
 | 
						|
    console.log('  6) Custom (Advanced)');
 | 
						|
 | 
						|
    const defaultModelValue =
 | 
						|
      snmpConfig.upsModel === 'cyberpower'
 | 
						|
        ? 1
 | 
						|
        : snmpConfig.upsModel === 'apc'
 | 
						|
        ? 2
 | 
						|
        : snmpConfig.upsModel === 'eaton'
 | 
						|
        ? 3
 | 
						|
        : snmpConfig.upsModel === 'tripplite'
 | 
						|
        ? 4
 | 
						|
        : snmpConfig.upsModel === 'liebert'
 | 
						|
        ? 5
 | 
						|
        : snmpConfig.upsModel === 'custom'
 | 
						|
        ? 6
 | 
						|
        : 1;
 | 
						|
 | 
						|
    const modelInput = await prompt(`Select UPS model [${defaultModelValue}]: `);
 | 
						|
    const modelValue = parseInt(modelInput, 10) || defaultModelValue;
 | 
						|
 | 
						|
    if (modelValue === 1) {
 | 
						|
      snmpConfig.upsModel = 'cyberpower';
 | 
						|
    } else if (modelValue === 2) {
 | 
						|
      snmpConfig.upsModel = 'apc';
 | 
						|
    } else if (modelValue === 3) {
 | 
						|
      snmpConfig.upsModel = 'eaton';
 | 
						|
    } else if (modelValue === 4) {
 | 
						|
      snmpConfig.upsModel = 'tripplite';
 | 
						|
    } else if (modelValue === 5) {
 | 
						|
      snmpConfig.upsModel = 'liebert';
 | 
						|
    } else if (modelValue === 6) {
 | 
						|
      snmpConfig.upsModel = 'custom';
 | 
						|
      console.log('\nEnter custom OIDs for your UPS:');
 | 
						|
      console.log('(Leave blank to use standard RFC 1628 OIDs as fallback)');
 | 
						|
 | 
						|
      // Custom OIDs
 | 
						|
      const powerStatusOID = await prompt('Power Status OID: ');
 | 
						|
      const batteryCapacityOID = await prompt('Battery Capacity OID: ');
 | 
						|
      const batteryRuntimeOID = await prompt('Battery Runtime OID: ');
 | 
						|
 | 
						|
      // Create custom OIDs object
 | 
						|
      snmpConfig.customOIDs = {
 | 
						|
        POWER_STATUS: powerStatusOID.trim(),
 | 
						|
        BATTERY_CAPACITY: batteryCapacityOID.trim(),
 | 
						|
        BATTERY_RUNTIME: batteryRuntimeOID.trim(),
 | 
						|
      };
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Display UPS configuration summary
 | 
						|
   * @param ups UPS configuration
 | 
						|
   */
 | 
						|
  private displayUpsConfigSummary(ups: any): void {
 | 
						|
    const boxWidth = 45;
 | 
						|
    logger.log('');
 | 
						|
    logger.logBoxTitle(`UPS Configuration: ${ups.name}`, boxWidth);
 | 
						|
    logger.logBoxLine(`UPS ID: ${ups.id}`);
 | 
						|
    logger.logBoxLine(`SNMP Host: ${ups.snmp.host}:${ups.snmp.port}`);
 | 
						|
    logger.logBoxLine(`SNMP Version: ${ups.snmp.version}`);
 | 
						|
    logger.logBoxLine(`UPS Model: ${ups.snmp.upsModel}`);
 | 
						|
    logger.logBoxLine(
 | 
						|
      `Thresholds: ${ups.thresholds.battery}% battery, ${ups.thresholds.runtime} min runtime`
 | 
						|
    );
 | 
						|
    if (ups.groups && ups.groups.length > 0) {
 | 
						|
      logger.logBoxLine(`Groups: ${ups.groups.join(', ')}`);
 | 
						|
    } else {
 | 
						|
      logger.logBoxLine('Groups: None');
 | 
						|
    }
 | 
						|
    logger.logBoxEnd();
 | 
						|
    logger.log('');
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Optionally test connection to UPS
 | 
						|
   * @param snmpConfig SNMP configuration to test
 | 
						|
   * @param prompt Function to prompt for user input
 | 
						|
   */
 | 
						|
  private async optionallyTestConnection(
 | 
						|
    snmpConfig: any,
 | 
						|
    prompt: (question: string) => Promise<string>
 | 
						|
  ): Promise<void> {
 | 
						|
    const testConnection = await prompt(
 | 
						|
      'Would you like to test the connection to your UPS? (y/N): '
 | 
						|
    );
 | 
						|
    if (testConnection.toLowerCase() === 'y') {
 | 
						|
      logger.log('\nTesting connection to UPS...');
 | 
						|
      try {
 | 
						|
        // Create a test config with a short timeout
 | 
						|
        const testConfig = {
 | 
						|
          ...snmpConfig,
 | 
						|
          timeout: Math.min(snmpConfig.timeout, 10000), // Use at most 10 seconds for testing
 | 
						|
        };
 | 
						|
 | 
						|
        const status = await this.nupst.getSnmp().getUpsStatus(testConfig);
 | 
						|
        const boxWidth = 45;
 | 
						|
        logger.log('');
 | 
						|
        logger.logBoxTitle('Connection Successful!', boxWidth);
 | 
						|
        logger.logBoxLine('UPS Status:');
 | 
						|
        logger.logBoxLine(`✓ Power Status: ${status.powerStatus}`);
 | 
						|
        logger.logBoxLine(`✓ Battery Capacity: ${status.batteryCapacity}%`);
 | 
						|
        logger.logBoxLine(`✓ Runtime Remaining: ${status.batteryRuntime} minutes`);
 | 
						|
        logger.logBoxEnd();
 | 
						|
      } catch (error) {
 | 
						|
        const errorBoxWidth = 45;
 | 
						|
        logger.log('');
 | 
						|
        logger.logBoxTitle('Connection Failed!', errorBoxWidth);
 | 
						|
        logger.logBoxLine(`Error: ${error.message}`);
 | 
						|
        logger.logBoxEnd();
 | 
						|
        logger.log('\nPlease check your settings and try again.');
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Check if the systemd service is running and restart it if it is
 | 
						|
   * This is useful after configuration changes
 | 
						|
   */
 | 
						|
  public async restartServiceIfRunning(): Promise<void> {
 | 
						|
    try {
 | 
						|
      // Check if the service is active
 | 
						|
      const isActive =
 | 
						|
        execSync('systemctl is-active nupst.service || true').toString().trim() === 'active';
 | 
						|
 | 
						|
      if (isActive) {
 | 
						|
        // Service is running, restart it
 | 
						|
        const boxWidth = 45;
 | 
						|
        logger.logBoxTitle('Service Update', boxWidth);
 | 
						|
        logger.logBoxLine('Configuration has changed.');
 | 
						|
        logger.logBoxLine('Restarting NUPST service to apply changes...');
 | 
						|
 | 
						|
        try {
 | 
						|
          if (process.getuid && process.getuid() === 0) {
 | 
						|
            // We have root access, restart directly
 | 
						|
            execSync('systemctl restart nupst.service');
 | 
						|
            logger.logBoxLine('Service restarted successfully.');
 | 
						|
          } else {
 | 
						|
            // No root access, show instructions
 | 
						|
            logger.logBoxLine('Please restart the service with:');
 | 
						|
            logger.logBoxLine('  sudo systemctl restart nupst.service');
 | 
						|
          }
 | 
						|
        } catch (error) {
 | 
						|
          logger.logBoxLine(`Error restarting service: ${error.message}`);
 | 
						|
          logger.logBoxLine('You may need to restart the service manually:');
 | 
						|
          logger.logBoxLine('  sudo systemctl restart nupst.service');
 | 
						|
        }
 | 
						|
 | 
						|
        logger.logBoxEnd();
 | 
						|
      }
 | 
						|
    } catch (error) {
 | 
						|
      // Ignore errors checking service status
 | 
						|
    }
 | 
						|
  }
 | 
						|
} |