use crate::core::types::{
ChannelState, ChannelType, DeviceCapabilities, MessagePriority, NetworkType,
};
pub struct Scorer;
impl Scorer {
pub fn score(
channel: ChannelType,
state: &ChannelState,
device_caps: &DeviceCapabilities,
priority: MessagePriority,
) -> f64 {
if !state.available {
return 0.0;
}
let latency_score = 1.0 / (1.0 + (state.rtt_ms as f64 / 10.0).ln().max(0.0));
let reliability_score = 1.0 - state.packet_loss_rate as f64;
let power_cost = channel.power_cost();
let power_score = if device_caps.is_charging {
1.0
} else {
let battery_factor = device_caps.battery_level.unwrap_or(100) as f64 / 100.0;
match power_cost {
1 => 1.0, 2 => 0.8 * (0.5 + 0.5 * battery_factor), 3 => 0.6 * battery_factor, _ => 0.4 * battery_factor, }
};
let cost_score = match state.network_type {
NetworkType::WiFi
| NetworkType::Ethernet
| NetworkType::Loopback
| NetworkType::Bluetooth => 1.0, NetworkType::Cellular4G | NetworkType::Cellular5G => {
if device_caps.data_cost_sensitive {
0.1 } else {
0.6 }
}
NetworkType::Unknown => 0.5,
};
let (w_lat, w_rel, w_pow, w_cost) = match priority {
MessagePriority::Critical => (0.5, 0.4, 0.05, 0.05), MessagePriority::High => (0.4, 0.3, 0.1, 0.2),
MessagePriority::Normal => (0.2, 0.3, 0.2, 0.3),
MessagePriority::Low => (0.1, 0.2, 0.3, 0.4), };
let final_score = (latency_score * w_lat)
+ (reliability_score * w_rel)
+ (power_score * w_pow)
+ (cost_score * w_cost);
final_score.clamp(0.0, 1.0)
}
}