Skip to main content

browser_control/launch/
chromium.rs

1//! Chromium-family browser launcher (Chrome, Edge, Chromium, Brave).
2
3use std::fs::File;
4use std::process::Stdio;
5
6use anyhow::{Context, Result};
7use tokio::process::Command;
8
9use crate::detect::{Engine, Installed};
10
11use super::{
12    allocate_free_port, configure_session_detachment, wait_for_endpoint, LaunchOpts, LaunchedHandle,
13};
14
15pub async fn launch(installed: &Installed, opts: LaunchOpts) -> Result<LaunchedHandle> {
16    let port = allocate_free_port().context("allocating CDP port")?;
17
18    if let Some(parent) = opts.profile_dir.parent() {
19        let _ = std::fs::create_dir_all(parent);
20    }
21    std::fs::create_dir_all(&opts.profile_dir)
22        .with_context(|| format!("creating profile dir {}", opts.profile_dir.display()))?;
23
24    let log_path = opts.profile_dir.join("browser.log");
25    let log_file =
26        File::create(&log_path).with_context(|| format!("creating {}", log_path.display()))?;
27    let log_clone = log_file
28        .try_clone()
29        .context("cloning log file handle for stderr")?;
30
31    let mut cmd = Command::new(&installed.executable);
32    cmd.arg(format!("--remote-debugging-port={port}"))
33        .arg(format!("--user-data-dir={}", opts.profile_dir.display()))
34        .arg("--no-first-run")
35        .arg("--no-default-browser-check")
36        .arg("--disable-component-update");
37    if opts.headless {
38        cmd.arg("--headless=new");
39    }
40    cmd.arg("about:blank");
41
42    cmd.stdin(Stdio::null())
43        .stdout(Stdio::from(log_file))
44        .stderr(Stdio::from(log_clone))
45        .kill_on_drop(false);
46    configure_session_detachment(&mut cmd);
47
48    let mut child = cmd
49        .spawn()
50        .with_context(|| format!("spawning {}", installed.executable.display()))?;
51    let pid = child.id().context("child has no pid")?;
52
53    let endpoint = wait_for_endpoint(port, &mut child, &log_path).await?;
54
55    Ok(LaunchedHandle {
56        pid,
57        port,
58        endpoint,
59        engine: Engine::Cdp,
60        profile_dir: opts.profile_dir,
61        child: Some(child),
62    })
63}