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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright (C) 2020 Tobias Hunger <tobias.hunger@gmail.com>

//! This crate provides a simple way to download files via HTTP/HTTPS.
//!
//! It tries to make it very simple to just specify a couple of
//! URLs and then go and download all of the files.
//!
//! It supports system proxy configuration, parallel downloads of different files,
//! validation of downloads via a callback, as well as files being mirrored on
//! different machines.
//!
//! Callbacks to provide progress information are supported as well.

// Setup warnings/errors:
#![forbid(unsafe_code)]
#![deny(
    bare_trait_objects,
    unused_doc_comments,
    unused_import_braces,
    missing_docs
)]
// Clippy:
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
#![allow(clippy::non_ascii_literal)]

pub mod backend;
pub mod download;
pub mod downloader;
pub mod progress;
pub mod verify;

pub use crate::download::Download;
pub use crate::downloader::Downloader;
pub use crate::progress::Progress;
pub use crate::verify::{SimpleProgress, Verification, Verify};

// ----------------------------------------------------------------------
// - Error:
// ----------------------------------------------------------------------

/// Possible `Error`s that can occurred during normal operation.
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// The Setup is incomplete or bogus.
    #[error("Setup error: {0}")]
    Setup(String),
    /// A Definition of a `Download` is incomplete
    #[error("Download definition: {0}")]
    DownloadDefinition(String),
    /// Writing into a file failed during download.
    #[error("File creation failed: {0}")]
    File(DownloadSummary),
    /// A download failed
    #[error("Download failed for {0}")]
    Download(DownloadSummary),
    /// Download file verification failed.
    #[error("Verification failed for {0}")]
    Verification(DownloadSummary),
}

/// `Result` type for the `gng_shared` library
pub type Result<T> = std::result::Result<T, Error>;

// ----------------------------------------------------------------------
// - DownloadSummary:
// ----------------------------------------------------------------------

/// The result of a `Download`
pub struct DownloadSummary {
    /// A list of attempted downloads with URL and status code.
    pub status: Vec<(String, u16)>,
    /// The path this URL has been downloaded to.
    pub file_name: std::path::PathBuf,
    /// File verification status
    pub verified: Verification,
}

fn to_fmt(f: &mut std::fmt::Formatter<'_>, summary: &DownloadSummary) -> std::fmt::Result {
    writeln!(
        f,
        "{}: (verification: {}):",
        summary.file_name.to_string_lossy(),
        match summary.verified {
            Verification::NotVerified => "unverified",
            Verification::Failed => "FAILED",
            Verification::Ok => "Ok",
        },
    )?;
    for i in 0..summary.status.len() {
        writeln!(
            f,
            "  {}: {} with status {}",
            i + 1,
            summary.status[i].0,
            summary.status[i].1
        )?;
    }
    Ok(())
}

impl std::fmt::Display for DownloadSummary {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        to_fmt(f, self)
    }
}

impl std::fmt::Debug for DownloadSummary {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        to_fmt(f, self)
    }
}