Skip to main content

antibot_rs/
lib.rs

1//! Auto-managed Byparr/FlareSolverr client for bypassing bot detection.
2//!
3//! Provides a unified client for the FlareSolverr-compatible API used by both
4//! [Byparr](https://github.com/thephaseless/byparr) and
5//! [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr).
6//!
7//! # Features
8//! - Automatic Docker container lifecycle (pull, start, health-wait, restart, drop)
9//! - Provider-agnostic: Byparr, FlareSolverr, or any compatible image
10//! - Builder-style [`SolveRequest`] with GET/POST, headers, cookies, proxy, sessions, fingerprint
11//! - Per-domain session/cookie cache so repeat solves are free
12//! - Concurrent-solve coalescer that dedupes parallel solves
13//! - Retry policy with exponential backoff
14//! - Lock-free [`MetricsSnapshot`] for observability
15//! - Optional disk-replay sink for debugging
16//! - Round-robin across multiple instances
17//! - `solve_stream` for batch use with bounded concurrency
18//! - Standalone [`detect`] helpers for cheap challenge fingerprinting
19//!
20//! # Quick start
21//! ```no_run
22//! use antibot_rs::{Antibot, Provider};
23//!
24//! # async fn example() -> Result<(), antibot_rs::AntibotError> {
25//! let client = Antibot::builder()
26//!     .provider(Provider::Byparr)
27//!     .auto_start(true)
28//!     .enable_session_cache()
29//!     .build()
30//!     .await?;
31//!
32//! let solution = client.solve("https://example.com").await?;
33//! println!("Got {} bytes of HTML", solution.html().len());
34//! # Ok(())
35//! # }
36//! ```
37//!
38//! # Full-featured example
39//! ```no_run
40//! use antibot_rs::{
41//!     Antibot, CoalesceKey, Cookie, DebugConfig, DockerLimits, ProxyConfig,
42//!     Provider, RetryPolicy, SolveRequest,
43//! };
44//! use std::time::Duration;
45//!
46//! # async fn example() -> Result<(), antibot_rs::AntibotError> {
47//! let client = Antibot::builder()
48//!     .provider(Provider::Byparr)
49//!     .auto_start(true)
50//!     .docker_limits(DockerLimits::default().memory("2g").cpus("1.5").shm_size("1g"))
51//!     .enable_session_cache()
52//!     .coalesce_solves(CoalesceKey::Domain)
53//!     .retry(RetryPolicy::default())
54//!     .default_proxy(ProxyConfig::http("http://proxy.example:8080"))
55//!     .debug(DebugConfig::new("./antibot-replay"))
56//!     .health_watch(Duration::from_secs(30))
57//!     .manage_lifecycle(true)
58//!     .build()
59//!     .await?;
60//!
61//! let solution = client.execute(
62//!     SolveRequest::post("https://site.com/api/login")
63//!         .json(serde_json::json!({"user": "alice"}))
64//!         .with_header("X-Custom", "value")
65//!         .with_cookie(Cookie::new("session", "abc123"))
66//! ).await?;
67//! # let _ = solution;
68//! # Ok(())
69//! # }
70//! ```
71
72mod client;
73mod coalesce;
74mod cookie;
75mod debug_replay;
76pub mod detect;
77mod docker;
78mod error;
79mod fingerprint;
80mod metrics;
81mod proxy;
82mod request;
83mod retry;
84mod session_cache;
85mod stream;
86mod types;
87mod wire;
88
89pub use client::{merge_cookies, Antibot, AntibotBuilder, SessionHandle};
90pub use coalesce::CoalesceKey;
91pub use cookie::{Cookie, SameSite};
92pub use debug_replay::DebugConfig;
93pub use detect::{detect_challenge, ChallengeKind, DetectionInput};
94pub use docker::DockerLimits;
95pub use error::AntibotError;
96pub use fingerprint::{BrowserFingerprint, Viewport};
97pub use metrics::MetricsSnapshot;
98pub use proxy::ProxyConfig;
99pub use request::{PostBody, SolveMethod, SolveRequest};
100pub use retry::RetryPolicy;
101pub use session_cache::{CachedSession, SessionCacheConfig};
102pub use stream::SolveStream;
103pub use types::{Solution, SolutionSource};
104
105/// Re-export of `futures::StreamExt` so callers don't need a direct dep
106/// just to consume [`Antibot::solve_stream`].
107pub use futures::StreamExt;
108
109/// Docker image provider for the challenge-solving proxy.
110#[derive(Debug, Clone, Default)]
111pub enum Provider {
112    /// Byparr — recommended, actively maintained.
113    #[default]
114    Byparr,
115    /// FlareSolverr — the original implementation.
116    FlareSolverr,
117    /// Custom Docker image with a FlareSolverr-compatible `/v1` endpoint.
118    Custom(String),
119}
120
121impl Provider {
122    pub fn image(&self) -> &str {
123        match self {
124            Provider::Byparr => "ghcr.io/thephaseless/byparr:latest",
125            Provider::FlareSolverr => "ghcr.io/flaresolverr/flaresolverr:latest",
126            Provider::Custom(image) => image,
127        }
128    }
129
130    pub fn label(&self) -> &str {
131        match self {
132            Provider::Byparr => "Byparr",
133            Provider::FlareSolverr => "FlareSolverr",
134            Provider::Custom(_) => "Custom",
135        }
136    }
137}
138
139impl std::fmt::Display for Provider {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        write!(f, "{} ({})", self.label(), self.image())
142    }
143}