use core::time::Duration;
use reqwest;
use crate::error::Error;
use super::Client;
mod setters_core;
#[ cfg( feature = "retry" ) ]
mod setters_retry;
#[ cfg( feature = "circuit_breaker" ) ]
mod setters_circuit_breaker;
#[ cfg( feature = "caching" ) ]
mod setters_caching;
#[ cfg( feature = "rate_limiting" ) ]
mod setters_rate_limiting;
#[ cfg( feature = "compression" ) ]
mod setters_compression;
#[ cfg( feature = "builder_patterns" ) ]
mod presets;
#[ derive( Debug ) ]
#[ allow( clippy::struct_excessive_bools ) ] pub struct ClientBuilder
{
base_url : String,
api_key : Option< String >,
timeout : Duration,
#[ cfg( feature = "retry" ) ]
max_retries : u32,
#[ cfg( feature = "retry" ) ]
base_delay : Duration,
#[ cfg( feature = "retry" ) ]
max_delay : Duration,
#[ cfg( feature = "retry" ) ]
enable_jitter : bool,
#[ cfg( feature = "retry" ) ]
request_timeout : Option< Duration >,
#[ cfg( feature = "retry" ) ]
backoff_multiplier : f64,
#[ cfg( feature = "retry" ) ]
enable_retry_metrics : bool,
#[ cfg( feature = "retry" ) ]
max_elapsed_time : Option< Duration >,
#[ cfg( feature = "circuit_breaker" ) ]
enable_circuit_breaker : bool,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_failure_threshold : u32,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_success_threshold : u32,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_timeout : Duration,
#[ cfg( feature = "circuit_breaker" ) ]
enable_circuit_breaker_metrics : bool,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_shared_state : bool,
#[ cfg( feature = "caching" ) ]
enable_request_cache : bool,
#[ cfg( feature = "caching" ) ]
cache_ttl : Duration,
#[ cfg( feature = "caching" ) ]
cache_max_size : usize,
#[ cfg( feature = "caching" ) ]
enable_cache_metrics : bool,
#[ cfg( feature = "rate_limiting" ) ]
enable_rate_limiting : bool,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_requests_per_second : f64,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_algorithm : String,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_bucket_size : usize,
#[ cfg( feature = "rate_limiting" ) ]
enable_rate_limiting_metrics : bool,
#[ cfg( feature = "compression" ) ]
compression_config : Option< crate::internal::http::compression::CompressionConfig >,
}
impl Default for ClientBuilder
{
#[ inline ]
fn default() -> Self
{
Self::new()
}
}
impl ClientBuilder
{
#[ must_use ]
#[ inline ]
pub fn new() -> Self
{
ClientBuilder
{
base_url : "https://generativelanguage.googleapis.com".to_string(),
api_key : None,
timeout : Duration::from_secs( 30 ),
#[ cfg( feature = "retry" ) ]
max_retries : 3,
#[ cfg( feature = "retry" ) ]
base_delay : Duration::from_millis( 100 ),
#[ cfg( feature = "retry" ) ]
max_delay : Duration::from_secs( 10 ),
#[ cfg( feature = "retry" ) ]
enable_jitter : true,
#[ cfg( feature = "retry" ) ]
request_timeout : None,
#[ cfg( feature = "retry" ) ]
backoff_multiplier : 2.0,
#[ cfg( feature = "retry" ) ]
enable_retry_metrics : false,
#[ cfg( feature = "retry" ) ]
max_elapsed_time : Some( Duration::from_secs( 60 ) ),
#[ cfg( feature = "circuit_breaker" ) ]
enable_circuit_breaker : false,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_failure_threshold : 5,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_success_threshold : 2,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_timeout : Duration::from_secs( 60 ),
#[ cfg( feature = "circuit_breaker" ) ]
enable_circuit_breaker_metrics : false,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_shared_state : false,
#[ cfg( feature = "caching" ) ]
enable_request_cache : false,
#[ cfg( feature = "caching" ) ]
cache_ttl : Duration::from_secs( 300 ),
#[ cfg( feature = "caching" ) ]
cache_max_size : 1000,
#[ cfg( feature = "caching" ) ]
enable_cache_metrics : false,
#[ cfg( feature = "rate_limiting" ) ]
enable_rate_limiting : false,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_requests_per_second : 10.0,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_algorithm : "token_bucket".to_string(),
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_bucket_size : 10,
#[ cfg( feature = "rate_limiting" ) ]
enable_rate_limiting_metrics : false,
#[ cfg( feature = "compression" ) ]
compression_config : None,
}
}
#[ allow( clippy::too_many_lines ) ]
#[ inline ]
pub fn build( self ) -> Result< Client, Error >
{
let api_key = self.api_key
.ok_or_else( || Error::AuthenticationError( "API key is required".to_string() ) )?;
if api_key.is_empty()
{
return Err( Error::AuthenticationError( "API key cannot be empty".to_string() ) );
}
#[ cfg( feature = "retry" ) ]
{
if self.backoff_multiplier <= 1.0
{
return Err( Error::InvalidArgument(
format!( "Backoff multiplier must be greater than 1.0, got : {0}", self.backoff_multiplier )
) );
}
if self.base_delay >= self.max_delay
{
return Err( Error::InvalidArgument(
"Base delay must be less than max delay".to_string()
) );
}
}
#[ cfg( feature = "circuit_breaker" ) ]
{
if self.enable_circuit_breaker
{
if self.circuit_breaker_failure_threshold == 0
{
return Err( Error::InvalidArgument(
"Circuit breaker failure threshold must be greater than 0".to_string()
) );
}
if self.circuit_breaker_success_threshold == 0
{
return Err( Error::InvalidArgument(
"Circuit breaker success threshold must be greater than 0".to_string()
) );
}
if self.circuit_breaker_timeout.is_zero()
{
return Err( Error::InvalidArgument(
"Circuit breaker timeout must be greater than 0".to_string()
) );
}
}
}
#[ cfg( feature = "caching" ) ]
{
if self.enable_request_cache
{
if self.cache_ttl.is_zero()
{
return Err( Error::InvalidArgument(
"Cache TTL must be greater than 0".to_string()
) );
}
if self.cache_max_size == 0
{
return Err( Error::InvalidArgument(
"Cache max size must be greater than 0".to_string()
) );
}
}
}
#[ cfg( feature = "rate_limiting" ) ]
{
if self.enable_rate_limiting
{
if self.rate_limit_requests_per_second <= 0.0
{
return Err( Error::InvalidArgument(
"Rate limit requests per second must be greater than 0.0".to_string()
) );
}
if self.rate_limit_bucket_size == 0
{
return Err( Error::InvalidArgument(
"Rate limit bucket size must be greater than 0".to_string()
) );
}
match self.rate_limit_algorithm.as_str()
{
"token_bucket" | "sliding_window" | "adaptive" => {},
invalid => {
return Err( Error::InvalidArgument(
format!( "Invalid rate limiting algorithm '{invalid}'. Valid options : 'token_bucket', 'sliding_window', 'adaptive'" )
) );
}
}
}
}
let http_client = reqwest::Client::builder()
.timeout( self.timeout )
.build()
.map_err( |e| Error::NetworkError( format!( "Failed to create HTTP client : {e}" ) ) )?;
#[ cfg( feature = "caching" ) ]
let request_cache = if self.enable_request_cache
{
let cache_config = crate::internal::http::CacheConfig {
max_size : self.cache_max_size,
ttl : self.cache_ttl,
enable_metrics : self.enable_cache_metrics,
};
Some( std::sync::Arc::new( crate::internal::http::RequestCache::new( cache_config ) ) )
} else {
None
};
Ok( Client
{
api_key,
base_url : self.base_url,
http : http_client,
timeout : self.timeout,
#[ cfg( feature = "retry" ) ]
max_retries : self.max_retries,
#[ cfg( feature = "retry" ) ]
base_delay : self.base_delay,
#[ cfg( feature = "retry" ) ]
max_delay : self.max_delay,
#[ cfg( feature = "retry" ) ]
enable_jitter : self.enable_jitter,
#[ cfg( feature = "retry" ) ]
request_timeout : self.request_timeout,
#[ cfg( feature = "retry" ) ]
backoff_multiplier : self.backoff_multiplier,
#[ cfg( feature = "retry" ) ]
enable_retry_metrics : self.enable_retry_metrics,
#[ cfg( feature = "retry" ) ]
max_elapsed_time : self.max_elapsed_time,
#[ cfg( feature = "circuit_breaker" ) ]
enable_circuit_breaker : self.enable_circuit_breaker,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_failure_threshold : self.circuit_breaker_failure_threshold,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_success_threshold : self.circuit_breaker_success_threshold,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_timeout : self.circuit_breaker_timeout,
#[ cfg( feature = "circuit_breaker" ) ]
enable_circuit_breaker_metrics : self.enable_circuit_breaker_metrics,
#[ cfg( feature = "circuit_breaker" ) ]
circuit_breaker_shared_state : self.circuit_breaker_shared_state,
#[ cfg( feature = "caching" ) ]
enable_request_cache : self.enable_request_cache,
#[ cfg( feature = "caching" ) ]
cache_ttl : self.cache_ttl,
#[ cfg( feature = "caching" ) ]
cache_max_size : self.cache_max_size,
#[ cfg( feature = "caching" ) ]
enable_cache_metrics : self.enable_cache_metrics,
#[ cfg( feature = "caching" ) ]
request_cache,
#[ cfg( feature = "rate_limiting" ) ]
enable_rate_limiting : self.enable_rate_limiting,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_requests_per_second : self.rate_limit_requests_per_second,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_algorithm : self.rate_limit_algorithm,
#[ cfg( feature = "rate_limiting" ) ]
rate_limit_bucket_size : self.rate_limit_bucket_size,
#[ cfg( feature = "rate_limiting" ) ]
enable_rate_limiting_metrics : self.enable_rate_limiting_metrics,
#[ cfg( feature = "compression" ) ]
compression_config : self.compression_config,
} )
}
}