aios_collector/
system_collector.rs1use aios_spec::{LocationType, NetworkType, RingerMode, SystemStateEvent};
9
10pub struct SystemStateCollector;
12
13impl SystemStateCollector {
14 pub fn snapshot(timestamp_ms: i64) -> SystemStateEvent {
23 SystemStateEvent {
24 timestamp_ms,
25 battery_pct: Self::read_battery(),
26 is_charging: Self::read_charging(),
27 network: Self::detect_network(),
28 ringer_mode: RingerMode::Normal,
29 location_type: LocationType::Unknown,
30 headphone_connected: false,
31 bluetooth_connected: false,
32 }
33 }
34
35 fn read_battery() -> Option<u8> {
37 let paths = [
39 "/sys/class/power_supply/battery/capacity",
40 "/sys/class/power_supply/BAT0/capacity",
41 "/sys/class/power_supply/BAT1/capacity",
42 ];
43
44 for path in &paths {
45 if let Ok(content) = std::fs::read_to_string(path) {
46 if let Ok(pct) = content.trim().parse::<u8>() {
47 return Some(pct);
48 }
49 }
50 }
51 None
52 }
53
54 fn read_charging() -> bool {
56 let paths = [
57 "/sys/class/power_supply/battery/status",
58 "/sys/class/power_supply/BAT0/status",
59 ];
60
61 for path in &paths {
62 if let Ok(content) = std::fs::read_to_string(path) {
63 return content.trim().to_lowercase().contains("charging");
64 }
65 }
66 false
67 }
68
69 fn detect_network() -> NetworkType {
71 if let Ok(entries) = std::fs::read_dir("/sys/class/net") {
73 for entry in entries.flatten() {
74 let name = entry.file_name();
75 let name_str = name.to_string_lossy();
76 let operstate_path = entry.path().join("operstate");
77
78 if let Ok(state) = std::fs::read_to_string(&operstate_path) {
79 let up = state.trim() == "up";
80
81 if up && (name_str.starts_with("wlan") || name_str == "wlan0") {
82 return NetworkType::Wifi;
83 }
84 if up && (name_str.starts_with("rmnet") || name_str.starts_with("wwan")) {
85 return NetworkType::Cellular;
86 }
87 }
88 }
89
90 if std::fs::read_to_string("/sys/class/net/eth0/operstate")
92 .map(|s| s.trim() == "up")
93 .unwrap_or(false)
94 {
95 return NetworkType::Wifi; }
97 }
98
99 NetworkType::Unknown
100 }
101}