use dragonfly_client_core::Result;
use std::path::Path;
use std::sync::Arc;
use std::time::Duration;
use sysinfo::{Pid, ProcessRefreshKind, ProcessesToUpdate, RefreshKind, System};
use tokio::sync::Mutex;
use tracing::debug;
#[derive(Debug, Clone, Default)]
pub struct DiskStats {
pub total: u64,
pub free: u64,
pub usage: u64,
pub used_percent: f64,
}
#[derive(Debug, Clone, Default)]
pub struct ProcessDiskStats {
pub write_bandwidth: u64,
pub read_bandwidth: u64,
}
#[derive(Debug, Clone, Default)]
pub struct Disk {
mutex: Arc<Mutex<()>>,
}
impl Disk {
const DEFAULT_DISK_REFRESH_INTERVAL: Duration = Duration::from_secs(1);
pub fn new() -> Self {
Self {
mutex: Arc::new(Mutex::new(())),
}
}
pub fn get_stats(&self, path: &Path) -> Result<DiskStats> {
let stats = fs2::statvfs(path)?;
let total_space = stats.total_space();
let available_space = stats.available_space();
let usage_space = total_space - available_space;
let used_percent = (usage_space as f64 / (total_space) as f64) * 100.0;
debug!(
"disk total space: {} bytes, available space: {} bytes, usage space: {} bytes, used percent: {}%",
total_space, available_space, usage_space, used_percent
);
Ok(DiskStats {
total: total_space,
free: available_space,
usage: usage_space,
used_percent: used_percent.clamp(0.0, 100.0),
})
}
pub async fn get_process_stats(&self, pid: u32) -> ProcessDiskStats {
let _guard = self.mutex.lock().await;
let mut sys = System::new_with_specifics(
RefreshKind::new().with_processes(ProcessRefreshKind::new().with_disk_usage()),
);
tokio::time::sleep(Self::DEFAULT_DISK_REFRESH_INTERVAL).await;
sys.refresh_processes_specifics(
ProcessesToUpdate::All,
true,
ProcessRefreshKind::new().with_disk_usage(),
);
let disk_usage = sys.process(Pid::from_u32(pid)).unwrap().disk_usage();
let write_bandwidth =
disk_usage.written_bytes / Self::DEFAULT_DISK_REFRESH_INTERVAL.as_secs();
let read_bandwidth = disk_usage.read_bytes / Self::DEFAULT_DISK_REFRESH_INTERVAL.as_secs();
debug!(
"process {} disk write bandwidth: {} bytes/s, read bandwidth: {} bytes/s",
pid, write_bandwidth, read_bandwidth
);
ProcessDiskStats {
write_bandwidth,
read_bandwidth,
}
}
}