use async_trait::async_trait;
use rand::Rng as _;
use crate::error::{ProxyError, ProxyResult};
use crate::strategy::{ProxyCandidate, RotationStrategy, healthy_candidates};
#[derive(Debug, Default, Clone, Copy)]
pub struct WeightedStrategy;
#[async_trait]
impl RotationStrategy for WeightedStrategy {
async fn select<'a>(
&self,
candidates: &'a [ProxyCandidate],
) -> ProxyResult<&'a ProxyCandidate> {
let healthy: Vec<&ProxyCandidate> = healthy_candidates(candidates)
.into_iter()
.filter(|c| c.weight > 0)
.collect();
if healthy.is_empty() {
return Err(ProxyError::AllProxiesUnhealthy);
}
let total: u64 = healthy.iter().map(|c| c.weight as u64).sum();
let mut cursor: u64 = rand::rng().random_range(0..total);
for candidate in &healthy {
if cursor < candidate.weight as u64 {
return Ok(candidate);
}
cursor -= candidate.weight as u64;
}
Ok(healthy[healthy.len() - 1])
}
}