From c9ac3dd683a6c76355d5fa3697a98b71276bc3ff Mon Sep 17 00:00:00 2001 From: Daniel M Date: Thu, 31 Mar 2022 17:57:02 +0200 Subject: [PATCH] Remove into-file option + more refactoring --- src/args.rs | 8 -------- src/download.rs | 52 +++++++++++++++++++++++++------------------------ src/main.rs | 48 ++++++++++++++++++++------------------------- 3 files changed, 48 insertions(+), 60 deletions(-) diff --git a/src/args.rs b/src/args.rs index 7349238..cd3b9a1 100644 --- a/src/args.rs +++ b/src/args.rs @@ -18,14 +18,6 @@ pub struct CLIArgs { )] pub outdir: PathBuf, - #[clap( - short = 'i', - long = "into-file", - value_name = "FILENAME", - help = "Force filename. This only works for single file downloads", - )] - pub into_file: Option, - #[clap( short = 'n', long = "num-files", diff --git a/src/download.rs b/src/download.rs index ca79e32..52a4e73 100644 --- a/src/download.rs +++ b/src/download.rs @@ -95,10 +95,7 @@ pub async fn download_feedback_chunks( ) -> Result<()> { let mut content_length = match content_length { Some(it) => it, - None => { - let (content_length, _) = http_get_filesize_and_range_support(url).await?; - content_length - } + None => http_get_filesize_and_range_support(url).await?.filesize, }; // Send the HTTP request to download the given link @@ -226,7 +223,7 @@ pub async fn download_feedback_multi( ) -> Result<()> { let content_length = match content_length { Some(it) => it, - None => http_get_filesize_and_range_support(url).await?.0, + None => http_get_filesize_and_range_support(url).await?.filesize, }; // Create zeroed file with 1 byte too much. This will be truncated on download @@ -379,40 +376,45 @@ pub async fn download_feedback_multi( async fn create_zeroed_file(file: &Path, filesize: usize) -> Result<()> { let ofile = tokio::fs::OpenOptions::new() .create(true) - // Open in write mode .write(true) - // Delete and overwrite the file .truncate(true) .open(file) .await?; ofile.set_len(filesize as u64).await?; - Ok(()) } -pub async fn http_get_filesize_and_range_support(url: &str) -> Result<(u64, bool)> { +pub struct HttpFileInfo { + pub filesize: u64, + pub range_support: bool, + pub filename: String, +} + +pub async fn http_get_filesize_and_range_support(url: &str) -> Result { let resp = reqwest::Client::new().head(url).send().await?; - if let Some(filesize) = resp.headers().get(reqwest::header::CONTENT_LENGTH) { - if let Ok(val_str) = filesize.to_str() { - if let Ok(val) = val_str.parse::() { - let mut range_supported = false; + let filesize = resp + .headers() + .get(reqwest::header::CONTENT_LENGTH) + .and_then(|it| it.to_str().unwrap().parse::().ok()) + .ok_or(DlError::ContentLengthUnknown)?; - if let Some(range) = resp.headers().get(reqwest::header::ACCEPT_RANGES) { - if let Ok(range) = range.to_str() { - if range == "bytes" { - range_supported = true; - } - } - } + let range = resp + .headers() + .get(reqwest::header::ACCEPT_RANGES) + .and_then(|it| it.to_str().ok()); + let range_support = matches!(range, Some("bytes")); - return Ok((val, range_supported)); - } - } - } + let filename = url_to_filename(url); - Err(DlError::ContentLengthUnknown.into()) + let info = HttpFileInfo { + filesize, + range_support, + filename, + }; + + Ok(info) } #[cfg(test)] diff --git a/src/main.rs b/src/main.rs index 0d9ded6..92a0350 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use std::{ }; use clap::Parser; -use download::{download_feedback, download_feedback_multi, http_get_filesize_and_range_support}; use futures::future::join_all; use tokio::{ fs::create_dir_all, @@ -16,11 +15,12 @@ use tokio::{ Mutex, }, }; -use zippy::is_zippyshare_url; use crate::{ args::CLIArgs, dlreport::{watch_and_print_reports, DlReport, DlReporter, DlStatus}, + download::{download_feedback, download_feedback_multi, http_get_filesize_and_range_support}, + zippy::is_zippyshare_url, }; use anyhow::Result; @@ -134,71 +134,65 @@ async fn download_job(urls: SyncQueue, reporter: UnboundedSender, cli_ dlreq.url.to_string() }; - let file_name = cli_args - .into_file - .clone() - .unwrap_or_else(|| download::url_to_filename(&url).into()); - - let into_file: PathBuf = cli_args - .outdir - .join(Path::new(&file_name)) - .to_str() - .unwrap() - .to_string() - .into(); - - let (filesize, range_supported) = match http_get_filesize_and_range_support(&url).await { - Ok((filesize, range_supported)) => (filesize, range_supported), + let info = match http_get_filesize_and_range_support(&url).await { + Ok(it) => it, Err(_e) => { reporter.send(DlStatus::Message(format!( - "Error while querying metadata: {}", - url + "Error while querying metadata: {url}" ))); continue; } }; + let into_file: PathBuf = cli_args + .outdir + .join(Path::new(&info.filename)) + .to_str() + .unwrap() + .to_string() + .into(); + // If file with same name is present locally, check filesize if into_file.exists() { let local_filesize = std::fs::metadata(&into_file).unwrap().len(); - if filesize == local_filesize { + if info.filesize == local_filesize { reporter.send(DlStatus::Message(format!( "Skipping file '{}': already present", - file_name.display() + info.filename ))); reporter.send(DlStatus::Skipped); continue; } else { reporter.send(DlStatus::Message(format!( "Replacing file '{}': present but not completed", - &file_name.display() + &info.filename ))); } } let dl_status = if cli_args.conn_count.get() == 1 { - download_feedback(&url, &into_file, reporter.clone(), Some(filesize)).await - } else if !range_supported { + download_feedback(&url, &into_file, reporter.clone(), Some(info.filesize)).await + } else if !info.range_support { reporter.send(DlStatus::Message(format!( "Server does not support range headers. Downloading with single connection: {}", url ))); - download_feedback(&url, &into_file, reporter.clone(), Some(filesize)).await + download_feedback(&url, &into_file, reporter.clone(), Some(info.filesize)).await } else { download_feedback_multi( &url, &into_file, reporter.clone(), cli_args.conn_count.get(), - Some(filesize), + Some(info.filesize), ) .await }; if dl_status.is_err() { reporter.send(DlStatus::DoneErr { - filename: file_name.to_str().unwrap().to_string(), + filename: info.filename, }); } }