use crate::collectors::command::{run_status, CommandTimeout};
use crate::collectors::drivers::{
DeviceCategory, DeviceInfo, DeviceStatus, DriverData, ServiceInfo,
};
use std::fs;
pub fn collect() -> DriverData {
let mut data = DriverData::default();
collect_network_devices(&mut data);
collect_bluetooth_devices(&mut data);
collect_audio_devices(&mut data);
collect_input_devices(&mut data);
collect_services(&mut data);
data
}
fn collect_network_devices(data: &mut DriverData) {
if let Ok(entries) = fs::read_dir("/sys/class/net") {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
if name == "lo" {
continue; }
let driver_path = format!("/sys/class/net/{}/device/driver", name);
let driver = fs::read_link(&driver_path)
.ok()
.and_then(|p| p.file_name().map(|f| f.to_string_lossy().to_string()))
.unwrap_or_else(|| "unknown".into());
let state_path = format!("/sys/class/net/{}/operstate", name);
let operstate = fs::read_to_string(&state_path)
.unwrap_or_default()
.trim()
.to_string();
let status = match operstate.as_str() {
"up" => DeviceStatus::Ok,
"down" => DeviceStatus::Disabled,
_ => DeviceStatus::Unknown,
};
data.network.push(DeviceInfo {
name,
driver_version: driver,
driver_date: String::new(),
status,
category: DeviceCategory::Network,
extra: operstate,
});
}
}
}
fn collect_bluetooth_devices(data: &mut DriverData) {
if let Ok(entries) = fs::read_dir("/sys/class/bluetooth") {
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
data.bluetooth.push(DeviceInfo {
name,
driver_version: String::new(),
driver_date: String::new(),
status: DeviceStatus::Ok,
category: DeviceCategory::Bluetooth,
extra: String::new(),
});
}
}
if data.bluetooth.is_empty() {
data.bluetooth.push(DeviceInfo {
name: "Bluetooth".into(),
driver_version: String::new(),
driver_date: String::new(),
status: DeviceStatus::NotFound,
category: DeviceCategory::Bluetooth,
extra: String::new(),
});
}
}
fn collect_audio_devices(data: &mut DriverData) {
if let Ok(content) = fs::read_to_string("/proc/asound/cards") {
for line in content.lines() {
let line = line.trim();
if line.starts_with(|c: char| c.is_ascii_digit()) && line.contains(':') {
if let Some(desc) = line.split(':').nth(1) {
data.audio.push(DeviceInfo {
name: desc.trim().to_string(),
driver_version: String::new(),
driver_date: String::new(),
status: DeviceStatus::Ok,
category: DeviceCategory::Audio,
extra: String::new(),
});
}
}
}
}
if data.audio.is_empty() {
data.audio.push(DeviceInfo {
name: "Audio".into(),
driver_version: String::new(),
driver_date: String::new(),
status: DeviceStatus::NotFound,
category: DeviceCategory::Audio,
extra: String::new(),
});
}
}
fn collect_input_devices(data: &mut DriverData) {
if let Ok(content) = fs::read_to_string("/proc/bus/input/devices") {
let mut current_name = String::new();
for line in content.lines() {
if let Some(rest) = line.strip_prefix("N: Name=\"") {
current_name = rest.trim_end_matches('"').to_string();
}
if line.starts_with("H: Handlers=") && !current_name.is_empty() {
let name_lower = current_name.to_lowercase();
if name_lower.contains("keyboard")
|| name_lower.contains("mouse")
|| name_lower.contains("touchpad")
|| name_lower.contains("trackpad")
{
data.input.push(DeviceInfo {
name: current_name.clone(),
driver_version: String::new(),
driver_date: String::new(),
status: DeviceStatus::Ok,
category: DeviceCategory::Input,
extra: String::new(),
});
}
current_name.clear();
}
}
}
if data.input.is_empty() {
data.input.push(DeviceInfo {
name: "Input Devices".into(),
driver_version: String::new(),
driver_date: String::new(),
status: DeviceStatus::Unknown,
category: DeviceCategory::Input,
extra: String::new(),
});
}
}
fn collect_services(data: &mut DriverData) {
let services = [
("NetworkManager", "Network Manager"),
("wpa_supplicant", "WPA Supplicant"),
("bluetooth", "Bluetooth (BlueZ)"),
("pipewire", "PipeWire"),
("pulseaudio", "PulseAudio"),
];
for (name, display) in &services {
let is_running = run_status(
"systemctl",
["is-active", "--quiet", name],
CommandTimeout::Quick,
)
.unwrap_or(false);
data.services.push(ServiceInfo {
name: name.to_string(),
display_name: display.to_string(),
is_running,
});
}
}