From 2f703fbb2afa13f4f77c02ef05ee82a87ec2235a Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Wed, 8 Apr 2026 01:35:55 +0200 Subject: [PATCH] feat(domain): add TabFetcherPort and TabParserPort traits --- crates/domain/src/lib.rs | 2 ++ crates/domain/src/ports.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 crates/domain/src/ports.rs diff --git a/crates/domain/src/lib.rs b/crates/domain/src/lib.rs index 68b83fe..0877499 100644 --- a/crates/domain/src/lib.rs +++ b/crates/domain/src/lib.rs @@ -1,7 +1,9 @@ pub mod note; pub mod chord; pub mod song; +pub mod ports; pub use note::Note; pub use chord::Chord; pub use song::{ChordPosition, LyricLine, Section, SectionKind, SongMeta, Song}; +pub use ports::{FetchError, ParseError, TabFetcherPort, TabParserPort, TabSource}; diff --git a/crates/domain/src/ports.rs b/crates/domain/src/ports.rs new file mode 100644 index 0000000..fc70f25 --- /dev/null +++ b/crates/domain/src/ports.rs @@ -0,0 +1,37 @@ +use std::path::PathBuf; +use thiserror::Error; +use async_trait::async_trait; +use crate::song::Song; + +#[derive(Debug, Clone)] +pub enum TabSource { + File(PathBuf), + Url(String), +} + +#[derive(Debug, Error)] +pub enum FetchError { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("Network error: {0}")] + Network(String), + #[error("Response is not HTML")] + InvalidContentType, +} + +#[derive(Debug, Error)] +pub enum ParseError { + #[error("Tab content not found in HTML")] + MissingContent, + #[error("Malformed HTML: {0}")] + MalformedHtml(String), +} + +#[async_trait] +pub trait TabFetcherPort: Send + Sync { + async fn fetch(&self, source: TabSource) -> Result; +} + +pub trait TabParserPort: Send + Sync { + fn parse(&self, html: &str) -> Result; +}