aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 28de7625c618efc1af583066bd33e9036b077689 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
use std::fs;
use std::io::{self, BufRead};
use std::mem;
use std::path::PathBuf;

use anyhow::Error;
use hyper::Uri;
use structopt::StructOpt;

mod download;
use download::download;

#[derive(StructOpt, Debug)]
struct Args {
    /// Read URLs from a file
    #[structopt(short, long)]
    input_file: Option<PathBuf>,

    /// Specify output filename (will cause an error if multiple URLs are given)
    #[structopt(short = "O", long)]
    output_document: Option<PathBuf>,

    /// The URLs to download
    urls: Vec<Uri>,
}

#[tokio::main]
async fn main() -> Result<(), Vec<Error>> {
    let (args, urls) = {
        let mut args: Args = Args::from_args();
        let mut urls = mem::take(&mut args.urls);
        if let Some(input_file) = &args.input_file {
            if let Ok(input_file) = fs::File::open(input_file) {
                let input_file = io::BufReader::new(input_file);
                let input_file_urls = input_file
                    .lines()
                    .filter_map(|line| line.ok().and_then(|line| line.parse().ok()));
                urls.extend(input_file_urls);
            }
        }
        (args, urls)
    };
    if urls.len() != 1 && args.output_document.is_some() {
        panic!("can't use the same output file for multiple URLs!")
    }

    let download_handles = urls
        .into_iter()
        .map(|url| download(url, &args));
    let downloads = futures::future::join_all(download_handles);
    let download_errors = downloads.await
        .into_iter()
        .filter_map(|x| x.err())
        .collect::<Vec<Error>>();
    if download_errors.len() > 0 {
        Err(download_errors)
    } else {
        Ok(())
    }
}