import { NupstSnmp } from './snmp/manager.js'; import { NupstDaemon } from './daemon.js'; import { NupstSystemd } from './systemd.js'; import { commitinfo } from './00_commitinfo_data.js'; import { logger } from './logger.js'; import { UpsHandler } from './cli/ups-handler.js'; import { GroupHandler } from './cli/group-handler.js'; import { ServiceHandler } from './cli/service-handler.js'; import * as https from 'https'; /** * Main Nupst class that coordinates all components * Acts as a facade to access SNMP, Daemon, and Systemd functionality */ export class Nupst { private readonly snmp: NupstSnmp; private readonly daemon: NupstDaemon; private readonly systemd: NupstSystemd; private readonly upsHandler: UpsHandler; private readonly groupHandler: GroupHandler; private readonly serviceHandler: ServiceHandler; private updateAvailable: boolean = false; private latestVersion: string = ''; /** * Create a new Nupst instance with all necessary components */ constructor() { // Initialize core components this.snmp = new NupstSnmp(); this.snmp.setNupst(this); // Set up bidirectional reference this.daemon = new NupstDaemon(this.snmp); this.systemd = new NupstSystemd(this.daemon); // Initialize handlers this.upsHandler = new UpsHandler(this); this.groupHandler = new GroupHandler(this); this.serviceHandler = new ServiceHandler(this); } /** * Get the SNMP manager for UPS communication */ public getSnmp(): NupstSnmp { return this.snmp; } /** * Get the daemon manager for background monitoring */ public getDaemon(): NupstDaemon { return this.daemon; } /** * Get the systemd manager for service operations */ public getSystemd(): NupstSystemd { return this.systemd; } /** * Get the UPS handler for UPS management */ public getUpsHandler(): UpsHandler { return this.upsHandler; } /** * Get the Group handler for group management */ public getGroupHandler(): GroupHandler { return this.groupHandler; } /** * Get the Service handler for service management */ public getServiceHandler(): ServiceHandler { return this.serviceHandler; } /** * Get the current version of NUPST * @returns The current version string */ public getVersion(): string { return commitinfo.version; } /** * Check if an update is available * @returns Promise resolving to true if an update is available */ public async checkForUpdates(): Promise { try { const latestVersion = await this.getLatestVersion(); const currentVersion = this.getVersion(); // Compare versions this.updateAvailable = this.compareVersions(latestVersion, currentVersion) > 0; this.latestVersion = latestVersion; return this.updateAvailable; } catch (error) { logger.error(`Error checking for updates: ${error.message}`); return false; } } /** * Get update status information * @returns Object with update status information */ public getUpdateStatus(): { currentVersion: string, latestVersion: string, updateAvailable: boolean } { return { currentVersion: this.getVersion(), latestVersion: this.latestVersion || this.getVersion(), updateAvailable: this.updateAvailable }; } /** * Get the latest version from npm registry * @returns Promise resolving to the latest version string */ private async getLatestVersion(): Promise { return new Promise((resolve, reject) => { const options = { hostname: 'registry.npmjs.org', path: '/@serve.zone/nupst', method: 'GET', headers: { 'Accept': 'application/json', 'User-Agent': `nupst/${this.getVersion()}` } }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { const response = JSON.parse(data); if (response['dist-tags'] && response['dist-tags'].latest) { resolve(response['dist-tags'].latest); } else { reject(new Error('Failed to parse version from npm registry response')); } } catch (error) { reject(error); } }); }); req.on('error', (error) => { reject(error); }); req.end(); }); } /** * Compare two semantic version strings * @param versionA First version * @param versionB Second version * @returns -1 if versionA < versionB, 0 if equal, 1 if versionA > versionB */ private compareVersions(versionA: string, versionB: string): number { const partsA = versionA.split('.').map(part => parseInt(part, 10)); const partsB = versionB.split('.').map(part => parseInt(part, 10)); for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) { const partA = i < partsA.length ? partsA[i] : 0; const partB = i < partsB.length ? partsB[i] : 0; if (partA > partB) return 1; if (partA < partB) return -1; } return 0; // Versions are equal } /** * Log the current version and update status */ public logVersionInfo(checkForUpdates: boolean = true): void { const version = this.getVersion(); const boxWidth = 45; logger.logBoxTitle('NUPST Version', boxWidth); logger.logBoxLine(`Current Version: ${version}`); if (this.updateAvailable && this.latestVersion) { logger.logBoxLine(`Update Available: ${this.latestVersion}`); logger.logBoxLine('Run "sudo nupst update" to update'); logger.logBoxEnd(); } else if (checkForUpdates) { logger.logBoxLine('Checking for updates...'); // We can't end the box yet since we're in an async operation this.checkForUpdates().then(updateAvailable => { if (updateAvailable) { logger.logBoxLine(`Update Available: ${this.latestVersion}`); logger.logBoxLine('Run "sudo nupst update" to update'); } else { logger.logBoxLine('You are running the latest version'); } logger.logBoxEnd(); }).catch(() => { logger.logBoxLine('Could not check for updates'); logger.logBoxEnd(); }); } else { logger.logBoxEnd(); } } }