1use crate::models::Profile;
4use std::env;
5use std::path::PathBuf;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
10pub struct ChaserConfig {
11 pub context_limit: usize,
13
14 pub timeout_ms: u64,
16
17 pub profile: Profile,
19
20 pub lazy_init: bool,
22
23 pub chrome_path: Option<PathBuf>,
25
26 pub headless: bool,
28
29 pub viewport_width: u32,
31
32 pub viewport_height: u32,
34
35 pub extra_args: Vec<String>,
49}
50
51impl Default for ChaserConfig {
52 fn default() -> Self {
53 Self {
54 context_limit: 20,
55 timeout_ms: 60000,
56 profile: Profile::Windows,
57 lazy_init: false,
58 chrome_path: None,
59 headless: false,
60 viewport_width: 1920,
61 viewport_height: 1080,
62 extra_args: Vec::new(),
63 }
64 }
65}
66
67impl ChaserConfig {
68 pub fn from_env() -> Self {
80 let mut config = Self::default();
81
82 if let Ok(val) = env::var("CHASER_CONTEXT_LIMIT") {
83 if let Ok(limit) = val.parse() {
84 config.context_limit = limit;
85 }
86 }
87
88 if let Ok(val) = env::var("CHASER_TIMEOUT") {
89 if let Ok(timeout) = val.parse() {
90 config.timeout_ms = timeout;
91 }
92 }
93
94 if let Ok(val) = env::var("CHASER_PROFILE") {
95 if let Some(profile) = Profile::parse(&val) {
96 config.profile = profile;
97 }
98 }
99
100 if let Ok(val) = env::var("CHASER_LAZY_INIT") {
101 config.lazy_init = val.eq_ignore_ascii_case("true") || val == "1";
102 }
103
104 if let Ok(val) = env::var("CHROME_BIN") {
105 config.chrome_path = Some(PathBuf::from(val));
106 }
107
108 if let Ok(val) = env::var("CHASER_HEADLESS") {
109 config.headless = val.eq_ignore_ascii_case("true") || val == "1";
110 }
111
112 if let Ok(val) = env::var("CHASER_EXTRA_ARGS") {
113 config.extra_args = val
114 .split_whitespace()
115 .map(|s| s.to_string())
116 .collect();
117 }
118
119 config
120 }
121
122 pub fn with_context_limit(mut self, limit: usize) -> Self {
124 self.context_limit = limit;
125 self
126 }
127
128 pub fn with_timeout_ms(mut self, timeout: u64) -> Self {
130 self.timeout_ms = timeout;
131 self
132 }
133
134 pub fn with_timeout(mut self, timeout: Duration) -> Self {
136 self.timeout_ms = timeout.as_millis() as u64;
137 self
138 }
139
140 pub fn with_profile(mut self, profile: Profile) -> Self {
142 self.profile = profile;
143 self
144 }
145
146 pub fn with_lazy_init(mut self, lazy: bool) -> Self {
148 self.lazy_init = lazy;
149 self
150 }
151
152 pub fn with_chrome_path(mut self, path: impl Into<PathBuf>) -> Self {
154 self.chrome_path = Some(path.into());
155 self
156 }
157
158 pub fn with_headless(mut self, headless: bool) -> Self {
160 self.headless = headless;
161 self
162 }
163
164 pub fn with_viewport(mut self, width: u32, height: u32) -> Self {
166 self.viewport_width = width;
167 self.viewport_height = height;
168 self
169 }
170
171 pub fn with_extra_args<I, S>(mut self, args: I) -> Self
174 where
175 I: IntoIterator<Item = S>,
176 S: Into<String>,
177 {
178 self.extra_args = args.into_iter().map(Into::into).collect();
179 self
180 }
181
182 pub fn add_extra_arg(mut self, arg: impl Into<String>) -> Self {
186 self.extra_args.push(arg.into());
187 self
188 }
189
190 pub fn timeout(&self) -> Duration {
192 Duration::from_millis(self.timeout_ms)
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_default_config() {
202 let config = ChaserConfig::default();
203 assert_eq!(config.context_limit, 20);
204 assert_eq!(config.timeout_ms, 60000);
205 assert_eq!(config.profile, Profile::Windows);
206 assert!(!config.lazy_init);
207 assert!(!config.headless);
208 assert!(config.extra_args.is_empty());
209 }
210
211 #[test]
212 fn test_with_extra_args_replaces() {
213 let config = ChaserConfig::default()
214 .with_extra_args(["--no-sandbox", "--disable-gpu"]);
215 assert_eq!(config.extra_args, vec!["--no-sandbox", "--disable-gpu"]);
216 let config2 = config.with_extra_args(vec!["--foo"]);
218 assert_eq!(config2.extra_args, vec!["--foo"]);
219 }
220
221 #[test]
222 fn test_add_extra_arg_appends() {
223 let config = ChaserConfig::default()
224 .add_extra_arg("--no-sandbox")
225 .add_extra_arg("--disable-gpu");
226 assert_eq!(config.extra_args, vec!["--no-sandbox", "--disable-gpu"]);
227 }
228
229 #[test]
230 fn test_builder_pattern() {
231 let config = ChaserConfig::default()
232 .with_context_limit(10)
233 .with_timeout_ms(30000)
234 .with_profile(Profile::Linux)
235 .with_lazy_init(true)
236 .with_headless(true);
237
238 assert_eq!(config.context_limit, 10);
239 assert_eq!(config.timeout_ms, 30000);
240 assert_eq!(config.profile, Profile::Linux);
241 assert!(config.lazy_init);
242 assert!(config.headless);
243 }
244}