use serde::Deserialize;
#[derive(Debug)]
pub enum Error {
ApiUnavailable(String),
MissingKey(String),
BadKey(String),
TooManyRequests(String),
TooManyDecks(String),
TooManyCardsInDeck(String),
TooManyCardsTotal(String),
BadDeck(String),
BadVid(String),
BadSid(String),
BadRid(String),
BadImage(String),
BadAudio(String),
BadRequest(String),
BadSentence(String),
BadTranslation(String),
DeserializeError(std::io::Error),
Transport(ureq::Transport),
Unhandled(u16, RawError),
}
#[derive(Debug, PartialEq, Eq)]
pub enum ErrorKind {
ApiUnavailable,
MissingKey,
BadKey,
BadRequest,
BadDeck,
BadVid,
BadSid,
BadRid,
BadImage,
BadAudio,
BadSentence,
BadTranslation,
TooManyRequests,
TooManyDecks,
TooManyCardsInDeck,
TooManyCardsTotal,
Transport,
DeserializeError,
Unhandled,
}
#[derive(Deserialize, Debug)]
pub struct RawError {
error_message: String,
error: String,
}
impl Error {
pub fn kind(&self) -> ErrorKind {
match *self {
Error::MissingKey(_) => ErrorKind::MissingKey,
Error::BadKey(_) => ErrorKind::BadKey,
Error::BadRequest(_) => ErrorKind::BadRequest,
Error::Transport(_) => ErrorKind::Transport,
Error::Unhandled(_, _) => ErrorKind::Unhandled,
Error::TooManyRequests(_) => ErrorKind::TooManyRequests,
Error::ApiUnavailable(_) => ErrorKind::ApiUnavailable,
Error::TooManyDecks(_) => ErrorKind::TooManyDecks,
Error::TooManyCardsInDeck(_) => ErrorKind::TooManyCardsInDeck,
Error::TooManyCardsTotal(_) => ErrorKind::TooManyCardsTotal,
Error::BadDeck(_) => ErrorKind::BadDeck,
Error::BadVid(_) => ErrorKind::BadVid,
Error::BadSid(_) => ErrorKind::BadSid,
Error::BadRid(_) => ErrorKind::BadRid,
Error::BadImage(_) => ErrorKind::BadImage,
Error::BadAudio(_) => ErrorKind::BadAudio,
Error::BadSentence(_) => ErrorKind::BadSentence,
Error::BadTranslation(_) => ErrorKind::BadTranslation,
Error::DeserializeError(_) => ErrorKind::DeserializeError,
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
Error::Transport(ref source) => Some(source),
Error::DeserializeError(ref source) => Some(source),
_ => None,
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
Error::MissingKey(ref s) => write!(f, "No API key was specified. {s}"),
Error::BadKey(ref s) => write!(f, "A bad API key was specified. {s}"),
Error::Transport(ref e) => e.fmt(f),
Error::BadRequest(ref s) => write!(f, "The request body did not match the schema. {s}"),
Error::Unhandled(code, ref s) => write!(f, "Unhandled error. Code: {code}. Raw: {s:?}"),
Error::TooManyRequests(ref s) => write!(f, "Too many requests. {s}"),
Error::ApiUnavailable(ref s) => write!(f, "API Unavailable. {s}"),
Error::TooManyDecks(ref s) => write!(f, "The user has too many decks. {s}"),
Error::TooManyCardsInDeck(ref s) => {
write!(f, "The user has too many cards in the given deck. {s}")
}
Error::TooManyCardsTotal(ref s) => {
write!(f, "The user has reached the total card limit. {s}")
}
Error::BadDeck(ref s) => write!(f, "A deck with the given id doesn't exist. {s}"),
Error::BadVid(ref s) => write!(f, "There is no vocabulary with the given id. {s}"),
Error::BadSid(ref s) => write!(f, "There is no spelling with the given id. {s}"),
Error::BadRid(ref s) => write!(f, "There is no reading with the given id. {s}"),
Error::BadImage(ref s) => write!(f, "Bad image. {s}"),
Error::BadAudio(ref s) => write!(f, "Bad audio. {s}"),
Error::BadSentence(ref s) => write!(
f,
"The sentence is too long, or the given vocabulary was not found in it. {s}"
),
Error::BadTranslation(ref s) => write!(f, "The translation is too long. {s}"),
Error::DeserializeError(ref s) => s.fmt(f),
}
}
}
impl From<ureq::Error> for Error {
fn from(r: ureq::Error) -> Self {
match r {
ureq::Error::Status(code, response) => {
let raw = response
.into_json::<RawError>()
.map_err(Error::DeserializeError);
if let Err(e) = raw {
return e;
}
let raw = raw.unwrap();
match code {
403 => {
if raw.error != "bad_key" {
Error::Unhandled(code, raw)
} else {
match raw.error_message.as_str() {
"missing API key" => Error::MissingKey(raw.error_message),
"invalid API key" => Error::BadKey(raw.error_message),
_ => Error::Unhandled(code, raw),
}
}
}
429 => {
if raw.error != "too_many_requests" {
Error::Unhandled(code, raw)
} else {
Error::TooManyRequests(raw.error_message)
}
}
400 => match raw.error.as_str() {
"bad_request" => Error::BadRequest(raw.error_message),
"bad_deck" => Error::BadDeck(raw.error_message),
"bad_sid" => Error::BadSid(raw.error_message),
"bad_vid" => Error::BadVid(raw.error_message),
_ => Error::Unhandled(code, raw),
},
_ => Error::Unhandled(code, raw),
}
}
ureq::Error::Transport(a) => Error::Transport(a),
}
}
}