pub struct ProxyManager { /* private fields */ }Expand description
Unified proxy pool orchestrator.
Manage proxies via add_proxy and
remove_proxy, acquire one via
acquire_proxy, and start background
health checking with start.
§Quick start
use std::sync::Arc;
use stygian_proxy::{ProxyManager, ProxyConfig, Proxy, ProxyType};
use stygian_proxy::storage::MemoryProxyStore;
use stygian_proxy::types::{IpClass, ProxyCapabilities, TargetVendorCompatibility};
let storage = Arc::new(MemoryProxyStore::default());
let mgr = ProxyManager::with_round_robin(storage, ProxyConfig::default())?;
let (token, _handle) = mgr.start();
let proxy = mgr.add_proxy(Proxy {
url: "http://proxy.example.com:8080".into(),
proxy_type: ProxyType::Http,
username: None,
password: None,
weight: 1,
tags: vec![],
capabilities: ProxyCapabilities::default(),
ip_class: IpClass::Unknown,
target_compatibility: TargetVendorCompatibility::default(),
}).await?;
let handle = mgr.acquire_proxy().await?;
handle.mark_success();
token.cancel();Implementations§
Source§impl ProxyManager
impl ProxyManager
Sourcepub fn builder() -> ProxyManagerBuilder
pub fn builder() -> ProxyManagerBuilder
Start a ProxyManagerBuilder.
Sourcepub fn with_round_robin(
storage: Arc<dyn ProxyStoragePort>,
config: ProxyConfig,
) -> ProxyResult<Self>
pub fn with_round_robin( storage: Arc<dyn ProxyStoragePort>, config: ProxyConfig, ) -> ProxyResult<Self>
Convenience: round-robin rotation (default).
§Errors
Returns ProxyError::ConfigError when no storage is supplied to
the underlying builder.
Sourcepub fn with_random(
storage: Arc<dyn ProxyStoragePort>,
config: ProxyConfig,
) -> ProxyResult<Self>
pub fn with_random( storage: Arc<dyn ProxyStoragePort>, config: ProxyConfig, ) -> ProxyResult<Self>
Convenience: random rotation.
§Errors
Returns ProxyError::ConfigError when no storage is supplied to
the underlying builder.
Sourcepub fn with_weighted(
storage: Arc<dyn ProxyStoragePort>,
config: ProxyConfig,
) -> ProxyResult<Self>
pub fn with_weighted( storage: Arc<dyn ProxyStoragePort>, config: ProxyConfig, ) -> ProxyResult<Self>
Convenience: weighted rotation.
§Errors
Returns ProxyError::ConfigError when no storage is supplied to
the underlying builder.
Sourcepub fn with_least_used(
storage: Arc<dyn ProxyStoragePort>,
config: ProxyConfig,
) -> ProxyResult<Self>
pub fn with_least_used( storage: Arc<dyn ProxyStoragePort>, config: ProxyConfig, ) -> ProxyResult<Self>
Convenience: least-used rotation.
§Errors
Returns ProxyError::ConfigError when no storage is supplied to
the underlying builder.
Sourcepub async fn add_proxy(&self, proxy: Proxy) -> ProxyResult<Uuid>
pub async fn add_proxy(&self, proxy: Proxy) -> ProxyResult<Uuid>
Add a proxy and register a circuit breaker for it. Returns the new ID.
The circuit_breakers write lock is held for the duration of the storage
write. This is intentional: acquire_proxy holds
a read lock on the same map while it inspects candidates, so it cannot
proceed past that point until both the storage record and its CB entry
exist. Without this ordering a concurrent acquire_proxy could select
the new proxy before its CB was registered, breaking failure accounting.
§Errors
Returns ProxyError::StorageError when the underlying storage backend
rejects the new proxy record, or
ProxyError::InvalidGeoMetadata
when the proxy’s geo-metadata fields fail ingest validation
(e.g. asn = 0, city = "", postal_code = "").
Sourcepub async fn remove_proxy(&self, id: Uuid) -> ProxyResult<()>
pub async fn remove_proxy(&self, id: Uuid) -> ProxyResult<()>
Remove a proxy from the pool and drop its circuit breaker.
§Errors
Returns ProxyError::StorageError when the underlying storage backend
reports the proxy as missing or the remove call fails.
Sourcepub async fn add_proxy_with_metadata(
&self,
url: &str,
asn: Option<u32>,
city: Option<&str>,
postal_code: Option<&str>,
) -> ProxyResult<Uuid>
pub async fn add_proxy_with_metadata( &self, url: &str, asn: Option<u32>, city: Option<&str>, postal_code: Option<&str>, ) -> ProxyResult<Uuid>
Add a proxy with explicit geo metadata (ASN, city, postal code).
Convenience constructor for operator-curated pools that target
specific geographic or network ranges — the “Infatica-style
city, ZIP, and ASN filter” cited by the 2026 guide (L2837).
Constructs the Proxy and underlying
crate::ProxyCapabilities for the caller, populates the geo
fields, and runs the same ingest validation as
add_proxy (so asn = 0, city = "",
etc. are rejected with
ProxyError::InvalidGeoMetadata
before the record is stored).
The proxy_type, username, password, weight, tags, and
remaining ProxyCapabilities fields take their
Default::default() values; callers that need finer control
over those should build a Proxy directly and call
add_proxy instead.
§Example
use std::sync::Arc;
use stygian_proxy::{ProxyManager, ProxyConfig};
use stygian_proxy::storage::MemoryProxyStore;
use stygian_proxy::types::well_known::KNOWN_ASN_CLOUDFLARE;
let store = Arc::new(MemoryProxyStore::default());
let mgr = ProxyManager::with_round_robin(store, ProxyConfig::default())?;
let _id = mgr.add_proxy_with_metadata(
"http://cf-exit.example.com:8080",
Some(KNOWN_ASN_CLOUDFLARE),
Some("San Francisco"),
Some("94110"),
).await?;§Errors
Returns ProxyError::InvalidProxyUrl
when url is malformed, or
ProxyError::InvalidGeoMetadata
when any geo field fails the validation rules documented in
crate::types::validate_asn, crate::types::validate_city,
or crate::types::validate_postal_code. Storage failures
surface as ProxyError::StorageError.
Sourcepub fn start(&self) -> (CancellationToken, JoinHandle<()>)
pub fn start(&self) -> (CancellationToken, JoinHandle<()>)
Spawn the background health-check and session-purge tasks.
Returns a (CancellationToken, JoinHandle) pair. Cancel the token to
trigger a graceful shutdown; await the handle to ensure it finishes.
Sourcepub fn strategy_warmup_observe(&self, proxy_id: Uuid, success: bool)
pub fn strategy_warmup_observe(&self, proxy_id: Uuid, success: bool)
Pre-warm the Bayesian observer with a synthetic outcome for a proxy.
This is the same call that ProxyHandle::mark_success and the
Drop impl make at runtime, exposed publicly so callers can
pre-seed the bandit from a known-good (or known-bad) prior before
serving traffic. Most useful for tests and for warm-starting the
pool from an external health-check feed.
Sourcepub fn storage(&self) -> &Arc<dyn ProxyStoragePort> ⓘ
pub fn storage(&self) -> &Arc<dyn ProxyStoragePort> ⓘ
Read-only view of the underlying proxy storage. Useful for
tests, MCP introspection, and warm-up helpers that need to map
url → id without traversing the public API surface.
Sourcepub async fn acquire_proxy(&self) -> ProxyResult<ProxyHandle>
pub async fn acquire_proxy(&self) -> ProxyResult<ProxyHandle>
Acquire a proxy from the pool.
Builds ProxyCandidate entries from current storage, consulting the
health map and each proxy’s circuit breaker to set the healthy flag.
Delegates selection to the configured crate::strategy::RotationStrategy.
§Errors
Returns ProxyError::StorageError when the storage backend cannot list
proxies, or ProxyError::NoCompatibleProxy when no healthy proxy
is available.
Sourcepub async fn acquire_with_capabilities(
&self,
req: &CapabilityRequirement,
) -> ProxyResult<ProxyHandle>
pub async fn acquire_with_capabilities( &self, req: &CapabilityRequirement, ) -> ProxyResult<ProxyHandle>
Acquire a proxy that satisfies req from the pool.
Filters the candidate list to healthy proxies whose
ProxyCapabilities satisfy every
flag in req, then delegates to the configured rotation strategy.
Returns ProxyError::NoCompatibleProxy when no healthy proxy meets
the capability requirements.
§Example
use stygian_proxy::{ProxyManager, ProxyManagerBuilder, CapabilityRequirement};
async fn example(manager: &ProxyManager) {
let req = CapabilityRequirement { require_https_connect: true, ..Default::default() };
let handle = manager.acquire_with_capabilities(&req).await.unwrap();
println!("url: {}", handle.proxy_url);
}§Errors
Returns ProxyError::StorageError when the storage backend cannot list
proxies, or ProxyError::NoCompatibleProxy when no healthy proxy
satisfies the supplied CapabilityRequirement.
Sourcepub async fn acquire_for_domain(&self, domain: &str) -> ProxyResult<ProxyHandle>
pub async fn acquire_for_domain(&self, domain: &str) -> ProxyResult<ProxyHandle>
Acquire a proxy for domain, honouring the configured sticky-session
policy.
- When
StickyPolicy::Disabledis active, behaves identically toacquire_proxy. - When
StickyPolicy::Domainis active and a fresh session exists fordomain, the same proxy is returned for the TTL duration. - If the bound proxy’s circuit breaker has tripped or the proxy has been removed, the stale session is invalidated and a fresh proxy is acquired and bound.
The returned ProxyHandle automatically invalidates the session on
drop if not marked as successful.
§Errors
Returns ProxyError::StorageError when the storage backend fails, or
ProxyError::NoCompatibleProxy when no healthy proxy is available
(including when a sticky-bound proxy is unhealthy and the fallback
also exhausts the pool).
Sourcepub async fn pool_stats(&self) -> ProxyResult<PoolStats>
pub async fn pool_stats(&self) -> ProxyResult<PoolStats>
Return a health snapshot of the pool.
§Errors
Returns ProxyError::StorageError when the storage backend cannot list
proxies, or when the internal lock is poisoned.