This commit is contained in:
2026-01-09 07:14:39 +00:00
parent 95da37590c
commit 05e1f94c79
22 changed files with 6549 additions and 10 deletions

View File

@@ -0,0 +1,271 @@
import * as plugins from '../plugins.js';
import { Device } from '../abstract/device.abstract.js';
import { SnmpProtocol, SNMP_OIDS, type ISnmpOptions, type ISnmpVarbind } from './snmp.classes.snmpprotocol.js';
import type { IDeviceInfo, IRetryOptions, TDeviceStatus } from '../interfaces/index.js';
/**
* SNMP device information
*/
export interface ISnmpDeviceInfo extends IDeviceInfo {
type: 'snmp';
sysDescr: string;
sysObjectID: string;
sysUpTime: number;
sysContact?: string;
sysName?: string;
sysLocation?: string;
}
/**
* SNMP Device class for generic SNMP-enabled devices
*/
export class SnmpDevice extends Device {
private protocol: SnmpProtocol | null = null;
private snmpOptions: ISnmpOptions;
private _sysDescr: string = '';
private _sysObjectID: string = '';
private _sysUpTime: number = 0;
private _sysContact?: string;
private _sysName?: string;
private _sysLocation?: string;
constructor(
info: IDeviceInfo,
snmpOptions?: ISnmpOptions,
retryOptions?: IRetryOptions
) {
super(info, retryOptions);
this.snmpOptions = { port: info.port, ...snmpOptions };
}
// Getters for SNMP properties
public get sysDescr(): string {
return this._sysDescr;
}
public get sysObjectID(): string {
return this._sysObjectID;
}
public get sysUpTime(): number {
return this._sysUpTime;
}
public get sysContact(): string | undefined {
return this._sysContact;
}
public get sysName(): string | undefined {
return this._sysName;
}
public get sysLocation(): string | undefined {
return this._sysLocation;
}
/**
* Connect to the SNMP device
*/
protected async doConnect(): Promise<void> {
this.protocol = new SnmpProtocol(this.address, this.snmpOptions);
// Verify connection by fetching system info
const sysInfo = await this.protocol.getSystemInfo();
this._sysDescr = sysInfo.sysDescr;
this._sysObjectID = sysInfo.sysObjectID;
this._sysUpTime = sysInfo.sysUpTime;
this._sysContact = sysInfo.sysContact || undefined;
this._sysName = sysInfo.sysName || undefined;
this._sysLocation = sysInfo.sysLocation || undefined;
// Update device name if sysName is available
if (sysInfo.sysName && !this.name.includes('SNMP Device')) {
// Keep custom name
} else if (sysInfo.sysName) {
(this as { name: string }).name = sysInfo.sysName;
}
}
/**
* Disconnect from the SNMP device
*/
protected async doDisconnect(): Promise<void> {
if (this.protocol) {
this.protocol.close();
this.protocol = null;
}
}
/**
* Refresh device status
*/
public async refreshStatus(): Promise<void> {
if (!this.protocol) {
throw new Error('Not connected');
}
const sysInfo = await this.protocol.getSystemInfo();
this._sysUpTime = sysInfo.sysUpTime;
this.emit('status:updated', this.getDeviceInfo());
}
/**
* Get a single OID value
*/
public async get(oid: string): Promise<ISnmpVarbind> {
if (!this.protocol) {
throw new Error('Not connected');
}
return this.protocol.get(oid);
}
/**
* Get multiple OID values
*/
public async getMultiple(oids: string[]): Promise<ISnmpVarbind[]> {
if (!this.protocol) {
throw new Error('Not connected');
}
return this.protocol.getMultiple(oids);
}
/**
* Get next OID in the MIB tree
*/
public async getNext(oid: string): Promise<ISnmpVarbind> {
if (!this.protocol) {
throw new Error('Not connected');
}
return this.protocol.getNext(oid);
}
/**
* GETBULK operation for efficient table retrieval
*/
public async getBulk(
oids: string[],
nonRepeaters?: number,
maxRepetitions?: number
): Promise<ISnmpVarbind[]> {
if (!this.protocol) {
throw new Error('Not connected');
}
return this.protocol.getBulk(oids, nonRepeaters, maxRepetitions);
}
/**
* Walk a MIB tree
*/
public async walk(baseOid: string): Promise<ISnmpVarbind[]> {
if (!this.protocol) {
throw new Error('Not connected');
}
return this.protocol.walk(baseOid);
}
/**
* Set an OID value
*/
public async set(
oid: string,
type: 'Integer' | 'OctetString' | 'ObjectIdentifier' | 'IpAddress',
value: unknown
): Promise<ISnmpVarbind> {
if (!this.protocol) {
throw new Error('Not connected');
}
return this.protocol.set(oid, type, value);
}
/**
* Get device information
*/
public getDeviceInfo(): ISnmpDeviceInfo {
return {
id: this.id,
name: this.name,
type: 'snmp',
address: this.address,
port: this.port,
status: this.status,
sysDescr: this._sysDescr,
sysObjectID: this._sysObjectID,
sysUpTime: this._sysUpTime,
sysContact: this._sysContact,
sysName: this._sysName,
sysLocation: this._sysLocation,
};
}
/**
* Create SnmpDevice from discovery data
*/
public static fromDiscovery(
data: {
id: string;
name: string;
address: string;
port?: number;
community?: string;
},
retryOptions?: IRetryOptions
): SnmpDevice {
const info: IDeviceInfo = {
id: data.id,
name: data.name,
type: 'snmp',
address: data.address,
port: data.port ?? 161,
status: 'unknown',
};
return new SnmpDevice(
info,
{ community: data.community ?? 'public' },
retryOptions
);
}
/**
* Probe an IP address for SNMP device
*/
public static async probe(
address: string,
port: number = 161,
community: string = 'public',
timeout: number = 5000
): Promise<ISnmpDeviceInfo | null> {
const protocol = new SnmpProtocol(address, {
community,
port,
timeout,
retries: 0,
});
try {
const sysInfo = await protocol.getSystemInfo();
return {
id: `snmp:${address}:${port}`,
name: sysInfo.sysName || `SNMP Device at ${address}`,
type: 'snmp',
address,
port,
status: 'online',
sysDescr: sysInfo.sysDescr,
sysObjectID: sysInfo.sysObjectID,
sysUpTime: sysInfo.sysUpTime,
sysContact: sysInfo.sysContact || undefined,
sysName: sysInfo.sysName || undefined,
sysLocation: sysInfo.sysLocation || undefined,
};
} catch {
return null;
} finally {
protocol.close();
}
}
}
export { SNMP_OIDS };