Skip to main content

chaser_cf/core/
config.rs

1//! Configuration for chaser-cf
2
3use crate::models::Profile;
4use std::env;
5use std::path::PathBuf;
6use std::time::Duration;
7
8/// Configuration for ChaserCF
9#[derive(Debug, Clone)]
10pub struct ChaserConfig {
11    /// Maximum concurrent browser contexts (default: 20)
12    pub context_limit: usize,
13
14    /// Request timeout in milliseconds (default: 60000)
15    pub timeout_ms: u64,
16
17    /// Stealth profile to use (default: Windows)
18    pub profile: Profile,
19
20    /// Whether to defer browser initialization until first use (default: false)
21    pub lazy_init: bool,
22
23    /// Path to Chrome/Chromium binary (default: auto-detect)
24    pub chrome_path: Option<PathBuf>,
25
26    /// Whether to run in headless mode (default: false for stealth)
27    pub headless: bool,
28
29    /// Browser viewport width (default: 1920)
30    pub viewport_width: u32,
31
32    /// Browser viewport height (default: 1080)
33    pub viewport_height: u32,
34}
35
36impl Default for ChaserConfig {
37    fn default() -> Self {
38        Self {
39            context_limit: 20,
40            timeout_ms: 60000,
41            profile: Profile::Windows,
42            lazy_init: false,
43            chrome_path: None,
44            headless: false,
45            viewport_width: 1920,
46            viewport_height: 1080,
47        }
48    }
49}
50
51impl ChaserConfig {
52    /// Create configuration from environment variables
53    ///
54    /// Environment variables:
55    /// - `CHASER_CONTEXT_LIMIT`: Max concurrent contexts (default: 20)
56    /// - `CHASER_TIMEOUT`: Timeout in ms (default: 60000)
57    /// - `CHASER_PROFILE`: Profile name (windows/linux/macos)
58    /// - `CHASER_LAZY_INIT`: Enable lazy init (true/false)
59    /// - `CHROME_BIN`: Path to Chrome binary
60    /// - `CHASER_HEADLESS`: Run headless (true/false)
61    pub fn from_env() -> Self {
62        let mut config = Self::default();
63
64        if let Ok(val) = env::var("CHASER_CONTEXT_LIMIT") {
65            if let Ok(limit) = val.parse() {
66                config.context_limit = limit;
67            }
68        }
69
70        if let Ok(val) = env::var("CHASER_TIMEOUT") {
71            if let Ok(timeout) = val.parse() {
72                config.timeout_ms = timeout;
73            }
74        }
75
76        if let Ok(val) = env::var("CHASER_PROFILE") {
77            if let Some(profile) = Profile::parse(&val) {
78                config.profile = profile;
79            }
80        }
81
82        if let Ok(val) = env::var("CHASER_LAZY_INIT") {
83            config.lazy_init = val.eq_ignore_ascii_case("true") || val == "1";
84        }
85
86        if let Ok(val) = env::var("CHROME_BIN") {
87            config.chrome_path = Some(PathBuf::from(val));
88        }
89
90        if let Ok(val) = env::var("CHASER_HEADLESS") {
91            config.headless = val.eq_ignore_ascii_case("true") || val == "1";
92        }
93
94        config
95    }
96
97    /// Builder method: set context limit
98    pub fn with_context_limit(mut self, limit: usize) -> Self {
99        self.context_limit = limit;
100        self
101    }
102
103    /// Builder method: set timeout
104    pub fn with_timeout_ms(mut self, timeout: u64) -> Self {
105        self.timeout_ms = timeout;
106        self
107    }
108
109    /// Builder method: set timeout from Duration
110    pub fn with_timeout(mut self, timeout: Duration) -> Self {
111        self.timeout_ms = timeout.as_millis() as u64;
112        self
113    }
114
115    /// Builder method: set profile
116    pub fn with_profile(mut self, profile: Profile) -> Self {
117        self.profile = profile;
118        self
119    }
120
121    /// Builder method: enable lazy initialization
122    pub fn with_lazy_init(mut self, lazy: bool) -> Self {
123        self.lazy_init = lazy;
124        self
125    }
126
127    /// Builder method: set Chrome path
128    pub fn with_chrome_path(mut self, path: impl Into<PathBuf>) -> Self {
129        self.chrome_path = Some(path.into());
130        self
131    }
132
133    /// Builder method: set headless mode
134    pub fn with_headless(mut self, headless: bool) -> Self {
135        self.headless = headless;
136        self
137    }
138
139    /// Builder method: set viewport size
140    pub fn with_viewport(mut self, width: u32, height: u32) -> Self {
141        self.viewport_width = width;
142        self.viewport_height = height;
143        self
144    }
145
146    /// Get timeout as Duration
147    pub fn timeout(&self) -> Duration {
148        Duration::from_millis(self.timeout_ms)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn test_default_config() {
158        let config = ChaserConfig::default();
159        assert_eq!(config.context_limit, 20);
160        assert_eq!(config.timeout_ms, 60000);
161        assert_eq!(config.profile, Profile::Windows);
162        assert!(!config.lazy_init);
163        assert!(!config.headless);
164    }
165
166    #[test]
167    fn test_builder_pattern() {
168        let config = ChaserConfig::default()
169            .with_context_limit(10)
170            .with_timeout_ms(30000)
171            .with_profile(Profile::Linux)
172            .with_lazy_init(true)
173            .with_headless(true);
174
175        assert_eq!(config.context_limit, 10);
176        assert_eq!(config.timeout_ms, 30000);
177        assert_eq!(config.profile, Profile::Linux);
178        assert!(config.lazy_init);
179        assert!(config.headless);
180    }
181}