use std::time::Duration;
const DEFAULT_PROBE_PORTS: &[u16] = &[9222, 9223, 9224, 9225];
fn probe_ports() -> Vec<u16> {
if let Ok(raw) = std::env::var("CODETETHER_BROWSER_DEBUG_PORTS") {
let parsed: Vec<u16> = raw
.split(',')
.filter_map(|s| s.trim().parse::<u16>().ok())
.collect();
if !parsed.is_empty() {
return parsed;
}
}
DEFAULT_PROBE_PORTS.to_vec()
}
pub(super) fn pick_free_port() -> Option<u16> {
use std::net::TcpListener;
for port in probe_ports() {
if TcpListener::bind(("127.0.0.1", port)).is_ok() {
return Some(port);
}
}
None
}
pub(super) async fn detect_running_browser() -> Option<String> {
for port in probe_ports() {
if let Some(ws) = resolve_ws_url(&format!("http://127.0.0.1:{port}")).await {
tracing::info!(%ws, port, "attaching to running browser with remote debugging");
return Some(ws);
}
}
None
}
pub(super) async fn resolve_ws_url(http_base: &str) -> Option<String> {
let url = format!("{}/json/version", http_base.trim_end_matches('/'));
let client = reqwest::Client::builder()
.timeout(Duration::from_millis(500))
.build()
.ok()?;
let response = client.get(&url).send().await.ok()?;
if !response.status().is_success() {
return None;
}
let body: serde_json::Value = response.json().await.ok()?;
body.get("webSocketDebuggerUrl")
.and_then(|v| v.as_str())
.map(str::to_string)
}