use std::error::Error;
use hf_hub::HFError;
use crate::error::CanddingError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum Step {
Listing,
File,
}
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum Kind {
Gated,
Repository,
Revision,
Other,
}
pub(crate) fn kind(step: Step, status: Option<u16>, code: Option<&str>) -> Kind {
match (code, status, step) {
(Some("RevisionNotFound"), ..) => Kind::Revision,
(Some("RepoNotFound"), ..) => Kind::Repository,
(Some("GatedRepo"), ..) => Kind::Gated,
(_, Some(401 | 404), Step::Listing) => Kind::Repository,
(_, Some(401 | 403), _) => Kind::Gated,
_ => Kind::Other,
}
}
pub(crate) fn map(step: Step, error: HFError, id: &str, revision: &str) -> CanddingError {
let id = id.to_string();
let revision = revision.to_string();
let (status, code) = response(&error);
match error {
HFError::Io(error) => CanddingError::Io(error),
HFError::Request { source, .. } => CanddingError::Network {
id,
reason: chain(&source),
},
HFError::RepoNotFound { context: None, .. } => CanddingError::RepositoryNotFound { id },
HFError::RevisionNotFound { context: None, .. } => {
CanddingError::RevisionNotFound { id, revision }
}
error => match kind(step, status, code.as_deref()) {
Kind::Gated => CanddingError::GatedModel { id },
Kind::Repository => CanddingError::RepositoryNotFound { id },
Kind::Revision => CanddingError::RevisionNotFound { id, revision },
Kind::Other => CanddingError::DownloadFailed {
id,
reason: error.to_string(),
},
},
}
}
fn response(error: &HFError) -> (Option<u16>, Option<String>) {
let context = match error {
HFError::Http { context }
| HFError::AuthRequired { context }
| HFError::Forbidden { context }
| HFError::Conflict { context }
| HFError::RateLimited { context, .. } => Some(context.as_ref()),
HFError::RepoNotFound { context, .. }
| HFError::RevisionNotFound { context, .. }
| HFError::EntryNotFound { context, .. } => context.as_deref(),
_ => None,
};
(
context.map(|context| context.status.as_u16()),
context.and_then(|context| context.error_code.clone()),
)
}
fn chain(error: &dyn Error) -> String {
let mut text = error.to_string();
let mut source = error.source();
while let Some(cause) = source {
text.push_str(": ");
text.push_str(&cause.to_string());
source = cause.source();
}
text
}