style: configure deno fmt to use single quotes
All checks were successful
CI / Build All Platforms (Tag/Main only) (push) Has been skipped
CI / Type Check & Lint (push) Successful in 6s
CI / Build Test (Current Platform) (push) Successful in 6s

- Add singleQuote: true to deno.json fmt configuration
- Reformat all files with single quotes using deno fmt
This commit is contained in:
2025-10-19 13:14:18 +00:00
parent b935087d50
commit 071ded9c41
24 changed files with 1094 additions and 672 deletions

View File

@@ -35,10 +35,10 @@ export class GroupHandler {
logger.logBoxEnd();
return;
}
// Get current configuration
const config = this.nupst.getDaemon().getConfig();
// Check if multi-UPS config
if (!config.groups || !Array.isArray(config.groups)) {
// Legacy or missing groups configuration
@@ -49,11 +49,11 @@ export class GroupHandler {
logger.logBoxEnd();
return;
}
// Display group list
const boxWidth = 60;
logger.logBoxTitle('UPS Groups', boxWidth);
if (config.groups.length === 0) {
logger.logBoxLine('No UPS groups configured.');
logger.logBoxLine('Use "nupst group add" to add a UPS group.');
@@ -62,27 +62,29 @@ export class GroupHandler {
logger.logBoxLine('');
logger.logBoxLine('ID | Name | Mode | UPS Devices');
logger.logBoxLine('-----------+----------------------+--------------+----------------');
for (const group of config.groups) {
const id = group.id.padEnd(10, ' ').substring(0, 10);
const name = (group.name || '').padEnd(20, ' ').substring(0, 20);
const mode = (group.mode || 'unknown').padEnd(12, ' ').substring(0, 12);
// Count UPS devices in this group
const upsInGroup = config.upsDevices.filter(ups => ups.groups.includes(group.id));
const upsInGroup = config.upsDevices.filter((ups) => ups.groups.includes(group.id));
const upsCount = upsInGroup.length;
const upsNames = upsInGroup.map(ups => ups.name).join(', ');
const upsNames = upsInGroup.map((ups) => ups.name).join(', ');
logger.logBoxLine(`${id} | ${name} | ${mode} | ${upsCount > 0 ? upsNames : 'None'}`);
}
}
logger.logBoxEnd();
} catch (error) {
logger.error(`Failed to list UPS groups: ${error instanceof Error ? error.message : String(error)}`);
logger.error(
`Failed to list UPS groups: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
/**
* Add a new UPS group
*/
@@ -110,54 +112,56 @@ export class GroupHandler {
try {
await this.nupst.getDaemon().loadConfig();
} catch (error) {
logger.error('No configuration found. Please run "nupst setup" first to create a configuration.');
logger.error(
'No configuration found. Please run "nupst setup" first to create a configuration.',
);
return;
}
// Get current configuration
const config = this.nupst.getDaemon().getConfig();
// Initialize groups array if not exists
if (!config.groups) {
config.groups = [];
}
// Check if upsDevices is initialized
if (!config.upsDevices) {
config.upsDevices = [];
}
logger.log('\nNUPST Add Group');
logger.log('==============\n');
logger.log('This will guide you through creating a new UPS group.\n');
// Generate a new unique group ID
const groupId = helpers.shortId();
// Get group name
const name = await prompt('Group Name: ');
// Get group mode
const modeInput = await prompt('Group Mode (redundant/nonRedundant) [redundant]: ');
const mode = modeInput.toLowerCase() === 'nonredundant' ? 'nonRedundant' : 'redundant';
// Get optional description
const description = await prompt('Group Description (optional): ');
// Create the new group
const newGroup: IGroupConfig = {
id: groupId,
name: name || `Group-${groupId}`,
mode,
description: description || undefined
description: description || undefined,
};
// Add the group to the configuration
config.groups.push(newGroup);
// Save the configuration
await this.nupst.getDaemon().saveConfig(config);
// Display summary
const boxWidth = 45;
logger.logBoxTitle('Group Created', boxWidth);
@@ -168,21 +172,23 @@ export class GroupHandler {
logger.logBoxLine(`Description: ${newGroup.description}`);
}
logger.logBoxEnd();
// Check if there are UPS devices to assign to this group
if (config.upsDevices.length > 0) {
const assignUps = await prompt('Would you like to assign UPS devices to this group now? (y/N): ');
const assignUps = await prompt(
'Would you like to assign UPS devices to this group now? (y/N): ',
);
if (assignUps.toLowerCase() === 'y') {
await this.assignUpsToGroup(newGroup.id, config, prompt);
// Save again after assigning UPS devices
await this.nupst.getDaemon().saveConfig(config);
}
}
// Check if service is running and restart it if needed
this.nupst.getUpsHandler().restartServiceIfRunning();
logger.log('\nGroup setup complete!');
} finally {
rl.close();
@@ -191,7 +197,7 @@ export class GroupHandler {
logger.error(`Add group error: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Edit an existing UPS group
* @param groupId ID of the group to edit
@@ -220,57 +226,61 @@ export class GroupHandler {
try {
await this.nupst.getDaemon().loadConfig();
} catch (error) {
logger.error('No configuration found. Please run "nupst setup" first to create a configuration.');
logger.error(
'No configuration found. Please run "nupst setup" first to create a configuration.',
);
return;
}
// Get current configuration
const config = this.nupst.getDaemon().getConfig();
// Check if groups are initialized
if (!config.groups || !Array.isArray(config.groups)) {
logger.error('No groups configured. Please run "nupst group add" first to create a group.');
logger.error(
'No groups configured. Please run "nupst group add" first to create a group.',
);
return;
}
// Find the group to edit
const groupIndex = config.groups.findIndex(group => group.id === groupId);
const groupIndex = config.groups.findIndex((group) => group.id === groupId);
if (groupIndex === -1) {
logger.error(`Group with ID "${groupId}" not found.`);
return;
}
const group = config.groups[groupIndex];
logger.log(`\nNUPST Edit Group: ${group.name} (${group.id})`);
logger.log('==============================================\n');
// Edit group name
const newName = await prompt(`Group Name [${group.name}]: `);
if (newName.trim()) {
group.name = newName;
}
// Edit group mode
const currentMode = group.mode || 'redundant';
const modeInput = await prompt(`Group Mode (redundant/nonRedundant) [${currentMode}]: `);
if (modeInput.trim()) {
group.mode = modeInput.toLowerCase() === 'nonredundant' ? 'nonRedundant' : 'redundant';
}
// Edit description
const currentDesc = group.description || '';
const newDesc = await prompt(`Group Description [${currentDesc}]: `);
if (newDesc.trim() || newDesc === '') {
group.description = newDesc.trim() || undefined;
}
// Update the group in the configuration
config.groups[groupIndex] = group;
// Save the configuration
await this.nupst.getDaemon().saveConfig(config);
// Display summary
const boxWidth = 45;
logger.logBoxTitle('Group Updated', boxWidth);
@@ -281,19 +291,21 @@ export class GroupHandler {
logger.logBoxLine(`Description: ${group.description}`);
}
logger.logBoxEnd();
// Edit UPS assignments if requested
const editAssignments = await prompt('Would you like to edit UPS assignments for this group? (y/N): ');
const editAssignments = await prompt(
'Would you like to edit UPS assignments for this group? (y/N): ',
);
if (editAssignments.toLowerCase() === 'y') {
await this.assignUpsToGroup(group.id, config, prompt);
// Save again after editing assignments
await this.nupst.getDaemon().saveConfig(config);
}
// Check if service is running and restart it if needed
this.nupst.getUpsHandler().restartServiceIfRunning();
logger.log('\nGroup edit complete!');
} finally {
rl.close();
@@ -302,7 +314,7 @@ export class GroupHandler {
logger.error(`Edit group error: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Delete an existing UPS group
* @param groupId ID of the group to delete
@@ -313,48 +325,53 @@ export class GroupHandler {
try {
await this.nupst.getDaemon().loadConfig();
} catch (error) {
logger.error('No configuration found. Please run "nupst setup" first to create a configuration.');
logger.error(
'No configuration found. Please run "nupst setup" first to create a configuration.',
);
return;
}
// Get current configuration
const config = this.nupst.getDaemon().getConfig();
// Check if groups are initialized
if (!config.groups || !Array.isArray(config.groups)) {
logger.error('No groups configured.');
return;
}
// Find the group to delete
const groupIndex = config.groups.findIndex(group => group.id === groupId);
const groupIndex = config.groups.findIndex((group) => group.id === groupId);
if (groupIndex === -1) {
logger.error(`Group with ID "${groupId}" not found.`);
return;
}
const groupToDelete = config.groups[groupIndex];
// Get confirmation before deleting
const readline = await import('node: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 group "${groupToDelete.name}" (${groupId})? [y/N]: `, answer => {
resolve(answer.toLowerCase());
});
const confirm = await new Promise<string>((resolve) => {
rl.question(
`Are you sure you want to delete group "${groupToDelete.name}" (${groupId})? [y/N]: `,
(answer) => {
resolve(answer.toLowerCase());
},
);
});
rl.close();
if (confirm !== 'y' && confirm !== 'yes') {
logger.log('Deletion cancelled.');
return;
}
// Remove this group from all UPS device group assignments
if (config.upsDevices && Array.isArray(config.upsDevices)) {
for (const ups of config.upsDevices) {
@@ -364,19 +381,21 @@ export class GroupHandler {
}
}
}
// Remove the group from the array
config.groups.splice(groupIndex, 1);
// Save the configuration
await this.nupst.getDaemon().saveConfig(config);
logger.log(`Group "${groupToDelete.name}" (${groupId}) has been deleted.`);
// Check if service is running and restart it if needed
this.nupst.getUpsHandler().restartServiceIfRunning();
} catch (error) {
logger.error(`Failed to delete group: ${error instanceof Error ? error.message : String(error)}`);
logger.error(
`Failed to delete group: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
@@ -389,18 +408,18 @@ export class GroupHandler {
public async assignUpsToGroups(
ups: any,
groups: any[],
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
// Initialize groups array if it doesn't exist
if (!ups.groups) {
ups.groups = [];
}
// Show current group assignments
logger.log('\nCurrent Group Assignments:');
if (ups.groups && ups.groups.length > 0) {
for (const groupId of ups.groups) {
const group = groups.find(g => g.id === groupId);
const group = groups.find((g) => g.id === groupId);
if (group) {
logger.log(`- ${group.name} (${group.id})`);
} else {
@@ -410,52 +429,56 @@ export class GroupHandler {
} else {
logger.log('- None');
}
// Show available groups
logger.log('\nAvailable Groups:');
if (groups.length === 0) {
logger.log('- No groups available. Use "nupst group add" to create groups.');
return;
}
for (let i = 0; i < groups.length; i++) {
const group = groups[i];
const assigned = ups.groups && ups.groups.includes(group.id);
logger.log(`${i + 1}) ${group.name} (${group.id}) [${assigned ? 'Assigned' : 'Not Assigned'}]`);
logger.log(
`${i + 1}) ${group.name} (${group.id}) [${assigned ? 'Assigned' : 'Not Assigned'}]`,
);
}
// Prompt for group selection
const selection = await prompt('\nSelect groups to assign/unassign (comma-separated numbers, or "clear" to remove all): ');
const selection = await prompt(
'\nSelect groups to assign/unassign (comma-separated numbers, or "clear" to remove all): ',
);
if (selection.toLowerCase() === 'clear') {
// Clear all group assignments
ups.groups = [];
logger.log('All group assignments cleared.');
return;
}
if (!selection.trim()) {
// No change if empty input
return;
}
// Process selections
const selections = selection.split(',').map(s => s.trim());
const selections = selection.split(',').map((s) => s.trim());
for (const sel of selections) {
const index = parseInt(sel, 10) - 1;
if (isNaN(index) || index < 0 || index >= groups.length) {
logger.error(`Invalid selection: ${sel}`);
continue;
}
const group = groups[index];
// Initialize groups array if needed (should already be done above)
if (!ups.groups) {
ups.groups = [];
}
// Toggle assignment
const groupIndex = ups.groups.indexOf(group.id);
if (groupIndex === -1) {
@@ -469,7 +492,7 @@ export class GroupHandler {
}
}
}
/**
* Assign UPS devices to a specific group
* @param groupId Group ID to assign UPS devices to
@@ -479,22 +502,24 @@ export class GroupHandler {
public async assignUpsToGroup(
groupId: string,
config: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
if (!config.upsDevices || config.upsDevices.length === 0) {
logger.log('No UPS devices available. Use "nupst add" to add UPS devices.');
return;
}
const group = config.groups.find((g: { id: string }) => g.id === groupId);
if (!group) {
logger.error(`Group with ID "${groupId}" not found.`);
return;
}
// Show current assignments
logger.log(`\nUPS devices in group "${group.name}" (${group.id}):`);
const upsInGroup = config.upsDevices.filter((ups: { groups?: string[] }) => ups.groups && ups.groups.includes(groupId));
const upsInGroup = config.upsDevices.filter((ups: { groups?: string[] }) =>
ups.groups && ups.groups.includes(groupId)
);
if (upsInGroup.length === 0) {
logger.log('- None');
} else {
@@ -502,7 +527,7 @@ export class GroupHandler {
logger.log(`- ${ups.name} (${ups.id})`);
}
}
// Show all UPS devices
logger.log('\nAvailable UPS devices:');
for (let i = 0; i < config.upsDevices.length; i++) {
@@ -510,10 +535,12 @@ export class GroupHandler {
const assigned = ups.groups && ups.groups.includes(groupId);
logger.log(`${i + 1}) ${ups.name} (${ups.id}) [${assigned ? 'Assigned' : 'Not Assigned'}]`);
}
// Prompt for UPS selection
const selection = await prompt('\nSelect UPS devices to assign/unassign (comma-separated numbers, or "clear" to remove all): ');
const selection = await prompt(
'\nSelect UPS devices to assign/unassign (comma-separated numbers, or "clear" to remove all): ',
);
if (selection.toLowerCase() === 'clear') {
// Clear all UPS from this group
for (const ups of config.upsDevices) {
@@ -527,29 +554,29 @@ export class GroupHandler {
logger.log(`All UPS devices removed from group "${group.name}".`);
return;
}
if (!selection.trim()) {
// No change if empty input
return;
}
// Process selections
const selections = selection.split(',').map(s => s.trim());
const selections = selection.split(',').map((s) => s.trim());
for (const sel of selections) {
const index = parseInt(sel, 10) - 1;
if (isNaN(index) || index < 0 || index >= config.upsDevices.length) {
logger.error(`Invalid selection: ${sel}`);
continue;
}
const ups = config.upsDevices[index];
// Initialize groups array if needed
if (!ups.groups) {
ups.groups = [];
}
// Toggle assignment
const groupIndex = ups.groups.indexOf(groupId);
if (groupIndex === -1) {
@@ -563,4 +590,4 @@ export class GroupHandler {
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
import process from 'node:process';
import { execSync } from "node:child_process";
import { execSync } from 'node:child_process';
import { Nupst } from '../nupst.ts';
import { logger } from '../logger.ts';
@@ -129,7 +129,7 @@ export class ServiceHandler {
try {
// Check if running as root
this.checkRootAccess(
'This command must be run as root to update NUPST and refresh the systemd service.'
'This command must be run as root to update NUPST and refresh the systemd service.',
);
const boxWidth = 45;
@@ -243,7 +243,7 @@ export class ServiceHandler {
// Ask about removing configuration
const removeConfig = await prompt(
'Do you want to remove the NUPST configuration files? (y/N): '
'Do you want to remove the NUPST configuration files? (y/N): ',
);
// Find the uninstall.sh script location
@@ -318,4 +318,4 @@ export class ServiceHandler {
return { debugMode, cleanedArgs };
}
}
}

View File

@@ -1,5 +1,5 @@
import process from 'node:process';
import { execSync } from "node:child_process";
import { execSync } from 'node:child_process';
import { Nupst } from '../nupst.ts';
import { logger } from '../logger.ts';
import * as helpers from '../helpers/index.ts';
@@ -67,7 +67,7 @@ export class UpsHandler {
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
@@ -78,9 +78,9 @@ export class UpsHandler {
name: 'Default UPS',
snmp: config.snmp,
thresholds: config.thresholds,
groups: []
groups: [],
}],
groups: []
groups: [],
};
logger.log('Converting existing configuration to multi-UPS format.');
}
@@ -89,7 +89,7 @@ export class UpsHandler {
config = {
checkInterval: 30000, // Default check interval
upsDevices: [],
groups: []
groups: [],
};
logger.log('No existing configuration found. Creating a new configuration.');
}
@@ -108,13 +108,13 @@ export class UpsHandler {
community: 'public',
version: 1,
timeout: 5000,
upsModel: 'cyberpower' as TUpsModel
upsModel: 'cyberpower' as TUpsModel,
},
thresholds: {
battery: 60,
runtime: 20
runtime: 20,
},
groups: []
groups: [],
};
// Gather SNMP settings
@@ -144,10 +144,10 @@ export class UpsHandler {
// 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!');
}
@@ -189,10 +189,13 @@ export class UpsHandler {
* @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> {
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();
@@ -208,10 +211,10 @@ export class UpsHandler {
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
@@ -224,17 +227,17 @@ export class UpsHandler {
name: 'Default UPS',
snmp: config.snmp,
thresholds: config.thresholds,
groups: []
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);
upsToEdit = config.upsDevices.find((ups) => ups.id === upsId);
if (!upsToEdit) {
logger.error(`UPS with ID "${upsId}" not found.`);
return;
@@ -249,41 +252,41 @@ export class UpsHandler {
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!');
}
@@ -304,58 +307,63 @@ export class UpsHandler {
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);
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('node: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());
});
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 instanceof Error ? error.message : String(error)}`);
logger.error(
`Failed to delete UPS: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
@@ -375,10 +383,10 @@ export class UpsHandler {
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
@@ -395,41 +403,49 @@ export class UpsHandler {
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(
` 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('-----------+----------------------+-----------------+--------------+----------------');
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 instanceof Error ? error.message : String(error)}`);
logger.error(
`Failed to list UPS devices: ${error instanceof Error ? error.message : String(error)}`,
);
}
}
@@ -465,7 +481,7 @@ export class UpsHandler {
// 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})`);
@@ -492,11 +508,11 @@ export class UpsHandler {
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}`);
@@ -529,18 +545,22 @@ export class UpsHandler {
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 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(
`Group Assignments: ${config.groups.length === 0 ? 'None' : config.groups.join(', ')}`,
);
}
logger.logBoxLine(`Check Interval: ${checkInterval / 1000} seconds`);
logger.logBoxEnd();
}
@@ -553,12 +573,12 @@ export class UpsHandler {
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
@@ -599,26 +619,26 @@ export class UpsHandler {
if (status.batteryCapacity < thresholds.battery) {
logger.logBoxLine('⚠️ WARNING: Battery capacity below threshold');
logger.logBoxLine(
` Current: ${status.batteryCapacity}% | Threshold: ${thresholds.battery}%`
` 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}%`
` 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`
` 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`
` Current: ${status.batteryRuntime} min | Threshold: ${thresholds.runtime} min`,
);
}
@@ -632,7 +652,7 @@ export class UpsHandler {
*/
private async gatherSnmpSettings(
snmpConfig: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
// SNMP IP Address
const defaultHost = snmpConfig.host || '127.0.0.1';
@@ -653,10 +673,9 @@ export class UpsHandler {
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;
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)
@@ -676,7 +695,7 @@ export class UpsHandler {
*/
private async gatherSnmpV3Settings(
snmpConfig: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
console.log('\nSNMPv3 Security Settings:');
@@ -734,7 +753,7 @@ export class UpsHandler {
// 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.'
'\nSNMPv3 operations with authentication and privacy may require longer timeouts.',
);
const timeoutInput = await prompt(`SNMP Timeout in seconds [${defaultTimeout}]: `);
const timeout = parseInt(timeoutInput, 10);
@@ -751,7 +770,7 @@ export class UpsHandler {
*/
private async gatherAuthenticationSettings(
snmpConfig: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
// Authentication protocol
console.log('\nAuthentication Protocol:');
@@ -759,7 +778,7 @@ export class UpsHandler {
console.log(' 2) SHA');
const defaultAuthProtocol = snmpConfig.authProtocol === 'SHA' ? 2 : 1;
const authProtocolInput = await prompt(
`Select Authentication Protocol [${defaultAuthProtocol}]: `
`Select Authentication Protocol [${defaultAuthProtocol}]: `,
);
const authProtocol = parseInt(authProtocolInput, 10) || defaultAuthProtocol;
snmpConfig.authProtocol = authProtocol === 2 ? 'SHA' : 'MD5';
@@ -777,7 +796,7 @@ export class UpsHandler {
*/
private async gatherPrivacySettings(
snmpConfig: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
// Privacy protocol
console.log('\nPrivacy Protocol:');
@@ -801,31 +820,29 @@ export class UpsHandler {
*/
private async gatherThresholdSettings(
thresholds: any,
prompt: (question: string) => Promise<string>
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}%]: `
`Battery percentage threshold [${defaultBatteryThreshold}%]: `,
);
const batteryThreshold = parseInt(batteryThresholdInput, 10);
thresholds.battery =
batteryThresholdInput.trim() && !isNaN(batteryThreshold)
? batteryThreshold
: defaultBatteryThreshold;
thresholds.battery = batteryThresholdInput.trim() && !isNaN(batteryThreshold)
? batteryThreshold
: defaultBatteryThreshold;
// Runtime threshold
const defaultRuntimeThreshold = thresholds.runtime || 20;
const runtimeThresholdInput = await prompt(
`Runtime minutes threshold [${defaultRuntimeThreshold} minutes]: `
`Runtime minutes threshold [${defaultRuntimeThreshold} minutes]: `,
);
const runtimeThreshold = parseInt(runtimeThresholdInput, 10);
thresholds.runtime =
runtimeThresholdInput.trim() && !isNaN(runtimeThreshold)
? runtimeThreshold
: defaultRuntimeThreshold;
thresholds.runtime = runtimeThresholdInput.trim() && !isNaN(runtimeThreshold)
? runtimeThreshold
: defaultRuntimeThreshold;
}
/**
@@ -835,7 +852,7 @@ export class UpsHandler {
*/
private async gatherUpsModelSettings(
snmpConfig: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
console.log('\nUPS Model Selection:');
console.log(' 1) CyberPower');
@@ -845,20 +862,19 @@ export class UpsHandler {
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 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;
@@ -905,7 +921,7 @@ export class UpsHandler {
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`
`Thresholds: ${ups.thresholds.battery}% battery, ${ups.thresholds.runtime} min runtime`,
);
if (ups.groups && ups.groups.length > 0) {
logger.logBoxLine(`Groups: ${ups.groups.join(', ')}`);
@@ -923,10 +939,10 @@ export class UpsHandler {
*/
private async optionallyTestConnection(
snmpConfig: any,
prompt: (question: string) => Promise<string>
prompt: (question: string) => Promise<string>,
): Promise<void> {
const testConnection = await prompt(
'Would you like to test the connection to your UPS? (y/N): '
'Would you like to test the connection to your UPS? (y/N): ',
);
if (testConnection.toLowerCase() === 'y') {
logger.log('\nTesting connection to UPS...');
@@ -985,7 +1001,9 @@ export class UpsHandler {
logger.logBoxLine(' sudo systemctl restart nupst.service');
}
} catch (error) {
logger.logBoxLine(`Error restarting service: ${error instanceof Error ? error.message : String(error)}`);
logger.logBoxLine(
`Error restarting service: ${error instanceof Error ? error.message : String(error)}`,
);
logger.logBoxLine('You may need to restart the service manually:');
logger.logBoxLine(' sudo systemctl restart nupst.service');
}
@@ -996,4 +1014,4 @@ export class UpsHandler {
// Ignore errors checking service status
}
}
}
}