Comprehensive type safety improvements across all CLI handlers and daemon: **Error handling type fixes:** - Add 'error instanceof Error' checks before accessing error.message throughout - Fix all error/retryError/stdError/upsError type assertions - Replace direct error.message with proper type guards **Switch case improvements:** - Wrap case block declarations in braces to satisfy deno-lint - Fix no-case-declarations warnings in CLI command handlers **Null/undefined safety:** - Add checks for config.snmp and config.thresholds before access - Fix IUpsStatus lastStatusChange to handle undefined with default value - Add proper null checks in legacy configuration paths **Type annotations:** - Add explicit type annotations to lambda parameters (groupId, updateAvailable, etc.) - Add TUpsModel type cast for 'cyberpower' default - Import and use INupstConfig type where needed **Parameter type fixes:** - Fix implicit 'any' type errors in array callbacks - Add type annotations to filter/find/map parameters Files modified: - ts/cli.ts: config.snmp/thresholds null checks, unused error variable fixes - ts/cli/group-handler.ts: 4 error.message fixes + 2 parameter type annotations - ts/cli/service-handler.ts: 3 error.message fixes - ts/cli/ups-handler.ts: 5 error.message fixes + config checks + TUpsModel import - ts/daemon.ts: 8 error.message fixes + IUpsStatus lastStatusChange fix + updateAvailable type - ts/nupst.ts: 1 error.message fix - ts/systemd.ts: 5 error.message fixes + parameter type annotation All tests passing (3/3 SNMP tests + 10/10 logger tests) Type check: ✓ No errors
227 lines
6.4 KiB
TypeScript
227 lines
6.4 KiB
TypeScript
import { NupstSnmp } from './snmp/manager.ts';
|
|
import { NupstDaemon } from './daemon.ts';
|
|
import { NupstSystemd } from './systemd.ts';
|
|
import { commitinfo } from './00_commitinfo_data.ts';
|
|
import { logger } from './logger.ts';
|
|
import { UpsHandler } from './cli/ups-handler.ts';
|
|
import { GroupHandler } from './cli/group-handler.ts';
|
|
import { ServiceHandler } from './cli/service-handler.ts';
|
|
import * as https from "node: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 instanceof Error ? error.message : String(error)}`);
|
|
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();
|
|
}
|
|
}
|
|
} |