soar_dl/
error.rs

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
use std::{error::Error, fmt::Display, io};

#[derive(Debug)]
pub enum DownloadError {
    InvalidUrl {
        url: String,
        source: url::ParseError,
    },
    IoError(io::Error),
    NetworkError {
        source: reqwest::Error,
    },
    ResourceError {
        url: String,
        status: reqwest::StatusCode,
    },
    InvalidResponse,
    LayersNotFound,
}

impl Display for DownloadError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            DownloadError::IoError(err) => write!(f, "IO error: {}", err),
            DownloadError::InvalidUrl { url, .. } => write!(f, "Invalid URL: {}", url),
            DownloadError::NetworkError { .. } => write!(f, "Network Request failed"),
            DownloadError::ResourceError { url, status } => {
                write!(f, "Failed to fetch resource from {} [{}]", url, status)
            }
            DownloadError::LayersNotFound => write!(f, "No downloadable layers found"),
            DownloadError::InvalidResponse => write!(f, "Failed to parse response"),
        }
    }
}

impl Error for DownloadError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            DownloadError::IoError(err) => Some(err),
            DownloadError::InvalidUrl { source, .. } => Some(source),
            DownloadError::NetworkError { source } => Some(source),
            DownloadError::ResourceError { .. } => None,
            DownloadError::LayersNotFound => None,
            DownloadError::InvalidResponse => None,
        }
    }
}

impl From<io::Error> for DownloadError {
    fn from(value: io::Error) -> Self {
        Self::IoError(value)
    }
}

#[derive(Debug)]
pub enum PlatformError {
    ApiError { status: reqwest::StatusCode },
    DownloadError(DownloadError),
    InvalidInput(String),
    InvalidResponse,
    NoMatchingAssets { available_assets: Vec<String> },
    NoRelease { tag: Option<String> },
    RepositoryNotFound { owner: String, repo: String },
}

impl Display for PlatformError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            PlatformError::ApiError { status } => write!(f, "API error [{}]", status),
            PlatformError::DownloadError(err) => write!(f, "Download error: {}", err),
            PlatformError::InvalidInput(msg) => {
                write!(f, "{} is invalid. Should be in format (owner/repo)", msg)
            }
            PlatformError::InvalidResponse => write!(f, "Failed to parse response"),
            PlatformError::NoRelease { tag } => write!(
                f,
                "No {} found.",
                tag.clone()
                    .map(|t| format!("tag {}", t))
                    .unwrap_or("release".to_string())
            ),
            PlatformError::NoMatchingAssets { .. } => write!(f, "No matching assets found"),
            PlatformError::RepositoryNotFound { owner, repo } => {
                write!(f, "Repository not found: {}/{}", owner, repo)
            }
        }
    }
}

impl From<DownloadError> for PlatformError {
    fn from(value: DownloadError) -> Self {
        Self::DownloadError(value)
    }
}