use std::sync::Arc;
use async_trait::async_trait;
use crate::error::ProxyResult;
use crate::manager::{ProxyHandle, ProxyManager};
#[async_trait]
pub trait ProxyManagerPort: Send + Sync + 'static {
async fn acquire_proxy(&self) -> ProxyResult<ProxyHandle>;
}
pub type BoxedProxyManager = Arc<dyn ProxyManagerPort>;
#[async_trait]
impl ProxyManagerPort for ProxyManager {
async fn acquire_proxy(&self) -> ProxyResult<ProxyHandle> {
Self::acquire_proxy(self).await
}
}
pub struct NoopProxyManager;
#[async_trait]
impl ProxyManagerPort for NoopProxyManager {
async fn acquire_proxy(&self) -> ProxyResult<ProxyHandle> {
Ok(ProxyHandle::direct())
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::*;
use crate::storage::MemoryProxyStore;
use crate::types::{Proxy, ProxyConfig, ProxyType};
fn make_proxy(url: &str) -> Proxy {
Proxy {
url: url.into(),
proxy_type: ProxyType::Http,
username: None,
password: None,
weight: 1,
tags: vec![],
capabilities: crate::types::ProxyCapabilities::default(),
ip_class: crate::types::IpClass::Unknown,
target_compatibility: crate::types::TargetVendorCompatibility::default(),
}
}
#[tokio::test]
async fn noop_returns_direct_handle() -> Result<(), Box<dyn std::error::Error>> {
let noop = NoopProxyManager;
let handle = noop.acquire_proxy().await?;
assert!(
handle.proxy_url.is_empty(),
"direct handle should have empty URL"
);
drop(handle);
Ok(())
}
#[tokio::test]
async fn proxy_manager_implements_port() -> Result<(), Box<dyn std::error::Error>> {
let storage = Arc::new(MemoryProxyStore::default());
let mgr = Arc::new(ProxyManager::with_round_robin(
storage.clone(),
ProxyConfig::default(),
)?);
mgr.add_proxy(make_proxy("http://a.test:8080")).await?;
let port: &dyn ProxyManagerPort = mgr.as_ref();
let handle = port.acquire_proxy().await?;
assert!(!handle.proxy_url.is_empty());
handle.mark_success();
Ok(())
}
}