use crate::capability::manager::CapabilityManager;
use crate::core::types::{ChannelType, DeviceCapabilities, DeviceType};
use log::{debug, info};
use std::collections::HashSet;
use std::sync::Arc;
use sysinfo::{System, SystemExt};
pub struct LocalCapabilityDetector {
manager: Arc<CapabilityManager>,
system: System,
}
impl LocalCapabilityDetector {
pub fn new(manager: Arc<CapabilityManager>) -> Self {
let mut system = System::new();
system.refresh_system();
system.refresh_memory();
system.refresh_cpu();
Self { manager, system }
}
pub fn detect_and_update(&mut self) {
debug!("Starting local capability detection...");
self.system.refresh_system();
self.system.refresh_memory();
self.system.refresh_cpu();
let old_caps = self.manager.get_local_caps();
let mut supported_channels = HashSet::new();
if self.detect_lan_support() {
supported_channels.insert(ChannelType::Lan);
supported_channels.insert(ChannelType::Internet); }
supported_channels.insert(ChannelType::BluetoothLE);
let (battery_level, is_charging) = self.get_battery_info();
let device_type = self.infer_device_type();
let new_caps = DeviceCapabilities {
device_id: old_caps.device_id,
device_type,
device_name: self
.system
.host_name()
.unwrap_or_else(|| "Unknown Device".to_string()),
supported_channels,
battery_level,
is_charging,
data_cost_sensitive: false, };
info!(
"Local capabilities detected: {} (Type: {:?}, Channels: {:?})",
new_caps.device_name, new_caps.device_type, new_caps.supported_channels
);
self.manager.update_local_capabilities(new_caps);
}
fn detect_lan_support(&self) -> bool {
pnet_datalink::interfaces()
.iter()
.any(|iface| !iface.is_loopback() && iface.is_up() && !iface.ips.is_empty())
}
fn get_battery_info(&self) -> (Option<u8>, bool) {
#[cfg(target_os = "linux")]
{
if let Ok(entries) = std::fs::read_dir("/sys/class/power_supply/") {
for entry in entries.flatten() {
let path = entry.path();
let name = path.file_name().and_then(|s| s.to_str()).unwrap_or("");
if name.starts_with("BAT") {
let capacity = std::fs::read_to_string(path.join("capacity"))
.ok()
.and_then(|s| s.trim().parse::<u8>().ok());
let status = std::fs::read_to_string(path.join("status"))
.unwrap_or_else(|_| "Unknown".to_string());
let is_charging = status.trim() == "Charging" || status.trim() == "Full";
return (capacity, is_charging);
}
}
}
}
#[cfg(target_os = "android")]
{
}
(None, true) }
fn infer_device_type(&self) -> DeviceType {
#[cfg(target_os = "android")]
return DeviceType::Smartphone;
#[cfg(target_os = "ios")]
return DeviceType::Smartphone;
let os_name = self.system.name().unwrap_or_default().to_lowercase();
if os_name.contains("windows") || os_name.contains("darwin") || os_name.contains("linux") {
return DeviceType::Laptop;
}
DeviceType::Server
}
}