feat: Add zip parser
ref: Parsers now returns vector, not a single book
This commit is contained in:
@@ -10,6 +10,7 @@ pub struct Loader {
|
||||
|
||||
pub struct LoaderIter {
|
||||
queue: VecDeque<PathBuf>,
|
||||
pending_books: VecDeque<Book>,
|
||||
}
|
||||
|
||||
impl Loader {
|
||||
@@ -25,13 +26,20 @@ impl IntoIterator for Loader {
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let mut queue = VecDeque::new();
|
||||
queue.push_back(self.root);
|
||||
LoaderIter { queue }
|
||||
LoaderIter {
|
||||
queue,
|
||||
pending_books: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for LoaderIter {
|
||||
type Item = Book;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(book) = self.pending_books.pop_front() {
|
||||
return Some(book);
|
||||
}
|
||||
|
||||
while let Some(path) = self.queue.pop_front() {
|
||||
match path.is_dir() {
|
||||
true => {
|
||||
@@ -42,9 +50,11 @@ impl Iterator for LoaderIter {
|
||||
}
|
||||
}
|
||||
false => {
|
||||
let book = Self::parse_path(&path);
|
||||
if book.is_some() {
|
||||
return book;
|
||||
if let Some(books) = Self::parse_path(&path) {
|
||||
self.pending_books.extend(books);
|
||||
if let Some(book) = self.pending_books.pop_front() {
|
||||
return Some(book);
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -57,9 +67,9 @@ impl Iterator for LoaderIter {
|
||||
}
|
||||
|
||||
impl LoaderIter {
|
||||
fn parse_path(path: &PathBuf) -> Option<Book> {
|
||||
fn parse_path(path: &PathBuf) -> Option<Vec<Book>> {
|
||||
match parsers::parse(&path) {
|
||||
Ok(book) => return Some(book),
|
||||
Ok(books) => return Some(books),
|
||||
Err(err) => {
|
||||
match err {
|
||||
parsers::Error::ParseError(err) => {
|
||||
|
||||
@@ -48,9 +48,8 @@ impl<'a> Iterator for LoaderIter<'a> {
|
||||
Ok(events) => {
|
||||
for ev in events {
|
||||
println!("{:?}", ev);
|
||||
if let Some(book) = Self::process_event(ev) {
|
||||
println!("{}", book);
|
||||
self.queue.push_back(book);
|
||||
if let Some(books) = Self::process_event(ev) {
|
||||
self.queue.extend(books);
|
||||
}
|
||||
}
|
||||
self.queue.pop_front()
|
||||
@@ -64,16 +63,21 @@ impl<'a> Iterator for LoaderIter<'a> {
|
||||
}
|
||||
|
||||
impl<'a> LoaderIter<'a> {
|
||||
fn process_event(event: Event<&OsStr>) -> Option<Book> {
|
||||
fn process_event(event: Event<&OsStr>) -> Option<Vec<Book>> {
|
||||
let path = PathBuf::from(event.name?);
|
||||
if !path.exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match parsers::parse(&path) {
|
||||
Ok(book) => Some(book),
|
||||
Ok(books) => {
|
||||
for book in &books {
|
||||
println!("{}", book);
|
||||
}
|
||||
Some(books)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("Failed to parse book from {:?}: {:?}", path, err);
|
||||
eprintln!("Failed to parse book from {:?}: {}", path, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::path::Path;
|
||||
use crate::domain::author;
|
||||
use crate::domain::book::Book;
|
||||
|
||||
pub fn parse(path: &Path) -> Result<Book, String> {
|
||||
pub fn parse(path: &Path) -> Result<Vec<Book>, String> {
|
||||
let file = File::open(path).map_err(|e| e.to_string())?;
|
||||
let mut reader = Reader::from_reader(BufReader::new(file));
|
||||
let mut buf = Vec::new();
|
||||
@@ -131,7 +131,7 @@ pub fn parse(path: &Path) -> Result<Book, String> {
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
Ok(Book{
|
||||
Ok(vec![Book{
|
||||
id: Uuid::new_v4(),
|
||||
title,
|
||||
author: authors,
|
||||
@@ -141,5 +141,5 @@ pub fn parse(path: &Path) -> Result<Book, String> {
|
||||
published_at,
|
||||
publisher,
|
||||
updated: chrono::Utc::now().to_rfc3339(),
|
||||
})
|
||||
}])
|
||||
}
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
use std::fmt;
|
||||
use crate::domain::book::Book;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod rs;
|
||||
mod fb2;
|
||||
mod zip;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
NotSupported,
|
||||
ParseError(String),
|
||||
}
|
||||
pub fn parse(path: &PathBuf) -> Result<Book, Error> {
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::NotSupported => write!(f, "File format not supported"),
|
||||
Error::ParseError(msg) => write!(f, "Parse error: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(path: &PathBuf) -> Result<Vec<Book>, Error> {
|
||||
match path.extension().and_then(|s| s.to_str()) {
|
||||
Some("rs") => rs::parse(path).map_err(Error::ParseError),
|
||||
Some("fb2") => fb2::parse(path).map_err(Error::ParseError),
|
||||
Some("zip") => zip::parse(path).map_err(Error::ParseError),
|
||||
Some(_) | None => Err(Error::NotSupported),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::domain::author::Author;
|
||||
use crate::domain::book::Book;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn parse(path: &PathBuf) -> Result<Book, String> {
|
||||
pub fn parse(path: &PathBuf) -> Result<Vec<Book>, String> {
|
||||
let mut book = Book::new();
|
||||
|
||||
book.title = path.to_string_lossy().to_string();
|
||||
@@ -11,5 +11,5 @@ pub fn parse(path: &PathBuf) -> Result<Book, String> {
|
||||
author.first_name = path.extension().unwrap().to_string_lossy().to_string();
|
||||
book.author.push(author);
|
||||
|
||||
return Ok(book);
|
||||
return Ok(vec![ book]);
|
||||
}
|
||||
|
||||
26
src/application/parsers/zip.rs
Normal file
26
src/application/parsers/zip.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::application::parsers;
|
||||
use crate::domain::book::Book;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
use zip::ZipArchive;
|
||||
|
||||
pub fn parse(path: &Path) -> Result<Vec<Book>, String> {
|
||||
let file = File::open(path).map_err(|e| e.to_string())?;
|
||||
let reader = BufReader::new(file);
|
||||
let mut archive = ZipArchive::new(reader).map_err(|e| e.to_string())?;
|
||||
|
||||
let mut books: Vec<Book> = Vec::new();
|
||||
|
||||
for i in 0..archive.len() {
|
||||
let file = archive.by_index(i).map_err(|e| e.to_string())?;
|
||||
let name = file.name().to_string();
|
||||
|
||||
match parsers::parse(&PathBuf::from(name.to_lowercase())) {
|
||||
Ok(new_books) => books.extend(new_books),
|
||||
Err(e) => return Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(books)
|
||||
}
|
||||
Reference in New Issue
Block a user