use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use tracing::{info, instrument};
use viewpoint_cdp::{CdpConnection, CdpConnectionOptions};
use super::Browser;
use crate::error::BrowserError;
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug, Clone)]
pub struct ConnectOverCdpBuilder {
endpoint_url: String,
timeout: Option<Duration>,
headers: HashMap<String, String>,
}
impl ConnectOverCdpBuilder {
pub(crate) fn new(endpoint_url: impl Into<String>) -> Self {
Self {
endpoint_url: endpoint_url.into(),
timeout: None,
headers: HashMap::new(),
}
}
#[must_use]
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
self.headers.insert(name.into(), value.into());
self
}
#[must_use]
pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
self.headers.extend(headers);
self
}
#[instrument(level = "info", skip(self), fields(endpoint_url = %self.endpoint_url))]
pub async fn connect(self) -> Result<Browser, BrowserError> {
info!("Connecting to browser via CDP endpoint");
let options = CdpConnectionOptions::new()
.timeout(self.timeout.unwrap_or(DEFAULT_TIMEOUT))
.headers(self.headers);
let connection = CdpConnection::connect_via_http_with_options(&self.endpoint_url, options)
.await
.map_err(|e| match e {
viewpoint_cdp::CdpError::ConnectionTimeout(d) => BrowserError::ConnectionTimeout(d),
viewpoint_cdp::CdpError::InvalidEndpointUrl(s) => {
BrowserError::InvalidEndpointUrl(s)
}
viewpoint_cdp::CdpError::EndpointDiscoveryFailed { url, reason } => {
BrowserError::EndpointDiscoveryFailed(format!("{url}: {reason}"))
}
viewpoint_cdp::CdpError::ConnectionFailed(s) => BrowserError::ConnectionFailed(s),
other => BrowserError::Cdp(other),
})?;
connection
.send_command::<_, serde_json::Value>(
"Target.setDiscoverTargets",
Some(viewpoint_cdp::protocol::target_domain::SetDiscoverTargetsParams {
discover: true,
}),
None,
)
.await
.map_err(|e| BrowserError::ConnectionFailed(format!("Failed to enable target discovery: {e}")))?;
info!("Successfully connected to browser");
Ok(Browser {
connection: Arc::new(connection),
process: None,
owned: false,
_temp_user_data_dir: None,
})
}
}