storage.rs
1 //! Storage detection and information. 2 3 use acdc_core::Result; 4 use serde::{Deserialize, Serialize}; 5 use sysinfo::Disks; 6 7 /// Storage information. 8 #[derive(Debug, Clone, Serialize, Deserialize)] 9 pub struct StorageInfo { 10 /// Total storage in bytes (on the root/home partition) 11 pub total_bytes: u64, 12 /// Available storage in bytes 13 pub available_bytes: u64, 14 /// Mount point checked 15 pub mount_point: String, 16 /// Filesystem type 17 pub fs_type: String, 18 /// Whether storage is likely NVMe/SSD 19 pub is_ssd: bool, 20 } 21 22 impl StorageInfo { 23 /// Detect storage information for the home directory. 24 pub fn detect() -> Result<Self> { 25 let home = dirs::home_dir().unwrap_or_else(|| std::path::PathBuf::from("/")); 26 let disks = Disks::new_with_refreshed_list(); 27 28 // Find the disk that contains the home directory 29 let disk = disks 30 .iter() 31 .filter(|d| home.starts_with(d.mount_point())) 32 .max_by_key(|d| d.mount_point().as_os_str().len()) 33 .or_else(|| { 34 disks 35 .iter() 36 .find(|d| d.mount_point() == std::path::Path::new("/")) 37 }); 38 39 match disk { 40 Some(d) => { 41 let mount_str = d.mount_point().to_string_lossy().to_string(); 42 let fs_type = d.file_system().to_string_lossy().to_string(); 43 44 // Heuristic: NVMe devices usually have "nvme" in their name 45 let is_ssd = d.name().to_string_lossy().contains("nvme") 46 || d.name().to_string_lossy().contains("ssd"); 47 48 Ok(Self { 49 total_bytes: d.total_space(), 50 available_bytes: d.available_space(), 51 mount_point: mount_str, 52 fs_type, 53 is_ssd, 54 }) 55 } 56 None => Ok(Self { 57 total_bytes: 0, 58 available_bytes: 0, 59 mount_point: "/".to_string(), 60 fs_type: "unknown".to_string(), 61 is_ssd: false, 62 }), 63 } 64 } 65 66 /// Get total storage in GB. 67 pub fn total_gb(&self) -> u64 { 68 self.total_bytes / (1024 * 1024 * 1024) 69 } 70 71 /// Get available storage in GB. 72 pub fn available_gb(&self) -> u64 { 73 self.available_bytes / (1024 * 1024 * 1024) 74 } 75 }