diff --git a/Cargo.lock b/Cargo.lock index 923ecc4..571c791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -775,9 +775,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "67827e6ea8ee8a7c4a72227ef4fc08957040acffdb5f122733b24fa12daff41b" [[package]] name = "memchr" @@ -1080,9 +1080,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc55135a600d700580e406b4de0d59cb9ad25e344a3a091a97ded2622ec4ec6" +checksum = "f32154ba0af3a075eefa1eda8bb414ee928f62303a54ea85b8d6638ff1a6ee9e" [[package]] name = "proc-macro2" @@ -1150,7 +1150,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", + "regex-automata 0.3.4", "regex-syntax 0.7.4", ] @@ -1165,9 +1165,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" dependencies = [ "aho-corasick", "memchr", @@ -1297,18 +1297,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.175" +version = "1.0.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b" dependencies = [ "proc-macro2", "quote", @@ -1317,9 +1317,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", diff --git a/Cargo.toml b/Cargo.toml index ffa6fdf..9d14d2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ serde_json = "1.0.96" axum = "0.6.18" translit = "0.5.0" zip = "0.6.6" -tempfile = "3.5.0" +tempfile = "3.7.0" bytes = "1.4.0" axum-prometheus = "0.4.0" base64 = "0.21.2" diff --git a/src/services/downloader/mod.rs b/src/services/downloader/mod.rs index 72fddc3..198ad2a 100644 --- a/src/services/downloader/mod.rs +++ b/src/services/downloader/mod.rs @@ -96,11 +96,14 @@ pub async fn download_chain<'a>( if is_zip && book.file_type.to_lowercase() == "html" { let filename = get_filename_by_book(book, file_type, true, false); let filename_ascii = get_filename_by_book(book, file_type, true, true); + let data_size: usize = response.headers().get("Content-Length").unwrap().to_str().unwrap().parse().unwrap(); + return Some( DownloadResult::new( Data::Response(response), filename, - filename_ascii + filename_ascii, + data_size ) ); } @@ -108,19 +111,22 @@ pub async fn download_chain<'a>( if !is_zip && !final_need_zip && !converting { let filename = get_filename_by_book(book, &book.file_type, false, false); let filename_ascii = get_filename_by_book(book, file_type, false, true); + let data_size: usize = response.headers().get("Content-Length").unwrap().to_str().unwrap().parse().unwrap(); + return Some( DownloadResult::new( Data::Response(response), filename, filename_ascii, + data_size, ) ); }; - let unziped_temp_file = { + let (unziped_temp_file, data_size) = { let temp_file_to_unzip_result = response_to_tempfile(&mut response).await; let temp_file_to_unzip = match temp_file_to_unzip_result { - Some(v) => v, + Some(v) => v.0, None => return None, }; @@ -131,7 +137,7 @@ pub async fn download_chain<'a>( }; - let mut clean_file = if converting { + let (mut clean_file, data_size) = if converting { match convert_file(unziped_temp_file, file_type.to_string()).await { Some(mut response) => { match response_to_tempfile(&mut response).await { @@ -142,18 +148,20 @@ pub async fn download_chain<'a>( None => return None, } } else { - unziped_temp_file + (unziped_temp_file, data_size) }; if !final_need_zip { let t = SpooledTempAsyncRead::new(clean_file); let filename = get_filename_by_book(book, file_type, false, false); let filename_ascii = get_filename_by_book(book, file_type, false, true); + return Some( DownloadResult::new( Data::SpooledTempAsyncRead(t), filename, - filename_ascii + filename_ascii, + data_size ) ); }; @@ -161,15 +169,17 @@ pub async fn download_chain<'a>( let t_file_type = if file_type == "fb2zip" { "fb2" } else { file_type }; let filename = get_filename_by_book(book, t_file_type, false, false); match zip(&mut clean_file, filename.as_str()) { - Some(v) => { - let t = SpooledTempAsyncRead::new(v); + Some((t_file, data_size)) => { + let t = SpooledTempAsyncRead::new(t_file); let filename = get_filename_by_book(book, file_type, true, false); let filename_ascii = get_filename_by_book(book, file_type, true, true); + Some( DownloadResult::new( Data::SpooledTempAsyncRead(t), filename, - filename_ascii + filename_ascii, + data_size ) ) }, diff --git a/src/services/downloader/types.rs b/src/services/downloader/types.rs index c51186d..5652d0e 100644 --- a/src/services/downloader/types.rs +++ b/src/services/downloader/types.rs @@ -15,6 +15,7 @@ pub struct DownloadResult { pub data: Data, pub filename: String, pub filename_ascii: String, + pub data_size: usize, } pub fn get_response_async_read(it: Response) -> impl AsyncRead { @@ -25,8 +26,8 @@ pub fn get_response_async_read(it: Response) -> impl AsyncRead { } impl DownloadResult { - pub fn new(data: Data, filename: String, filename_ascii: String) -> Self { - Self { data, filename, filename_ascii } + pub fn new(data: Data, filename: String, filename_ascii: String, data_size: usize) -> Self { + Self { data, filename, filename_ascii, data_size } } pub fn get_async_read(self) -> Pin> { diff --git a/src/services/downloader/utils.rs b/src/services/downloader/utils.rs index 71543b4..7e65152 100644 --- a/src/services/downloader/utils.rs +++ b/src/services/downloader/utils.rs @@ -6,9 +6,11 @@ use bytes::Buf; use std::io::{Seek, SeekFrom, Write}; -pub async fn response_to_tempfile(res: &mut Response) -> Option { +pub async fn response_to_tempfile(res: &mut Response) -> Option<(SpooledTempFile, usize)> { let mut tmp_file = tempfile::spooled_tempfile(5 * 1024 * 1024); + let mut data_size: usize = 0; + { loop { let chunk = res.chunk().await; @@ -23,6 +25,8 @@ pub async fn response_to_tempfile(res: &mut Response) -> Option None => break, }; + data_size += data.len(); + match tmp_file.write(data.chunk()) { Ok(_) => (), Err(_) => return None, @@ -32,5 +36,5 @@ pub async fn response_to_tempfile(res: &mut Response) -> Option tmp_file.seek(SeekFrom::Start(0)).unwrap(); } - Some(tmp_file) + Some((tmp_file, data_size)) } \ No newline at end of file diff --git a/src/services/downloader/zip.rs b/src/services/downloader/zip.rs index f900f3d..29d33a1 100644 --- a/src/services/downloader/zip.rs +++ b/src/services/downloader/zip.rs @@ -1,10 +1,10 @@ -use std::io::{Seek, SeekFrom}; +use std::io::Seek; use tempfile::SpooledTempFile; use zip::write::FileOptions; -pub fn unzip(tmp_file: SpooledTempFile, file_type: &str) -> Option { +pub fn unzip(tmp_file: SpooledTempFile, file_type: &str) -> Option<(SpooledTempFile, usize)> { let mut archive = zip::ZipArchive::new(tmp_file).unwrap(); let file_type_lower = file_type.to_lowercase(); @@ -16,21 +16,21 @@ pub fn unzip(tmp_file: SpooledTempFile, file_type: &str) -> Option (), + let size: usize = match std::io::copy(&mut file, &mut output_file) { + Ok(v) => v.try_into().unwrap(), Err(_) => return None, }; - output_file.seek(SeekFrom::Start(0)).unwrap(); + output_file.rewind().unwrap(); - return Some(output_file); + return Some((output_file, size)); } } None } -pub fn zip(tmp_file: &mut SpooledTempFile, filename: &str) -> Option { +pub fn zip(tmp_file: &mut SpooledTempFile, filename: &str) -> Option<(SpooledTempFile, usize)> { let output_file = tempfile::spooled_tempfile(5 * 1024 * 1024); let mut archive = zip::ZipWriter::new(output_file); @@ -54,7 +54,9 @@ pub fn zip(tmp_file: &mut SpooledTempFile, filename: &str) -> Option return None, }; - archive_result.seek(SeekFrom::Start(0)).unwrap(); + let data_size: usize = archive_result.stream_position().unwrap().try_into().unwrap(); - Some(archive_result) + archive_result.rewind().unwrap(); + + Some((archive_result, data_size)) } \ No newline at end of file diff --git a/src/views.rs b/src/views.rs index 9a1b308..2773c96 100644 --- a/src/views.rs +++ b/src/views.rs @@ -40,6 +40,7 @@ pub async fn download( let filename = data.filename.clone(); let filename_ascii = data.filename_ascii.clone(); + let file_size = data.data_size; let reader = data.get_async_read(); let stream = ReaderStream::new(reader); @@ -52,6 +53,10 @@ pub async fn download( header::CONTENT_DISPOSITION, format!("attachment; filename={filename_ascii}"), ), + ( + header::CONTENT_LENGTH, + format!("{file_size}") + ), ( header::HeaderName::from_static("x-filename-b64"), encoder.encode(filename),