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