soar_dl/
error.rs

1use std::{error::Error, fmt::Display, io};
2
3#[derive(Debug)]
4pub enum DownloadError {
5    InvalidUrl {
6        url: String,
7        source: url::ParseError,
8    },
9    IoError(io::Error),
10    NetworkError {
11        source: reqwest::Error,
12    },
13    ResourceError {
14        url: String,
15        status: reqwest::StatusCode,
16    },
17    InvalidResponse,
18    LayersNotFound,
19    ChunkError,
20    FileNameNotFound,
21    ZipError(zip::result::ZipError),
22}
23
24impl Display for DownloadError {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            DownloadError::IoError(err) => write!(f, "IO error: {}", err),
28            DownloadError::InvalidUrl { url, .. } => write!(f, "Invalid URL: {}", url),
29            DownloadError::NetworkError { .. } => write!(f, "Network Request failed"),
30            DownloadError::ResourceError { url, status } => {
31                write!(f, "Failed to fetch resource from {} [{}]", url, status)
32            }
33            DownloadError::LayersNotFound => write!(f, "No downloadable layers found"),
34            DownloadError::InvalidResponse => write!(f, "Failed to parse response"),
35            DownloadError::ChunkError => write!(f, "Failed to read chunk"),
36            DownloadError::FileNameNotFound => {
37                write!(
38                    f,
39                    "Couldn't find filename. Please provide filename explicitly."
40                )
41            }
42            DownloadError::ZipError(err) => write!(f, "Zip error: {}", err),
43        }
44    }
45}
46
47impl Error for DownloadError {
48    fn source(&self) -> Option<&(dyn Error + 'static)> {
49        match self {
50            DownloadError::IoError(err) => Some(err),
51            DownloadError::InvalidUrl { source, .. } => Some(source),
52            DownloadError::NetworkError { source } => Some(source),
53            _ => None,
54        }
55    }
56}
57
58impl From<io::Error> for DownloadError {
59    fn from(value: io::Error) -> Self {
60        Self::IoError(value)
61    }
62}
63
64#[derive(Debug)]
65pub enum PlatformError {
66    ApiError { status: reqwest::StatusCode },
67    DownloadError(DownloadError),
68    InvalidInput(String),
69    InvalidResponse,
70    NoMatchingAssets { available_assets: Vec<String> },
71    NoRelease { tag: Option<String> },
72    RepositoryNotFound { owner: String, repo: String },
73}
74
75impl Display for PlatformError {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            PlatformError::ApiError { status } => write!(f, "API error [{}]", status),
79            PlatformError::DownloadError(err) => write!(f, "Download error: {}", err),
80            PlatformError::InvalidInput(msg) => {
81                write!(f, "{} is invalid. Should be in format (owner/repo)", msg)
82            }
83            PlatformError::InvalidResponse => write!(f, "Failed to parse response"),
84            PlatformError::NoRelease { tag } => write!(
85                f,
86                "No {} found.",
87                tag.clone()
88                    .map(|t| format!("tag {}", t))
89                    .unwrap_or("release".to_string())
90            ),
91            PlatformError::NoMatchingAssets { .. } => write!(f, "No matching assets found"),
92            PlatformError::RepositoryNotFound { owner, repo } => {
93                write!(f, "Repository not found: {}/{}", owner, repo)
94            }
95        }
96    }
97}
98
99impl From<DownloadError> for PlatformError {
100    fn from(value: DownloadError) -> Self {
101        Self::DownloadError(value)
102    }
103}