nupst/ts/nupst.ts

227 lines
6.4 KiB
TypeScript

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<boolean> {
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<string> {
return new Promise<string>((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();
}
}
}