Files
pocket-chords/crates/adapters/ug-parser/src/fetcher.rs
Gabriel Kaszewski d13df586dd refactor: DDD/CQRS architecture, unified crate layout
- crates: common→application, api→presentation, infrastructure/*→adapters/*
- new crates: api-types, infra-wiring
- domain: errors/, models/, value_objects/, ports/, services/
- application: CQRS use cases (songs/, tabs/) w/ commands, queries, deps
- unified DomainError replaces RepositoryError
- workspace deps, unused dep cleanup
- fix: parse plain-text chord lines (UG drops spans mid-song)
- tests extracted to separate modules (tests/ dirs)
2026-07-11 21:02:10 +02:00

53 lines
1.4 KiB
Rust

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(),
}
}
}
impl Default for UgTabFetcher {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl TabFetcherPort for UgTabFetcher {
async fn fetch(&self, source: TabSource) -> Result<String, FetchError> {
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)]
#[path = "tests/fetcher.rs"]
mod tests;