browser_commander/browser/
launcher.rs1use crate::core::constants::CHROME_ARGS;
7use crate::core::engine::EngineType;
8use std::path::PathBuf;
9
10#[derive(Debug, Clone)]
12pub struct LaunchOptions {
13 pub engine: EngineType,
15 pub user_data_dir: Option<PathBuf>,
17 pub headless: bool,
19 pub slow_mo: u64,
21 pub verbose: bool,
23 pub args: Vec<String>,
25}
26
27impl Default for LaunchOptions {
28 fn default() -> Self {
29 Self {
30 engine: EngineType::Chromiumoxide,
31 user_data_dir: None,
32 headless: false,
33 slow_mo: 0,
34 verbose: false,
35 args: Vec::new(),
36 }
37 }
38}
39
40impl LaunchOptions {
41 pub fn chromiumoxide() -> Self {
43 Self {
44 engine: EngineType::Chromiumoxide,
45 ..Default::default()
46 }
47 }
48
49 pub fn fantoccini() -> Self {
51 Self {
52 engine: EngineType::Fantoccini,
53 ..Default::default()
54 }
55 }
56
57 pub fn headless(mut self, headless: bool) -> Self {
59 self.headless = headless;
60 self
61 }
62
63 pub fn user_data_dir(mut self, dir: impl Into<PathBuf>) -> Self {
65 self.user_data_dir = Some(dir.into());
66 self
67 }
68
69 pub fn slow_mo(mut self, ms: u64) -> Self {
71 self.slow_mo = ms;
72 self
73 }
74
75 pub fn verbose(mut self, verbose: bool) -> Self {
77 self.verbose = verbose;
78 self
79 }
80
81 pub fn with_args(mut self, args: Vec<String>) -> Self {
83 self.args = args;
84 self
85 }
86
87 pub fn all_chrome_args(&self) -> Vec<String> {
89 let mut all_args: Vec<String> = CHROME_ARGS.iter().map(|s| s.to_string()).collect();
90 all_args.extend(self.args.clone());
91 all_args
92 }
93
94 pub fn get_user_data_dir(&self) -> PathBuf {
96 if let Some(ref dir) = self.user_data_dir {
97 dir.clone()
98 } else {
99 let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
100 home.join(".browser-commander")
101 .join(format!("{}-data", self.engine))
102 }
103 }
104}
105
106#[derive(Debug)]
111pub struct Browser {
112 pub engine: EngineType,
114 pub user_data_dir: PathBuf,
116 pub headless: bool,
118}
119
120#[derive(Debug)]
122pub struct LaunchResult {
123 pub browser: Browser,
125}
126
127pub async fn launch_browser(options: LaunchOptions) -> Result<LaunchResult, anyhow::Error> {
144 if options.verbose {
145 tracing::info!("Launching browser with {} engine...", options.engine);
146 }
147
148 let user_data_dir = options.get_user_data_dir();
149
150 std::fs::create_dir_all(&user_data_dir)?;
152
153 let browser = Browser {
155 engine: options.engine,
156 user_data_dir,
157 headless: options.headless,
158 };
159
160 if options.verbose {
161 tracing::info!("Browser launched with {} engine", options.engine);
162 }
163
164 Ok(LaunchResult { browser })
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn launch_options_default() {
173 let options = LaunchOptions::default();
174 assert_eq!(options.engine, EngineType::Chromiumoxide);
175 assert!(!options.headless);
176 assert_eq!(options.slow_mo, 0);
177 assert!(!options.verbose);
178 assert!(options.args.is_empty());
179 }
180
181 #[test]
182 fn launch_options_builder() {
183 let options = LaunchOptions::chromiumoxide()
184 .headless(true)
185 .slow_mo(100)
186 .verbose(true)
187 .with_args(vec!["--custom-arg".to_string()]);
188
189 assert_eq!(options.engine, EngineType::Chromiumoxide);
190 assert!(options.headless);
191 assert_eq!(options.slow_mo, 100);
192 assert!(options.verbose);
193 assert_eq!(options.args, vec!["--custom-arg"]);
194 }
195
196 #[test]
197 fn launch_options_fantoccini() {
198 let options = LaunchOptions::fantoccini();
199 assert_eq!(options.engine, EngineType::Fantoccini);
200 }
201
202 #[test]
203 fn all_chrome_args_includes_defaults() {
204 let options = LaunchOptions::default();
205 let args = options.all_chrome_args();
206
207 assert!(args.contains(&"--disable-infobars".to_string()));
208 assert!(args.contains(&"--no-first-run".to_string()));
209 }
210
211 #[test]
212 fn all_chrome_args_includes_custom() {
213 let options = LaunchOptions::default().with_args(vec!["--custom".to_string()]);
214 let args = options.all_chrome_args();
215
216 assert!(args.contains(&"--custom".to_string()));
217 }
218
219 #[test]
220 fn get_user_data_dir_uses_custom() {
221 let options = LaunchOptions::default().user_data_dir("/custom/path");
222 assert_eq!(options.get_user_data_dir(), PathBuf::from("/custom/path"));
223 }
224
225 #[test]
226 fn get_user_data_dir_creates_default() {
227 let options = LaunchOptions::default();
228 let dir = options.get_user_data_dir();
229 assert!(dir.to_string_lossy().contains("browser-commander"));
230 assert!(dir.to_string_lossy().contains("chromiumoxide-data"));
231 }
232}