From c86be31d5411e2074fd9aa9150efd9a2c630173c Mon Sep 17 00:00:00 2001 From: derfenix Date: Tue, 9 Sep 2025 07:39:16 +0300 Subject: [PATCH] Refactoring --- src/application/application.rs | 43 ++++++++++++-------- src/application/config.rs | 33 +++++++++++++++ src/application/services/books.rs | 27 ++++++++---- src/domain/repository.rs | 6 +-- src/infrastructure/repository/inmem/books.rs | 8 +--- src/lib.rs | 5 +-- src/main.rs | 4 +- 7 files changed, 87 insertions(+), 39 deletions(-) diff --git a/src/application/application.rs b/src/application/application.rs index 0233a41..c85d748 100644 --- a/src/application/application.rs +++ b/src/application/application.rs @@ -1,34 +1,45 @@ +use crate::application::config::{Config, Storage}; use crate::application::services::books::Books; -use crate::application::config::Config; use crate::domain::book::Book; use crate::domain::repository::{BookFilter, Repository}; +use crate::infrastructure::repository::inmem; +use std::sync::{Arc, Mutex}; -pub struct Application> { - pub books: Books, +pub struct Application { cfg: Config, + pub repo: Arc + 'static>>>, + pub srv: Books, } -impl +'static> Application { - pub fn new(repo: R) -> Self { +impl Application { + pub fn new() -> Self { let cfg = Config::new(); - Application { - books: Books::new(repo, (&cfg.books_dir).into(), "https://foo.bar/".to_string()), + let repo: Box> = match cfg.storage { + Storage::InMemory => Box::new(inmem::books::BookRepository::new()), + }; + let repo = Arc::new(Mutex::new(repo)); + let srv = Books::new( + repo.clone(), + cfg.books_dir.clone().into(), + "https://foo.bar".to_string(), + ); - cfg + Application { + cfg, + repo, + srv } } - pub fn start(&mut self) -> Result<(), String>{ - self.books.add_books_from_path(); + pub fn start(&mut self) -> Result<(), String> { + self.srv.add_books_from_path(); if self.cfg.watcher { - return match self.books.watch_dir() { - Ok(_) => {Ok(())} - Err(e) => { - Err(format!("Error start watching books: {}", e)) - } - } + return match self.srv.watch_dir() { + Ok(_) => Ok(()), + Err(e) => Err(format!("Error start watching books: {}", e)), + }; } Ok(()) diff --git a/src/application/config.rs b/src/application/config.rs index 1773e25..e77d38d 100644 --- a/src/application/config.rs +++ b/src/application/config.rs @@ -1,4 +1,7 @@ use envman::EnvMan; +use std::error::Error; +use std::fmt; +use std::str::FromStr; #[derive(EnvMan)] pub struct Config { @@ -6,6 +9,8 @@ pub struct Config { pub books_dir: String, #[envman(default = "true")] pub watcher: bool, + #[envman(default = "inmemory")] + pub storage: Storage, } impl Config { @@ -13,3 +18,31 @@ impl Config { Config::load_from_env().expect("Failed to load configuration") } } + +pub enum Storage { + InMemory, +} + +#[derive(Debug)] +pub struct ParseStorageError { + details: String, +} + +impl fmt::Display for ParseStorageError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Unknown storage type: {}", self.details) + } +} + +impl Error for ParseStorageError {} + +impl FromStr for Storage { + type Err = ParseStorageError; + + fn from_str(s: &str) -> Result { + match s { + "inmemory" => Ok(Storage::InMemory), + _ => Err(ParseStorageError { details: s.into() }), + } + } +} diff --git a/src/application/services/books.rs b/src/application/services/books.rs index 969a76c..8243ddf 100644 --- a/src/application/services/books.rs +++ b/src/application/services/books.rs @@ -10,19 +10,20 @@ use url::Url; const AUTHOR_URL_PREFIX: &str = "author"; -pub struct Books> { - pub repo: Arc>, +pub struct Books { + pub repo: Arc + 'static>>>, root: PathBuf, base_url: Url, } -impl> Books -where - R: 'static, -{ - pub fn new(repo: R, root: PathBuf, base_url: String) -> Self { +impl Books { + pub fn new( + repo: Arc + 'static>>>, + root: PathBuf, + base_url: String, + ) -> Self { Books { - repo: Arc::new(Mutex::new(repo)), + repo, root, base_url: Url::parse(&base_url).unwrap(), } @@ -68,7 +69,15 @@ where pub fn add_books_from_path(&mut self) { let iter = fs::Loader::new(PathBuf::from(&self.root)); - self.repo.lock().unwrap().bulk_add(iter); + + match self.repo.lock() { + Ok(mut repo) => { + for book in iter { + repo.add(book); + } + } + Err(err) => eprintln!("{}", err), + } } pub fn watch_dir(&mut self) -> Result<(), io::Error> { diff --git a/src/domain/repository.rs b/src/domain/repository.rs index 1c8907d..5acd8ea 100644 --- a/src/domain/repository.rs +++ b/src/domain/repository.rs @@ -1,10 +1,10 @@ -pub trait Repository: Send + Sync + Sized{ +pub trait Repository: Send + Sync { fn add(&mut self, item: T); - fn bulk_add(&mut self, items: I) where I: IntoIterator; + fn bulk_add(&mut self, items: Vec); fn remove(&mut self, item: T); fn get(&self, id: String) -> Option; fn update(&mut self, item: T); - fn filter(&self, filter: F) -> Box>; + fn filter(&self, filter: F) -> Box + '_>; } pub struct BookFilter { diff --git a/src/infrastructure/repository/inmem/books.rs b/src/infrastructure/repository/inmem/books.rs index f808b00..ecedf50 100644 --- a/src/infrastructure/repository/inmem/books.rs +++ b/src/infrastructure/repository/inmem/books.rs @@ -1,4 +1,3 @@ -use crate::domain::author::Author; use crate::domain::repository::{BookFilter, Repository}; use crate::domain::{author, book}; use std::collections::HashMap; @@ -61,7 +60,7 @@ impl Into for Book { pub struct BookRepository { books: Vec, - authors: HashMap, + authors: HashMap, author_uniques: HashMap, } @@ -110,10 +109,7 @@ impl Repository for BookRepository { self.books.push(item.into()); } - fn bulk_add(&mut self, items: I) - where - I: IntoIterator, - { + fn bulk_add(&mut self, items: Vec) { items.into_iter().for_each(|item| { if self.get(item.id.to_string()).is_none() { self.add(item) diff --git a/src/lib.rs b/src/lib.rs index a35a2b2..6e51ddc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,12 @@ use crate::application::application::Application; -use crate::infrastructure::repository::inmem::books::BookRepository; pub mod domain; mod application; pub mod infrastructure; -pub fn demo() -> Application { - let mut app = Application::new(BookRepository::new()); +pub fn demo() -> Application { + let mut app = Application::new(); app.start().expect("Application initialization failed"); app diff --git a/src/main.rs b/src/main.rs index 4cb431e..b9cbc15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,11 +22,11 @@ fn main() { updated: None, }; - let res = app.books.books_feed(filter); + let res = app.srv.books_feed(filter); println!("{}", to_xml_string(&res).unwrap()); if let Some(book) = res.entry.iter().next() { - let book = app.books.repo.lock().unwrap().get(book.id.to_string().clone()); + let book = app.repo.lock().unwrap().get(book.id.to_string().clone()); println!("{:?}", book.unwrap().author); }