use super::config::BrowserConfig;
use super::executor::{BrowserError, BrowserExecutor};
use std::sync::Arc;
pub struct BrowserClient {
executor: Arc<dyn BrowserExecutor>,
}
impl BrowserClient {
pub fn new(executor: Arc<dyn BrowserExecutor>) -> Self {
Self { executor }
}
pub fn with_default_config() -> Self {
let config = BrowserConfig::default();
let executor = Arc::new(super::executor::CliExecutor::new(config));
Self::new(executor)
}
pub fn executor(&self) -> &Arc<dyn BrowserExecutor> {
&self.executor
}
pub async fn open(&self, url: &str) -> Result<(), BrowserError> {
self.validate_url(url)?;
let output = self.executor.execute(&["open", url]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"Failed to open URL: {}",
output.stderr
)))
}
}
pub async fn close(&self) -> Result<(), BrowserError> {
let output = self.executor.execute(&["close"]).await?;
if output.success {
Ok(())
} else {
Err(BrowserError::Other(format!(
"Failed to close browser: {}",
output.stderr
)))
}
}
pub fn is_daemon_running(&self) -> bool {
self.executor.is_daemon_running()
}
fn validate_url(&self, url: &str) -> Result<(), BrowserError> {
if url.is_empty() {
return Err(BrowserError::InvalidArguments(
"URL cannot be empty".to_string(),
));
}
if !url.starts_with("http://") && !url.starts_with("https://") {
return Err(BrowserError::InvalidArguments(
"URL must start with http:// or https://".to_string(),
));
}
Ok(())
}
pub(crate) fn extract_field(content: &str, field_name: &str) -> Option<String> {
for line in content.lines() {
if let Some(stripped) = line.strip_prefix(field_name) {
return Some(stripped.trim().to_string());
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_field() {
let content = "Title: Example\nURL: https://example.com\nOther content";
assert_eq!(
BrowserClient::extract_field(content, "Title:"),
Some("Example".to_string())
);
assert_eq!(
BrowserClient::extract_field(content, "URL:"),
Some("https://example.com".to_string())
);
assert_eq!(BrowserClient::extract_field(content, "Missing:"), None);
}
}