use std::sync::Arc;
use async_trait::async_trait;
use crate::error::ProxyResult;
use crate::manager::{ProxyHandle, ProxyManager};
#[async_trait]
pub trait BrowserProxySource: Send + Sync + 'static {
async fn bind_proxy(&self) -> ProxyResult<(String, ProxyHandle)>;
}
pub struct ProxyManagerBridge {
manager: Arc<ProxyManager>,
}
impl ProxyManagerBridge {
pub fn new(manager: Arc<ProxyManager>) -> Self {
Self { manager }
}
}
#[async_trait]
impl BrowserProxySource for ProxyManagerBridge {
async fn bind_proxy(&self) -> ProxyResult<(String, ProxyHandle)> {
let handle = self.manager.acquire_proxy().await?;
let url = handle.proxy_url.clone();
Ok((url, handle))
}
}
#[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![],
}
}
#[tokio::test]
async fn bridge_returns_proxy_url_and_handle() {
let storage = Arc::new(MemoryProxyStore::default());
let mgr = Arc::new(
ProxyManager::with_round_robin(storage.clone(), ProxyConfig::default()).unwrap(),
);
mgr.add_proxy(make_proxy("http://p.test:8080"))
.await
.unwrap();
let bridge = ProxyManagerBridge::new(mgr);
let (url, handle) = bridge.bind_proxy().await.unwrap();
assert_eq!(url, "http://p.test:8080");
handle.mark_success();
}
#[tokio::test]
async fn crash_records_failure() {
let storage = Arc::new(MemoryProxyStore::default());
let mgr = Arc::new(
ProxyManager::with_round_robin(
storage.clone(),
ProxyConfig {
circuit_open_threshold: 1,
..ProxyConfig::default()
},
)
.unwrap(),
);
mgr.add_proxy(make_proxy("http://q.test:8080"))
.await
.unwrap();
let bridge = ProxyManagerBridge::new(Arc::clone(&mgr));
{
let (_url, _handle) = bridge.bind_proxy().await.unwrap();
}
let stats = mgr.pool_stats().await.unwrap();
assert_eq!(
stats.open, 1,
"circuit should open after crash (open = {})",
stats.open
);
}
#[test]
fn direct_handle_is_valid_noop_binding() {
let handle = ProxyHandle::direct();
assert!(handle.proxy_url.is_empty());
handle.mark_success();
}
}