A virtual newsroom powered by RSS and AI.
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

// 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;
}
}
}