use crate::YahooError;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct YahooConnectorBuilder {
pub(crate) rate_limit: f64,
pub(crate) circuit_breaker_threshold: u32,
pub(crate) circuit_breaker_window_secs: u64,
pub(crate) circuit_breaker_timeout_secs: u64,
pub(crate) retry_attempts: u32,
pub(crate) retry_initial_delay_ms: u64,
pub(crate) retry_max_delay_ms: u64,
pub(crate) timeout: Duration,
pub(crate) cache_size: usize,
pub(crate) cache_duration_secs: u64,
pub(crate) connection_pool_max: usize,
pub(crate) verbose_logging: bool,
pub(crate) enable_metrics: bool,
pub(crate) enable_tracing: bool,
}
impl Default for YahooConnectorBuilder {
fn default() -> Self {
Self {
rate_limit: 10.0,
circuit_breaker_threshold: 10,
circuit_breaker_window_secs: 60,
circuit_breaker_timeout_secs: 30,
retry_attempts: 3,
retry_initial_delay_ms: 1000,
retry_max_delay_ms: 10_000,
timeout: Duration::from_secs(30),
cache_size: 500,
cache_duration_secs: 30,
connection_pool_max: 10,
verbose_logging: true,
enable_metrics: true,
enable_tracing: false,
}
}
}
impl YahooConnectorBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn production() -> Self {
Self {
rate_limit: 0.5,
circuit_breaker_threshold: 5,
circuit_breaker_window_secs: 300, circuit_breaker_timeout_secs: 60,
retry_attempts: 5,
retry_initial_delay_ms: 1000,
retry_max_delay_ms: 30_000,
timeout: Duration::from_secs(60),
cache_size: 2000,
cache_duration_secs: 900,
connection_pool_max: 50,
verbose_logging: false,
enable_metrics: true,
enable_tracing: true,
}
}
pub fn enterprise() -> Self {
Self {
rate_limit: 0.5,
circuit_breaker_threshold: 8,
circuit_breaker_window_secs: 180, circuit_breaker_timeout_secs: 45,
retry_attempts: 4,
retry_initial_delay_ms: 1500,
retry_max_delay_ms: 20_000,
timeout: Duration::from_secs(45),
cache_size: 3000,
cache_duration_secs: 300,
connection_pool_max: 100,
verbose_logging: false,
enable_metrics: true,
enable_tracing: true,
}
}
pub fn minimal() -> Self {
Self {
rate_limit: 1000.0,
circuit_breaker_threshold: 1000,
circuit_breaker_window_secs: 1,
circuit_breaker_timeout_secs: 1,
retry_attempts: 0,
retry_initial_delay_ms: 0,
retry_max_delay_ms: 0,
timeout: Duration::from_secs(10),
cache_size: 0,
cache_duration_secs: 0,
connection_pool_max: 1,
verbose_logging: false,
enable_metrics: false,
enable_tracing: false,
}
}
pub fn rate_limit(mut self, requests_per_second: f64) -> Self {
self.rate_limit = requests_per_second;
self
}
pub fn circuit_breaker_threshold(mut self, threshold: u32) -> Self {
self.circuit_breaker_threshold = threshold;
self
}
pub fn circuit_breaker_window_secs(mut self, seconds: u64) -> Self {
self.circuit_breaker_window_secs = seconds;
self
}
pub fn circuit_breaker_timeout_secs(mut self, seconds: u64) -> Self {
self.circuit_breaker_timeout_secs = seconds;
self
}
pub fn retry_attempts(mut self, attempts: u32) -> Self {
self.retry_attempts = attempts;
self
}
pub fn retry_initial_delay_ms(mut self, milliseconds: u64) -> Self {
self.retry_initial_delay_ms = milliseconds;
self
}
pub fn retry_max_delay_ms(mut self, milliseconds: u64) -> Self {
self.retry_max_delay_ms = milliseconds;
self
}
pub fn timeout(mut self, duration: Duration) -> Self {
self.timeout = duration;
self
}
pub fn cache_size(mut self, size: usize) -> Self {
self.cache_size = size;
self
}
pub fn cache_duration(mut self, seconds: u64) -> Self {
self.cache_duration_secs = seconds;
self
}
pub fn connection_pool_max(mut self, max_connections: usize) -> Self {
self.connection_pool_max = max_connections;
self
}
pub fn verbose_logging(mut self, enabled: bool) -> Self {
self.verbose_logging = enabled;
self
}
pub fn enable_metrics(mut self, enabled: bool) -> Self {
self.enable_metrics = enabled;
self
}
pub fn enable_tracing(mut self, enabled: bool) -> Self {
self.enable_tracing = enabled;
self
}
pub fn build(self) -> Result<crate::YahooConnector, YahooError> {
use crate::rate_limiter::RateLimitConfig;
use std::time::Duration;
self.validate()?;
let rate_limit_config = RateLimitConfig {
requests_per_hour: self.rate_limit as u32,
burst_limit: 10, min_interval: Duration::from_millis(100), };
crate::YahooConnectorBuilderLegacy::new()
.rate_limit_config(rate_limit_config)
.timeout(self.timeout)
.build()
}
fn validate(&self) -> Result<(), YahooError> {
if self.rate_limit <= 0.0 {
return Err(YahooError::InvalidStatusCode(
"Rate limit must be greater than 0".into(),
));
}
if self.circuit_breaker_threshold == 0 {
return Err(YahooError::InvalidStatusCode(
"Circuit breaker threshold must be greater than 0".into(),
));
}
if self.timeout.as_secs() == 0 {
return Err(YahooError::InvalidStatusCode(
"Timeout must be greater than 0".into(),
));
}
if self.retry_attempts > 20 {
return Err(YahooError::InvalidStatusCode(
"Retry attempts should not exceed 20 (recommended max: 10)".into(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_builder_default_is_development() {
let builder = YahooConnectorBuilder::default();
assert_eq!(builder.rate_limit, 10.0);
assert_eq!(builder.circuit_breaker_threshold, 10);
assert_eq!(builder.cache_duration_secs, 30);
assert!(builder.verbose_logging);
}
#[test]
fn test_builder_production() {
let builder = YahooConnectorBuilder::production();
assert_eq!(builder.rate_limit, 0.5);
assert_eq!(builder.circuit_breaker_threshold, 5);
assert_eq!(builder.cache_duration_secs, 900);
assert!(!builder.verbose_logging);
assert!(builder.enable_tracing);
}
#[test]
fn test_builder_enterprise() {
let builder = YahooConnectorBuilder::enterprise();
assert_eq!(builder.rate_limit, 0.5);
assert_eq!(builder.circuit_breaker_threshold, 8);
assert_eq!(builder.cache_duration_secs, 300);
assert!(builder.enable_metrics);
assert!(builder.enable_tracing);
}
#[test]
fn test_builder_minimal() {
let builder = YahooConnectorBuilder::minimal();
assert_eq!(builder.rate_limit, 1000.0);
assert_eq!(builder.retry_attempts, 0);
assert_eq!(builder.cache_size, 0);
assert!(!builder.enable_metrics);
assert!(!builder.enable_tracing);
}
#[test]
fn test_builder_fluent_api() {
let builder = YahooConnectorBuilder::new()
.rate_limit(5.0)
.cache_size(1000)
.retry_attempts(7)
.timeout(Duration::from_secs(45));
assert_eq!(builder.rate_limit, 5.0);
assert_eq!(builder.cache_size, 1000);
assert_eq!(builder.retry_attempts, 7);
assert_eq!(builder.timeout, Duration::from_secs(45));
}
#[test]
fn test_builder_validation_rate_limit() {
let builder = YahooConnectorBuilder::new().rate_limit(0.0);
assert!(builder.validate().is_err());
let builder = YahooConnectorBuilder::new().rate_limit(-1.0);
assert!(builder.validate().is_err());
}
#[test]
fn test_builder_validation_circuit_breaker() {
let builder = YahooConnectorBuilder::new().circuit_breaker_threshold(0);
assert!(builder.validate().is_err());
}
#[test]
fn test_builder_validation_timeout() {
let builder = YahooConnectorBuilder::new().timeout(Duration::from_secs(0));
assert!(builder.validate().is_err());
}
#[test]
fn test_builder_validation_retry_attempts() {
let builder = YahooConnectorBuilder::new().retry_attempts(25);
assert!(builder.validate().is_err());
}
#[test]
fn test_builder_validation_success() {
let builder = YahooConnectorBuilder::production();
assert!(builder.validate().is_ok());
}
}