use crate::{BrowserInfo, BrowserInfoError, BrowserType};
use serde::Deserialize;
use std::time::Duration;
#[derive(Debug, Deserialize)]
struct ChromeTab {
#[allow(dead_code)]
id: String,
title: String,
url: String,
#[serde(rename = "type")]
tab_type: String,
}
pub struct ChromeDevToolsExtractor;
impl ChromeDevToolsExtractor {
const DEFAULT_PORT: u16 = 9222;
const TIMEOUT_SECS: u64 = 3;
pub async fn is_available() -> bool {
Self::test_connection(Self::DEFAULT_PORT).await
}
async fn test_connection(port: u16) -> bool {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(Self::TIMEOUT_SECS))
.build()
.unwrap();
let url = format!("http://localhost:{port}/json/version");
client.get(&url).send().await.is_ok()
}
pub async fn extract_browser_info() -> Result<BrowserInfo, BrowserInfoError> {
let tabs = Self::get_tabs(Self::DEFAULT_PORT).await?;
let active_tab = tabs
.into_iter()
.find(|tab| tab.tab_type == "page")
.ok_or(BrowserInfoError::Other("No active tabs found".to_string()))?;
Ok(BrowserInfo {
url: active_tab.url,
title: active_tab.title,
browser_name: "Chrome".to_string(),
browser_type: BrowserType::Chrome,
version: None, tabs_count: None, is_incognito: false, process_id: 0, window_position: Default::default(), })
}
async fn get_tabs(port: u16) -> Result<Vec<ChromeTab>, BrowserInfoError> {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(Self::TIMEOUT_SECS))
.build()
.map_err(|e| BrowserInfoError::Other(format!("Network error: {e}")))?;
let url = format!("http://localhost:{port}/json");
let response = client
.get(&url)
.send()
.await
.map_err(|e| BrowserInfoError::Other(format!("Network error: {e}")))?;
let tabs: Vec<ChromeTab> = response
.json()
.await
.map_err(|e| BrowserInfoError::Other(format!("Parse error: {e}")))?;
Ok(tabs)
}
}