browser_commander/browser/
launcher.rs1use crate::browser::media::ColorScheme;
7use crate::core::constants::CHROME_ARGS;
8use crate::core::engine::EngineType;
9use std::path::PathBuf;
10
11#[derive(Debug, Clone)]
13pub struct LaunchOptions {
14 pub engine: EngineType,
16 pub user_data_dir: Option<PathBuf>,
18 pub headless: bool,
20 pub slow_mo: u64,
22 pub verbose: bool,
24 pub args: Vec<String>,
26 pub color_scheme: Option<ColorScheme>,
28}
29
30impl Default for LaunchOptions {
31 fn default() -> Self {
32 Self {
33 engine: EngineType::Chromiumoxide,
34 user_data_dir: None,
35 headless: false,
36 slow_mo: 0,
37 verbose: false,
38 args: Vec::new(),
39 color_scheme: None,
40 }
41 }
42}
43
44impl LaunchOptions {
45 pub fn chromiumoxide() -> Self {
47 Self {
48 engine: EngineType::Chromiumoxide,
49 ..Default::default()
50 }
51 }
52
53 pub fn fantoccini() -> Self {
55 Self {
56 engine: EngineType::Fantoccini,
57 ..Default::default()
58 }
59 }
60
61 pub fn headless(mut self, headless: bool) -> Self {
63 self.headless = headless;
64 self
65 }
66
67 pub fn user_data_dir(mut self, dir: impl Into<PathBuf>) -> Self {
69 self.user_data_dir = Some(dir.into());
70 self
71 }
72
73 pub fn slow_mo(mut self, ms: u64) -> Self {
75 self.slow_mo = ms;
76 self
77 }
78
79 pub fn verbose(mut self, verbose: bool) -> Self {
81 self.verbose = verbose;
82 self
83 }
84
85 pub fn with_args(mut self, args: Vec<String>) -> Self {
87 self.args = args;
88 self
89 }
90
91 pub fn color_scheme(mut self, color_scheme: ColorScheme) -> Self {
93 self.color_scheme = Some(color_scheme);
94 self
95 }
96
97 pub fn all_chrome_args(&self) -> Vec<String> {
99 let mut all_args: Vec<String> = CHROME_ARGS.iter().map(|s| s.to_string()).collect();
100 all_args.extend(self.args.clone());
101 all_args
102 }
103
104 pub fn get_user_data_dir(&self) -> PathBuf {
106 if let Some(ref dir) = self.user_data_dir {
107 dir.clone()
108 } else {
109 let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
110 home.join(".browser-commander")
111 .join(format!("{}-data", self.engine))
112 }
113 }
114}
115
116#[derive(Debug)]
121pub struct Browser {
122 pub engine: EngineType,
124 pub user_data_dir: PathBuf,
126 pub headless: bool,
128}
129
130#[derive(Debug)]
132pub struct LaunchResult {
133 pub browser: Browser,
135}
136
137pub async fn launch_browser(options: LaunchOptions) -> Result<LaunchResult, anyhow::Error> {
154 if options.verbose {
155 tracing::info!("Launching browser with {} engine...", options.engine);
156 }
157
158 let user_data_dir = options.get_user_data_dir();
159
160 std::fs::create_dir_all(&user_data_dir)?;
162
163 let browser = Browser {
165 engine: options.engine,
166 user_data_dir,
167 headless: options.headless,
168 };
169
170 if options.verbose {
171 tracing::info!("Browser launched with {} engine", options.engine);
172 }
173
174 Ok(LaunchResult { browser })
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180
181 #[test]
182 fn launch_options_default() {
183 let options = LaunchOptions::default();
184 assert_eq!(options.engine, EngineType::Chromiumoxide);
185 assert!(!options.headless);
186 assert_eq!(options.slow_mo, 0);
187 assert!(!options.verbose);
188 assert!(options.args.is_empty());
189 }
190
191 #[test]
192 fn launch_options_builder() {
193 let options = LaunchOptions::chromiumoxide()
194 .headless(true)
195 .slow_mo(100)
196 .verbose(true)
197 .with_args(vec!["--custom-arg".to_string()]);
198
199 assert_eq!(options.engine, EngineType::Chromiumoxide);
200 assert!(options.headless);
201 assert_eq!(options.slow_mo, 100);
202 assert!(options.verbose);
203 assert_eq!(options.args, vec!["--custom-arg"]);
204 }
205
206 #[test]
207 fn launch_options_fantoccini() {
208 let options = LaunchOptions::fantoccini();
209 assert_eq!(options.engine, EngineType::Fantoccini);
210 }
211
212 #[test]
213 fn all_chrome_args_includes_defaults() {
214 let options = LaunchOptions::default();
215 let args = options.all_chrome_args();
216
217 assert!(args.contains(&"--disable-infobars".to_string()));
218 assert!(args.contains(&"--no-first-run".to_string()));
219 }
220
221 #[test]
222 fn all_chrome_args_includes_custom() {
223 let options = LaunchOptions::default().with_args(vec!["--custom".to_string()]);
224 let args = options.all_chrome_args();
225
226 assert!(args.contains(&"--custom".to_string()));
227 }
228
229 #[test]
230 fn get_user_data_dir_uses_custom() {
231 let options = LaunchOptions::default().user_data_dir("/custom/path");
232 assert_eq!(options.get_user_data_dir(), PathBuf::from("/custom/path"));
233 }
234
235 #[test]
236 fn get_user_data_dir_creates_default() {
237 let options = LaunchOptions::default();
238 let dir = options.get_user_data_dir();
239 assert!(dir.to_string_lossy().contains("browser-commander"));
240 assert!(dir.to_string_lossy().contains("chromiumoxide-data"));
241 }
242}