namespace MoonlightServers.Daemon.Helpers;
///
/// Reads Linux system metrics directly from the /proc and /sys
/// pseudo-filesystems
///
public static partial class SystemMetrics
{
public record SystemSnapshot(
CpuSnapshot Cpu,
MemoryInfo Memory,
IReadOnlyList Disks,
IReadOnlyList Network,
TimeSpan Uptime
);
///
/// Collects a full system snapshot. The method waits
/// milliseconds between the two samples required to compute CPU and network rates.
/// All other reads happen in parallel during the second sampling window.
///
///
/// Interval between rate-measurement samples in milliseconds.
/// Larger values yield smoother CPU and network averages. Defaults to 500.
///
/// A fully populated .
public static async Task ReadAllAsync(int sampleIntervalMs = 500)
{
// First samples — must complete before the delay.
var cpuSample1Task = ReadRawCpuStatsAsync();
var netSample1Task = ReadRawNetStatsAsync();
await Task.WhenAll(cpuSample1Task, netSample1Task);
await Task.Delay(sampleIntervalMs);
// Second samples + all independent reads run concurrently.
var cpuSample2Task = ReadRawCpuStatsAsync();
var netSample2Task = ReadRawNetStatsAsync();
var memTask = ReadMemoryAsync();
var diskTask = ReadDisksAsync();
var uptimeTask = ReadUptimeAsync();
var cpuNameTask = ReadCpuModelNameAsync();
await Task.WhenAll(cpuSample2Task, netSample2Task, memTask, diskTask, uptimeTask, cpuNameTask);
var cpu = ComputeCpuUsage(cpuNameTask.Result, cpuSample1Task.Result, cpuSample2Task.Result);
var network = ComputeNetworkRates(netSample1Task.Result, netSample2Task.Result, sampleIntervalMs / 1000.0);
return new SystemSnapshot(cpu, memTask.Result, diskTask.Result, network, uptimeTask.Result);
}
// Uptime
private static async Task ReadUptimeAsync()
{
var text = await File.ReadAllTextAsync("/proc/uptime");
var seconds = double.Parse(text.Split(' ')[0], System.Globalization.CultureInfo.InvariantCulture);
return TimeSpan.FromSeconds(seconds);
}
}