Skip to main content

browser_control/launch/
chromium.rs

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