You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.6 KiB
148 lines
3.6 KiB
// lib/core/process.ts
|
|
// Copyright (C) 2025 DTP Technologies, LLC
|
|
// All Rights Reserved
|
|
|
|
import env from "../../config/env.js";
|
|
|
|
import os from "node:os";
|
|
|
|
import { CronJob } from "cron";
|
|
import diskusage from "diskusage";
|
|
|
|
import { DtpPlatform } from "./platform.js";
|
|
import { DtpComponent } from "./component.js";
|
|
import { IDtpProcessStats } from "../../app/models/lib/process-stats.js";
|
|
|
|
import SystemInformation from "systeminformation";
|
|
|
|
interface CpuTimes {
|
|
/** The number of milliseconds the CPU has spent in user mode. */
|
|
user: number;
|
|
/** The number of milliseconds the CPU has spent in nice mode. */
|
|
nice: number;
|
|
/** The number of milliseconds the CPU has spent in sys mode. */
|
|
sys: number;
|
|
/** The number of milliseconds the CPU has spent in idle mode. */
|
|
idle: number;
|
|
/** The number of milliseconds the CPU has spent in irq mode. */
|
|
irq: number;
|
|
}
|
|
|
|
export abstract class DtpProcess extends DtpPlatform {
|
|
maxCpuTime: number = 0;
|
|
processStats: IDtpProcessStats = {
|
|
cpu: 0,
|
|
memory: 0,
|
|
storage: 0,
|
|
netBytesTx: 0,
|
|
netBytesRx: 0,
|
|
};
|
|
|
|
reportJob?: CronJob;
|
|
|
|
abstract reportStats(): Promise<void>;
|
|
|
|
constructor(component: DtpComponent) {
|
|
super(component);
|
|
}
|
|
|
|
async start(): Promise<void> {
|
|
await super.start();
|
|
|
|
this.reportJob = new CronJob(
|
|
"0 * * * * *", // top of every minute
|
|
this.reportStats.bind(this),
|
|
null,
|
|
true,
|
|
env.timezone
|
|
);
|
|
}
|
|
|
|
async stop(): Promise<number> {
|
|
if (this.reportJob) {
|
|
this.log.info("stopping host report job");
|
|
this.reportJob.stop();
|
|
delete this.reportJob;
|
|
}
|
|
return super.stop();
|
|
}
|
|
|
|
async updateStats(): Promise<void> {
|
|
await this.getCpuUsage();
|
|
await this.getMemoryUsage();
|
|
await this.getDiskUsage(env.https.uploadPath);
|
|
await this.getNetworkUsage();
|
|
}
|
|
|
|
async getMemoryUsage() {
|
|
const freeMem = os.freemem();
|
|
const totalMem = os.totalmem();
|
|
this.processStats.memory = freeMem / totalMem;
|
|
}
|
|
|
|
async getCpuUsage() {
|
|
this.processStats.cpu = 0;
|
|
|
|
const cpus = os.cpus();
|
|
if (cpus.length > 0) {
|
|
const cpuTimes: CpuTimes = {
|
|
idle: 0,
|
|
irq: 0,
|
|
nice: 0,
|
|
sys: 0,
|
|
user: 0,
|
|
};
|
|
|
|
for (const cpu of cpus) {
|
|
cpuTimes.idle += cpu.times.idle;
|
|
cpuTimes.irq += cpu.times.irq;
|
|
cpuTimes.nice += cpu.times.nice;
|
|
cpuTimes.sys += cpu.times.sys;
|
|
cpuTimes.user += cpu.times.user;
|
|
}
|
|
|
|
cpuTimes.idle /= cpus.length;
|
|
cpuTimes.irq /= cpus.length;
|
|
cpuTimes.nice /= cpus.length;
|
|
cpuTimes.sys /= cpus.length;
|
|
cpuTimes.user /= cpus.length;
|
|
|
|
const cpuTime =
|
|
cpuTimes.idle +
|
|
cpuTimes.irq +
|
|
cpuTimes.nice +
|
|
cpuTimes.sys +
|
|
cpuTimes.user;
|
|
this.processStats.cpu = cpuTime / this.maxCpuTime;
|
|
}
|
|
}
|
|
|
|
async getDiskUsage(pathname: string): Promise<void> {
|
|
return new Promise<void>((resolve, reject) => {
|
|
diskusage.check(
|
|
pathname,
|
|
(error?: Error, usage?: diskusage.DiskUsage) => {
|
|
if (error) {
|
|
return reject(error);
|
|
}
|
|
if (usage) {
|
|
this.processStats.storage = usage.available / usage.total;
|
|
return resolve();
|
|
}
|
|
return 0;
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
async getNetworkUsage(): Promise<void> {
|
|
this.processStats.netBytesRx = 0;
|
|
this.processStats.netBytesTx = 0;
|
|
|
|
const interfaces = await SystemInformation.networkStats("*");
|
|
for (const iface of interfaces) {
|
|
this.processStats.netBytesTx += iface.tx_bytes;
|
|
this.processStats.netBytesRx += iface.rx_bytes;
|
|
}
|
|
}
|
|
}
|
|
|