zeloxy 0.5.1

A library for creating lightweight, async, and lag-free proxy connections.
Documentation
use std::sync::Arc;
use std::time::Duration;

use crate::chain::ProxyChain;
use crate::proxy::Proxy;
use crate::tools::{ping_proxy_chain_parallel, ping_proxy_parallel};

/// Функция сравнения разных прокси по скорости и выбора лучшего
pub async fn compare_proxies(proxies: Vec<impl Into<Proxy>>, timeout: Option<u64>) -> Option<Proxy> {
  let mut tasks = Vec::with_capacity(proxies.len());

  for proxy_impl in proxies {
    let proxy_arc = Arc::new(proxy_impl.into());
    let task_proxy = proxy_arc.clone();
    let task = tokio::spawn(ping_proxy_parallel(task_proxy, None));
    tasks.push((proxy_arc, task));
  }

  let mut results = Vec::with_capacity(tasks.len());

  for (proxy, task) in tasks {
    let info;

    if let Some(t) = timeout {
      info = match tokio::time::timeout(Duration::from_millis(t), task).await {
        Ok(r) => match r {
          Ok(i) => i,
          Err(_) => continue,
        },
        Err(_) => continue,
      };
    } else {
      info = match task.await {
        Ok(i) => i,
        Err(_) => continue,
      };
    }

    results.push((proxy, info));
  }

  let mut current_min_ping = None;
  let mut best_proxy = None;

  for (proxy, info) in results {
    if let Some(min_ping) = current_min_ping {
      if let Some(average_ping) = info.average_ping {
        if min_ping > average_ping {
          current_min_ping = Some(average_ping);
          best_proxy = Some(Proxy::from(proxy));
        }
      }
    } else {
      current_min_ping = info.average_ping;
      best_proxy = Some(Proxy::from(proxy));
    }
  }

  best_proxy
}

/// Функция сравнения разных цепочек прокси по скорости и выбора лучшей.
/// Рекомендуется ограничивать максимальное время сравнения с помощью аргумента
/// `timeout` (в мс), без ограничения времени сравнение цепочек может идти долго
pub async fn compare_proxy_chains(chains: Vec<impl Into<ProxyChain>>, timeout: Option<u64>) -> Option<ProxyChain> {
  let mut tasks = Vec::with_capacity(chains.len());

  for chain_impl in chains {
    let chain_arc = Arc::new(chain_impl.into());
    let task_chain = chain_arc.clone();
    let task = tokio::spawn(ping_proxy_chain_parallel(task_chain, None));
    tasks.push((chain_arc, task));
  }

  let mut results = Vec::with_capacity(tasks.len());

  for (chain, task) in tasks {
    let info;

    if let Some(t) = timeout {
      info = match tokio::time::timeout(Duration::from_millis(t), task).await {
        Ok(r) => match r {
          Ok(i) => i,
          Err(_) => continue,
        },
        Err(_) => continue,
      };
    } else {
      info = match task.await {
        Ok(i) => i,
        Err(_) => continue,
      };
    }

    results.push((chain, info));
  }

  let mut current_min_ping = None;
  let mut best_chain = None;

  for (chain, info) in results {
    if let Some(min_ping) = current_min_ping {
      if let Some(average_ping) = info.average_ping {
        if min_ping > average_ping {
          current_min_ping = Some(average_ping);
          best_chain = Some(ProxyChain::from(chain));
        }
      }
    } else {
      current_min_ping = info.average_ping;
      best_chain = Some(ProxyChain::from(chain));
    }
  }

  best_chain
}