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