Skip to main content

stygian_proxy/strategy/
random.rs

1//! Random proxy rotation strategy.
2
3use async_trait::async_trait;
4use rand::prelude::IndexedRandom as _;
5
6use crate::error::{ProxyError, ProxyResult};
7use crate::strategy::{ProxyCandidate, RotationStrategy, healthy_candidates};
8
9/// Selects a healthy proxy uniformly at random on each call.
10///
11/// Stateless — no lock or shared counter required.
12///
13/// # Example
14/// ```
15/// # tokio_test::block_on(async {
16/// use stygian_proxy::strategy::{RandomStrategy, RotationStrategy, ProxyCandidate};
17/// use stygian_proxy::types::ProxyMetrics;
18/// use std::sync::Arc;
19/// use uuid::Uuid;
20///
21/// let strategy = RandomStrategy;
22/// let candidates = vec![
23///     ProxyCandidate { id: Uuid::new_v4(), weight: 1, metrics: Arc::new(ProxyMetrics::default()), healthy: true },
24/// ];
25/// strategy.select(&candidates).await.unwrap();
26/// # })
27/// ```
28#[derive(Debug, Default, Clone, Copy)]
29pub struct RandomStrategy;
30
31#[async_trait]
32impl RotationStrategy for RandomStrategy {
33    async fn select<'a>(
34        &self,
35        candidates: &'a [ProxyCandidate],
36    ) -> ProxyResult<&'a ProxyCandidate> {
37        let healthy = healthy_candidates(candidates);
38        healthy
39            .choose(&mut rand::rng())
40            .copied()
41            .ok_or(ProxyError::AllProxiesUnhealthy)
42    }
43}