From a71ce6d26f2f71315a0057b6681c22b42945dbea Mon Sep 17 00:00:00 2001 From: derfenix Date: Tue, 9 Sep 2025 11:00:27 +0300 Subject: [PATCH] feat: Add zip parser ref: Parsers now returns vector, not a single book --- Cargo.lock | 425 +++++++++++++++++++++++++++++ Cargo.toml | 1 + src/application/loaders/fs.rs | 22 +- src/application/loaders/inotify.rs | 16 +- src/application/parsers/fb2.rs | 6 +- src/application/parsers/mod.rs | 15 +- src/application/parsers/rs.rs | 4 +- src/application/parsers/zip.rs | 26 ++ 8 files changed, 497 insertions(+), 18 deletions(-) create mode 100644 src/application/parsers/zip.rs diff --git a/Cargo.lock b/Cargo.lock index 0664aca..12def42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -26,6 +37,15 @@ dependencies = [ "libc", ] +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -53,12 +73,30 @@ version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bzip2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea8dcd42434048e4f7a304411d9273a411f647446c1234a65ce0554923f4cff" +dependencies = [ + "libbz2-rs-sys", +] + [[package]] name = "cc" version = "1.2.36" @@ -66,6 +104,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -88,6 +128,22 @@ dependencies = [ "windows-link 0.2.0", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.8.0" @@ -103,6 +159,86 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deflate64" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" + +[[package]] +name = "deranged" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -146,12 +282,29 @@ dependencies = [ "syn", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "find-msvc-tools" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "libz-rs-sys", + "miniz_oxide", +] + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -167,6 +320,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -185,6 +348,21 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -316,6 +494,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inotify" version = "0.11.0" @@ -338,6 +526,15 @@ dependencies = [ "libc", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "io-uring" version = "0.7.10" @@ -349,6 +546,16 @@ dependencies = [ "libc", ] +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom", + "libc", +] + [[package]] name = "js-sys" version = "0.3.78" @@ -359,12 +566,27 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "libbz2-rs-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4a545a15244c7d945065b5d392b2d2d7f21526fba56ce51467b06ed445e8f7" + [[package]] name = "libc" version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +[[package]] +name = "libz-rs-sys" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840db8cf39d9ec4dd794376f38acc40d0fc65eec2a8f484f7fd375b84602becd" +dependencies = [ + "zlib-rs", +] + [[package]] name = "litemap" version = "0.8.0" @@ -377,6 +599,16 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +[[package]] +name = "lzma-rust2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c60a23ffb90d527e23192f1246b14746e2f7f071cb84476dd879071696c18a4a" +dependencies = [ + "crc", + "sha2", +] + [[package]] name = "memchr" version = "2.7.5" @@ -403,6 +635,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.19" @@ -438,6 +676,17 @@ dependencies = [ "serde", "url", "uuid", + "zip", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", ] [[package]] @@ -452,6 +701,12 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "potential_utf" version = "0.1.3" @@ -461,6 +716,18 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppmd-rust" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -565,18 +832,46 @@ dependencies = [ "syn", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha1_smol" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "slab" version = "0.4.11" @@ -605,6 +900,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.106" @@ -647,6 +948,25 @@ dependencies = [ "syn", ] +[[package]] +name = "time" +version = "0.3.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + [[package]] name = "tinystr" version = "0.8.1" @@ -673,6 +993,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -729,6 +1055,12 @@ dependencies = [ "syn", ] +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1018,6 +1350,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerotrie" version = "0.2.2" @@ -1050,3 +1402,76 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zip" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fdfa5f34b5980f2c21b3a2c68c09ade4debddc7be52c51056695effc73a08c" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "deflate64", + "flate2", + "getrandom", + "hmac", + "indexmap", + "lzma-rust2", + "memchr", + "pbkdf2", + "ppmd-rust", + "sha1", + "time", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] +name = "zlib-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" + +[[package]] +name = "zopfli" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 1ca014a..8cd7b34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ uuid = { version = "1.18.1", features = [ "rng", ] } quick-xml = { version = "0.38.3", features = ["serialize", "serde"] } +zip = "5.0.0" [profile.release] lto = "fat" \ No newline at end of file diff --git a/src/application/loaders/fs.rs b/src/application/loaders/fs.rs index 4a08a1d..0d4315d 100644 --- a/src/application/loaders/fs.rs +++ b/src/application/loaders/fs.rs @@ -10,6 +10,7 @@ pub struct Loader { pub struct LoaderIter { queue: VecDeque, + pending_books: VecDeque, } 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 { + 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 { + fn parse_path(path: &PathBuf) -> Option> { match parsers::parse(&path) { - Ok(book) => return Some(book), + Ok(books) => return Some(books), Err(err) => { match err { parsers::Error::ParseError(err) => { diff --git a/src/application/loaders/inotify.rs b/src/application/loaders/inotify.rs index 74af8fc..5ffc19c 100644 --- a/src/application/loaders/inotify.rs +++ b/src/application/loaders/inotify.rs @@ -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 { + fn process_event(event: Event<&OsStr>) -> Option> { 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 } } diff --git a/src/application/parsers/fb2.rs b/src/application/parsers/fb2.rs index f333ed8..61a9c36 100644 --- a/src/application/parsers/fb2.rs +++ b/src/application/parsers/fb2.rs @@ -7,7 +7,7 @@ use std::path::Path; use crate::domain::author; use crate::domain::book::Book; -pub fn parse(path: &Path) -> Result { +pub fn parse(path: &Path) -> Result, 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 { buf.clear(); } - Ok(Book{ + Ok(vec![Book{ id: Uuid::new_v4(), title, author: authors, @@ -141,5 +141,5 @@ pub fn parse(path: &Path) -> Result { published_at, publisher, updated: chrono::Utc::now().to_rfc3339(), - }) + }]) } diff --git a/src/application/parsers/mod.rs b/src/application/parsers/mod.rs index 0560f4b..120f46b 100644 --- a/src/application/parsers/mod.rs +++ b/src/application/parsers/mod.rs @@ -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 { + +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, 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), } } diff --git a/src/application/parsers/rs.rs b/src/application/parsers/rs.rs index 352f504..8735498 100644 --- a/src/application/parsers/rs.rs +++ b/src/application/parsers/rs.rs @@ -2,7 +2,7 @@ use crate::domain::author::Author; use crate::domain::book::Book; use std::path::PathBuf; -pub fn parse(path: &PathBuf) -> Result { +pub fn parse(path: &PathBuf) -> Result, String> { let mut book = Book::new(); book.title = path.to_string_lossy().to_string(); @@ -11,5 +11,5 @@ pub fn parse(path: &PathBuf) -> Result { author.first_name = path.extension().unwrap().to_string_lossy().to_string(); book.author.push(author); - return Ok(book); + return Ok(vec![ book]); } diff --git a/src/application/parsers/zip.rs b/src/application/parsers/zip.rs new file mode 100644 index 0000000..66f7c1a --- /dev/null +++ b/src/application/parsers/zip.rs @@ -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, 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 = 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) +}