use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use thiserror::Error as ThisError;
const ANSI_ESC_CODE_COLOR_RED: &str = "\x1b[31m";
const ANSI_ESC_CODE_COLOR_RESET: &str = "\x1b[0m";
const DEFAULT_ERROR_MESSAGE: &str = "Something went wrong";
#[derive(Debug, Serialize, Deserialize, ThisError)]
#[error(
"{ANSI_ESC_CODE_COLOR_RED}{{\n \"provider_parser\": \"{}\",\n \"message\": \"{}\",\n \"status\": {}\n}}{ANSI_ESC_CODE_COLOR_RESET}",
provider_parser,
message,
status
)]
pub struct ErrorDetails {
pub provider_parser: &'static str,
pub message: String,
pub status: u16,
}
impl ErrorDetails {
fn new(
provider_parser: &'static str,
err_msg: Option<String>,
status: Option<StatusCode>,
) -> Self {
const DEFAULT_ERROR_STATUS: u16 = StatusCode::INTERNAL_SERVER_ERROR.as_u16();
let (status, message) = match (status, err_msg) {
(Some(s), Some(msg)) => (s.as_u16(), msg),
(Some(s), None) => (s.as_u16(), DEFAULT_ERROR_MESSAGE.to_string()),
(None, Some(msg)) => (DEFAULT_ERROR_STATUS, msg),
(None, None) => (DEFAULT_ERROR_STATUS, DEFAULT_ERROR_MESSAGE.to_string()),
};
let err = ErrorDetails {
provider_parser,
message,
status,
};
eprintln!("{err}");
return err;
}
}
pub type EnmaResult<T> = std::result::Result<T, EnmaError>;
#[derive(Debug, ThisError)]
pub enum EnmaError {
#[error("{ANSI_ESC_CODE_COLOR_RED}<{}>: {} {}{ANSI_ESC_CODE_COLOR_RESET}", details.provider_parser, details.status, details.message)]
SrcFetchError { details: ErrorDetails },
#[error("{ANSI_ESC_CODE_COLOR_RED}<{}>: {} {}{ANSI_ESC_CODE_COLOR_RESET}", details.provider_parser, details.status, details.message)]
SrcParseError { details: ErrorDetails },
#[error("{ANSI_ESC_CODE_COLOR_RED}<{}>: {} {}{ANSI_ESC_CODE_COLOR_RESET}", details.provider_parser, details.status, details.message)]
ParsingError { details: ErrorDetails },
#[error("{ANSI_ESC_CODE_COLOR_RED}<{}>: {} {}{ANSI_ESC_CODE_COLOR_RESET}", details.provider_parser, details.status, details.message)]
InvalidDataError { details: ErrorDetails },
#[error("{ANSI_ESC_CODE_COLOR_RED}<{}>: {} {}{ANSI_ESC_CODE_COLOR_RESET}", details.provider_parser, details.status, details.message)]
MiscError { details: ErrorDetails },
}
impl EnmaError {
pub fn details(&self) -> &ErrorDetails {
match self {
EnmaError::MiscError { details } => details,
EnmaError::ParsingError { details } => details,
EnmaError::SrcFetchError { details } => details,
EnmaError::SrcParseError { details } => details,
EnmaError::InvalidDataError { details } => details,
}
}
pub fn src_fetch_error(
provider_parser: &'static str,
err_msg: Option<String>,
status: Option<StatusCode>,
) -> Self {
const ERROR_PREFIX: &'static str = "SrcFetchError: ";
let err_msg =
Self::get_formatted_err(err_msg, ERROR_PREFIX, "Failed to fetch raw source data");
return Self::SrcFetchError {
details: ErrorDetails::new(provider_parser, err_msg, status),
};
}
pub fn src_parse_error(
provider_parser: &'static str,
err_msg: Option<String>,
status: Option<StatusCode>,
) -> Self {
const ERROR_PREFIX: &'static str = "SrcParseError: ";
let err_msg = Self::get_formatted_err(
err_msg,
ERROR_PREFIX,
"Failed to parse fetched raw source data",
);
return Self::SrcParseError {
details: ErrorDetails::new(provider_parser, err_msg, status),
};
}
pub fn parsing_error(
provider_parser: &'static str,
err_msg: Option<String>,
status: Option<StatusCode>,
) -> Self {
const ERROR_PREFIX: &'static str = "ParsingError: ";
let err_msg = Self::get_formatted_err(err_msg, ERROR_PREFIX, DEFAULT_ERROR_MESSAGE);
return Self::ParsingError {
details: ErrorDetails::new(provider_parser, err_msg, status),
};
}
pub fn invalid_data_error(
provider_parser: &'static str,
err_msg: Option<String>,
status: Option<StatusCode>,
) -> Self {
const ERROR_PREFIX: &'static str = "InvalidDataError: ";
let err_msg = Self::get_formatted_err(err_msg, ERROR_PREFIX, DEFAULT_ERROR_MESSAGE);
return Self::MiscError {
details: ErrorDetails::new(provider_parser, err_msg, status),
};
}
pub fn misc_error(
provider_parser: &'static str,
err_msg: Option<String>,
status: Option<StatusCode>,
) -> Self {
const ERROR_PREFIX: &'static str = "MiscError: ";
let err_msg = Self::get_formatted_err(err_msg, ERROR_PREFIX, DEFAULT_ERROR_MESSAGE);
return Self::MiscError {
details: ErrorDetails::new(provider_parser, err_msg, status),
};
}
fn get_formatted_err(
err_message: Option<String>,
err_prefix: &'static str,
default_err_message: &'static str,
) -> Option<String> {
let formatted_msg = match err_message {
Some(msg) => {
if msg.starts_with(err_prefix) {
msg
} else {
format!("{err_prefix}{msg}")
}
}
None => format!("{err_prefix}{default_err_message}"),
};
Some(formatted_msg)
}
}