cdp_html_shot/browser/
browser_utils.rs

1use regex::Regex;
2use anyhow::{Context, Result};
3use std::io::{BufRead, BufReader};
4use std::process::{ChildStderr, Command, Stdio};
5
6use crate::browser::browser_config::BrowserConfig;
7
8pub(crate) fn spawn_chrome_process(config: &BrowserConfig) -> Result<std::process::Child> {
9    let mut command = Command::new(&config.executable_path);
10
11    #[cfg(windows)]
12    configure_windows_process(&mut command);
13
14    command
15        .args(config.get_browser_args())
16        .stderr(Stdio::piped())
17        .spawn()
18        .context("Failed to spawn a Chrome process")
19}
20
21#[cfg(windows)]
22fn configure_windows_process(command: &mut Command) {
23    use std::os::windows::process::CommandExt;
24    const CREATE_NO_WINDOW: u32 = 0x08000000;
25    command.creation_flags(CREATE_NO_WINDOW);
26}
27
28pub(crate) async fn get_websocket_url(stderr: ChildStderr) -> Result<String> {
29    let reader = BufReader::new(stderr);
30    ws_url_from_reader(reader)
31        .await?
32        .context("Failed to get ws url")
33}
34
35async fn ws_url_from_reader(reader: BufReader<ChildStderr>) -> Result<Option<String>>
36{
37    let re = Regex::new(r"listening on (.*/devtools/browser/.*)$")?;
38
39    let extract = |text: &str| -> Option<String> {
40        let caps = re.captures(text);
41        let cap = &caps?[1];
42        Some(cap.into())
43    };
44
45    for line in reader.lines() {
46        if let Some(answer) = extract(&line?) {
47            return Ok(Some(answer));
48        }
49    }
50    Ok(None)
51}