diff --git a/crates/infrastructure/ug-parser/src/fetcher.rs b/crates/infrastructure/ug-parser/src/fetcher.rs index a3e51df..fa5eff6 100644 --- a/crates/infrastructure/ug-parser/src/fetcher.rs +++ b/crates/infrastructure/ug-parser/src/fetcher.rs @@ -1 +1,53 @@ -pub struct UgTabFetcher; +use async_trait::async_trait; +use domain::{FetchError, TabFetcherPort, TabSource}; + +pub struct UgTabFetcher { + client: reqwest::Client, +} + +impl UgTabFetcher { + pub fn new() -> Self { + Self { client: reqwest::Client::new() } + } +} + +#[async_trait] +impl TabFetcherPort for UgTabFetcher { + async fn fetch(&self, source: TabSource) -> Result { + match source { + TabSource::File(path) => { + Ok(tokio::fs::read_to_string(&path).await?) + } + TabSource::Url(url) => { + let resp = self.client.get(&url).send().await + .map_err(|e| FetchError::Network(e.to_string()))?; + let content_type = resp.headers() + .get(reqwest::header::CONTENT_TYPE) + .and_then(|v| v.to_str().ok()) + .unwrap_or(""); + if !content_type.contains("text/html") { + return Err(FetchError::InvalidContentType); + } + resp.text().await.map_err(|e| FetchError::Network(e.to_string())) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use domain::TabSource; + use std::path::PathBuf; + + #[tokio::test] + async fn fetch_local_file() { + let fetcher = UgTabFetcher::new(); + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .parent().unwrap().parent().unwrap().parent().unwrap() + .join("samples/A DROP IN THE OCEAN.html"); + let html = fetcher.fetch(TabSource::File(path)).await.unwrap(); + assert!(html.contains("[Chorus]")); + assert!(html.contains("data-name=\"Em\"")); + } +}