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.split_whitespace().map(|s| s.to_string()).collect();
114 }
115
116 config
117 }
118
119 pub fn with_context_limit(mut self, limit: usize) -> Self {
121 self.context_limit = limit;
122 self
123 }
124
125 pub fn with_timeout_ms(mut self, timeout: u64) -> Self {
127 self.timeout_ms = timeout;
128 self
129 }
130
131 pub fn with_timeout(mut self, timeout: Duration) -> Self {
133 self.timeout_ms = timeout.as_millis() as u64;
134 self
135 }
136
137 pub fn with_profile(mut self, profile: Profile) -> Self {
139 self.profile = profile;
140 self
141 }
142
143 pub fn with_lazy_init(mut self, lazy: bool) -> Self {
145 self.lazy_init = lazy;
146 self
147 }
148
149 pub fn with_chrome_path(mut self, path: impl Into<PathBuf>) -> Self {
151 self.chrome_path = Some(path.into());
152 self
153 }
154
155 pub fn with_headless(mut self, headless: bool) -> Self {
157 self.headless = headless;
158 self
159 }
160
161 pub fn with_viewport(mut self, width: u32, height: u32) -> Self {
163 self.viewport_width = width;
164 self.viewport_height = height;
165 self
166 }
167
168 pub fn with_extra_args<I, S>(mut self, args: I) -> Self
171 where
172 I: IntoIterator<Item = S>,
173 S: Into<String>,
174 {
175 self.extra_args = args.into_iter().map(Into::into).collect();
176 self
177 }
178
179 pub fn add_extra_arg(mut self, arg: impl Into<String>) -> Self {
183 self.extra_args.push(arg.into());
184 self
185 }
186
187 pub fn timeout(&self) -> Duration {
189 Duration::from_millis(self.timeout_ms)
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn test_default_config() {
199 let config = ChaserConfig::default();
200 assert_eq!(config.context_limit, 20);
201 assert_eq!(config.timeout_ms, 60000);
202 assert_eq!(config.profile, Profile::Windows);
203 assert!(!config.lazy_init);
204 assert!(!config.headless);
205 assert!(config.extra_args.is_empty());
206 }
207
208 #[test]
209 fn test_with_extra_args_replaces() {
210 let config = ChaserConfig::default().with_extra_args(["--no-sandbox", "--disable-gpu"]);
211 assert_eq!(config.extra_args, vec!["--no-sandbox", "--disable-gpu"]);
212 let config2 = config.with_extra_args(vec!["--foo"]);
214 assert_eq!(config2.extra_args, vec!["--foo"]);
215 }
216
217 #[test]
218 fn test_add_extra_arg_appends() {
219 let config = ChaserConfig::default()
220 .add_extra_arg("--no-sandbox")
221 .add_extra_arg("--disable-gpu");
222 assert_eq!(config.extra_args, vec!["--no-sandbox", "--disable-gpu"]);
223 }
224
225 #[test]
226 fn test_builder_pattern() {
227 let config = ChaserConfig::default()
228 .with_context_limit(10)
229 .with_timeout_ms(30000)
230 .with_profile(Profile::Linux)
231 .with_lazy_init(true)
232 .with_headless(true);
233
234 assert_eq!(config.context_limit, 10);
235 assert_eq!(config.timeout_ms, 30000);
236 assert_eq!(config.profile, Profile::Linux);
237 assert!(config.lazy_init);
238 assert!(config.headless);
239 }
240}