use crate::BoxError;
use crate::browser::{self, BrowserOptions};
use crate::cdp::client::CdpClient;
use crate::cli::{Cli, Command};
use crate::run_helpers::{connect_page, kill_pid, resolve_page_target};
use crate::session::{self, SessionStore};
pub async fn resolve_cli_connection(
cli: &Cli,
) -> Result<(SessionStore, CdpClient, CdpClient, String), BoxError> {
let mut store = session::load_session()?;
let requested_proxy = browser::normalized_proxy_option(
cli.connect.as_deref(),
cli.proxy_server.as_deref(),
)?;
let requested_chrome_args = browser::normalized_chrome_args_option(
cli.connect.as_deref(),
&cli.chrome_args,
)?;
let existing_mode = store.browsers.get(&cli.browser).map(|b| b.headless);
let want_headless = existing_mode.unwrap_or(!cli.headed);
let stored_proxy = store
.browsers
.get(&cli.browser)
.and_then(|b| b.proxy_server.clone());
let effective_proxy = requested_proxy.clone().or(stored_proxy);
let effective_chrome_args =
crate::chrome_args::effective_chrome_args(&store, &cli.browser, &requested_chrome_args);
let (conn, browser_client) = if let Some(existing) = store.browsers.get(&cli.browser) {
let mode_matches = existing.headless == want_headless;
let ws = &existing.ws_endpoint;
let http = browser::extract_http_from_ws(ws);
if mode_matches {
if let Ok(client) = CdpClient::connect(ws).await {
session::ensure_proxy_compatible(existing, requested_proxy.as_deref())?;
session::ensure_chrome_args_compatible(existing, &requested_chrome_args)?;
let conn = browser::BrowserConnection {
ws_endpoint: ws.clone(),
http_endpoint: Some(http),
pid: existing.pid,
};
(conn, client)
} else {
if let Some(pid) = existing.pid {
kill_pid(pid);
}
store.browsers.remove(&cli.browser);
let opts = BrowserOptions {
name: cli.browser.clone(),
headless: want_headless,
ignore_https_errors: cli.ignore_https_errors,
stealth: cli.stealth,
connect: cli.connect.clone(),
proxy_server: effective_proxy.clone(),
copy_cookies: cli.copy_cookies,
chrome_args: effective_chrome_args.clone(),
};
let conn = Box::pin(browser::resolve_browser(&opts)).await?;
let client = CdpClient::connect(&conn.ws_endpoint).await?;
(conn, client)
}
} else {
if let Some(pid) = existing.pid {
kill_pid(pid);
}
store.browsers.remove(&cli.browser);
let opts = BrowserOptions {
name: cli.browser.clone(),
headless: want_headless,
ignore_https_errors: cli.ignore_https_errors,
stealth: cli.stealth,
connect: cli.connect.clone(),
proxy_server: effective_proxy.clone(),
copy_cookies: cli.copy_cookies,
chrome_args: effective_chrome_args.clone(),
};
let conn = Box::pin(browser::resolve_browser(&opts)).await?;
let client = CdpClient::connect(&conn.ws_endpoint).await?;
(conn, client)
}
} else {
let needs_existing = !matches!(cli.command, Command::Goto { .. } | Command::Pipe);
if needs_existing {
return Err(format!(
"No browser session '{}'. Run `chrome-agent --browser {} goto <url>` first.",
cli.browser, cli.browser
)
.into());
}
let opts = BrowserOptions {
name: cli.browser.clone(),
headless: want_headless,
ignore_https_errors: cli.ignore_https_errors,
stealth: cli.stealth,
connect: cli.connect.clone(),
proxy_server: effective_proxy.clone(),
copy_cookies: cli.copy_cookies,
chrome_args: effective_chrome_args.clone(),
};
let conn = Box::pin(browser::resolve_browser(&opts)).await?;
let client = CdpClient::connect(&conn.ws_endpoint).await?;
(conn, client)
};
browser_client.set_call_timeout(std::time::Duration::from_secs(cli.timeout));
let http_endpoint = conn
.http_endpoint
.as_deref()
.ok_or("No HTTP endpoint available. Cannot resolve page WebSocket URL.")?;
let target_id = {
let browser_session = session::ensure_browser(
&mut store,
&cli.browser,
&conn.ws_endpoint,
conn.pid,
want_headless,
effective_proxy,
effective_chrome_args,
);
resolve_page_target(&browser_client, browser_session, &cli.page).await?
};
let _ = session::save_session(&mut store);
let client = Box::pin(connect_page(http_endpoint, &target_id, cli.stealth)).await?;
Ok((store, browser_client, client, target_id))
}