diff --git a/Cargo.lock b/Cargo.lock index 40982f4..dcf17d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" + [[package]] name = "atty" version = "0.2.14" @@ -170,6 +176,7 @@ dependencies = [ name = "ffdl" version = "0.1.2" dependencies = [ + "anyhow", "chrono", "clap", "crossterm", @@ -177,6 +184,7 @@ dependencies = [ "percent-encoding", "regex", "reqwest", + "thiserror", "tokio", ] @@ -983,6 +991,26 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.1.44" diff --git a/Cargo.toml b/Cargo.toml index 64024cd..6641a92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,5 @@ regex = "1.5.5" crossterm = "0.23.1" clap = { version = "3.1.6", features = [ "derive" ] } chrono = "0.4.19" +thiserror = "1.0.30" +anyhow = "1.0.56" diff --git a/src/dlreport.rs b/src/dlreport.rs index 1c33483..2578d44 100644 --- a/src/dlreport.rs +++ b/src/dlreport.rs @@ -9,7 +9,7 @@ use crossterm::execute; use crossterm::style::Print; use crossterm::terminal::{Clear, ClearType}; -use crate::errors::*; +use anyhow::Result; #[derive(Clone, Debug)] pub enum DlStatus { @@ -76,7 +76,7 @@ fn print_accumulated_report( moved_lines: u16, file_count_completed: i32, file_count_total: i32, -) -> ResBE { +) -> Result { let mut dl_speed_sum = 0.0; execute!( @@ -142,7 +142,7 @@ fn print_accumulated_report( pub async fn watch_and_print_reports( mut receiver: mpsc::UnboundedReceiver, file_count_total: i32, -) -> ResBE<()> { +) -> Result<()> { let mut statuses: HashMap = HashMap::new(); let mut moved_lines = 0; let mut msg_queue = VecDeque::new(); diff --git a/src/download.rs b/src/download.rs index 8e9f214..5b9c9bc 100644 --- a/src/download.rs +++ b/src/download.rs @@ -1,3 +1,4 @@ +use anyhow::Result; use futures::stream::FuturesUnordered; use futures::StreamExt; use percent_encoding::percent_decode_str; @@ -81,7 +82,7 @@ pub async fn download_feedback( into_file: &Path, rep: DlReporter, content_length: Option, -) -> ResBE<()> { +) -> Result<()> { download_feedback_chunks(url, into_file, rep, None, content_length).await } @@ -91,7 +92,7 @@ pub async fn download_feedback_chunks( rep: DlReporter, from_to: Option<(u64, u64)>, content_length: Option, -) -> ResBE<()> { +) -> Result<()> { let mut content_length = match content_length { Some(it) => it, None => { @@ -222,7 +223,7 @@ pub async fn download_feedback_multi( rep: DlReporter, conn_count: u32, content_length: Option, -) -> ResBE<()> { +) -> Result<()> { let content_length = match content_length { Some(it) => it, None => http_get_filesize_and_range_support(url).await?.0, @@ -269,7 +270,6 @@ pub async fn download_feedback_multi( Some(specific_content_length), ) .await - .map_err(|e| e.to_string()) })) } @@ -323,7 +323,7 @@ pub async fn download_feedback_multi( } rep.send(DlStatus::Update { - speed_mbps: speed_mbps, + speed_mbps, bytes_curr: progress_curr, }); } @@ -353,7 +353,7 @@ pub async fn download_feedback_multi( tokio::fs::remove_file(&into_file).await?; - return Err(e.into()); + return Err(e); } } @@ -376,7 +376,7 @@ pub async fn download_feedback_multi( Ok(()) } -async fn create_zeroed_file(file: &Path, filesize: usize) -> ResBE<()> { +async fn create_zeroed_file(file: &Path, filesize: usize) -> Result<()> { let ofile = tokio::fs::OpenOptions::new() .create(true) // Open in write mode @@ -391,7 +391,7 @@ async fn create_zeroed_file(file: &Path, filesize: usize) -> ResBE<()> { Ok(()) } -pub async fn http_get_filesize_and_range_support(url: &str) -> ResBE<(u64, bool)> { +pub async fn http_get_filesize_and_range_support(url: &str) -> Result<(u64, bool)> { let resp = reqwest::Client::new().head(url).send().await?; if let Some(filesize) = resp.headers().get(reqwest::header::CONTENT_LENGTH) { diff --git a/src/errors.rs b/src/errors.rs index 40afa21..3da2644 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,27 +1,14 @@ -use std::error::Error; -use std::fmt::{self, Display, Formatter}; - -/// Result Boxed Error -pub type ResBE = Result>; +use thiserror::Error; #[allow(unused)] -#[derive(Clone, Debug)] +#[derive(Error, Clone, Debug)] pub enum DlError { + #[error("Bad http response status")] BadHttpStatus, + #[error("Content-Length is unknown")] ContentLengthUnknown, + #[error("Http server sent no more data")] HttpNoData, + #[error("Unknown download error: '{0}'")] Other(String), } - -impl Error for DlError {} - -impl Display for DlError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - DlError::BadHttpStatus => write!(f, "Bad http response status"), - DlError::ContentLengthUnknown => write!(f, "Content-Length is unknown"), - DlError::HttpNoData => write!(f, "Http server sent no more data"), - DlError::Other(s) => write!(f, "Unknown download error: '{}'", s), - } - } -} diff --git a/src/main.rs b/src/main.rs index cb668e7..412dd8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,9 +21,10 @@ use zippy::is_zippyshare_url; use crate::{ args::CLIArgs, dlreport::{watch_and_print_reports, DlReport, DlReporter, DlStatus}, - errors::ResBE, }; +use anyhow::Result; + mod args; mod dlreport; mod download; @@ -38,7 +39,7 @@ struct DlRequest { type SyncQueue = Arc>>; #[tokio::main] -async fn main() -> ResBE<()> { +async fn main() -> Result<()> { let args = CLIArgs::parse(); // Combine all urls taken from files and the ones provided on the command line @@ -62,7 +63,7 @@ async fn main() -> ResBE<()> { } /// Parse a listfile and return all urls found in it -async fn urls_from_listfile(listfile: &Path) -> ResBE> { +async fn urls_from_listfile(listfile: &Path) -> Result> { let text = tokio::fs::read_to_string(listfile).await?; let urls = text .lines() @@ -74,7 +75,7 @@ async fn urls_from_listfile(listfile: &Path) -> ResBE> { } // Download all files in parallel according to the provided CLI arguments -async fn download_multiple(args: CLIArgs, raw_urls: Vec) -> ResBE<()> { +async fn download_multiple(args: CLIArgs, raw_urls: Vec) -> Result<()> { let num_urls = raw_urls.len(); let urls: SyncQueue = Default::default(); diff --git a/src/zippy.rs b/src/zippy.rs index f0db94b..e58fa56 100644 --- a/src/zippy.rs +++ b/src/zippy.rs @@ -1,8 +1,7 @@ +use anyhow::Result; use regex::Regex; use std::io::{Error, ErrorKind}; -use crate::errors::ResBE; - pub fn is_zippyshare_url(url: &str) -> bool { Regex::new(r"^https?://(?:www\d*\.)?zippyshare\.com/v/[0-9a-zA-Z]+/file\.html$") .unwrap() @@ -23,7 +22,7 @@ Link generation code: document.getElementById('dlbutton').href = "/d/0Ky7p1C6/" + (186549 % 51245 + 186549 % 913) + "/some-file-name.part1.rar"; ``` */ -pub async fn resolve_link(url: &str) -> ResBE { +pub async fn resolve_link(url: &str) -> Result { // Regex to check if the provided url is a zippyshare download url let re = Regex::new(r"(https://www\d*\.zippyshare\.com)")?; if !re.is_match(&url) {