use chrono::{DateTime, Utc};
use reqwest::blocking::Client;
use serde_json::json;
use std::error::Error as StdError;
use std::fmt;
use crate::env::EnvVar;
#[derive(Debug)]
pub enum AniRustError {
ReqwestError(reqwest::Error),
HyperError(hyper::Error),
RegexError(regex::Error),
NoProxiesAvailable,
FailedToFetchAfterRetries,
ParseIntError(std::num::ParseIntError),
NoDomainExists(String),
UnknownError(String),
}
impl fmt::Display for AniRustError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AniRustError::ReqwestError(err) => write!(f, "Reqwest error: {}", err),
AniRustError::HyperError(err) => write!(f, "Hyper error: {}", err),
AniRustError::RegexError(err) => write!(f, "Regex error: {}", err),
AniRustError::NoProxiesAvailable => write!(f, "No proxies available"),
AniRustError::FailedToFetchAfterRetries => write!(f, "Failed to fetch after retries"),
AniRustError::ParseIntError(err) => write!(f, "Failed to parse int error: {}", err),
AniRustError::NoDomainExists(site) => write!(f, "No domain added for: {}", site),
AniRustError::UnknownError(err) => write!(f, "Std error occured: {}", err),
}
}
}
impl From<reqwest::Error> for AniRustError {
fn from(err: reqwest::Error) -> Self {
AniRustError::ReqwestError(err)
}
}
impl From<hyper::Error> for AniRustError {
fn from(err: hyper::Error) -> Self {
AniRustError::HyperError(err)
}
}
impl From<regex::Error> for AniRustError {
fn from(err: regex::Error) -> Self {
AniRustError::RegexError(err)
}
}
impl From<Box<dyn StdError>> for AniRustError {
fn from(err: Box<dyn StdError>) -> Self {
AniRustError::UnknownError(err.to_string())
}
}
impl StdError for AniRustError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
AniRustError::ReqwestError(err) => Some(err),
AniRustError::HyperError(err) => Some(err),
AniRustError::RegexError(err) => Some(err),
AniRustError::NoProxiesAvailable => None,
AniRustError::FailedToFetchAfterRetries => None,
AniRustError::ParseIntError(err) => Some(err),
AniRustError::NoDomainExists(_) => None,
AniRustError::UnknownError(_) => None,
}
}
}
impl AniRustError {
pub fn webhook_url(&self) -> String {
match self {
AniRustError::ReqwestError(_) => EnvVar::REQWEST_ERROR_WEBHOOK.get_config(),
AniRustError::HyperError(_) => EnvVar::REQWEST_ERROR_WEBHOOK.get_config(),
AniRustError::NoProxiesAvailable => {
EnvVar::NO_PROXIES_AVAILABLE_ERROR_WEBHOOK.get_config()
}
AniRustError::FailedToFetchAfterRetries => {
EnvVar::FAILED_TO_FETCH_AFTER_RETRIES_ERROR_WEBHOOK.get_config()
}
AniRustError::ParseIntError(_) | AniRustError::RegexError(_) => {
EnvVar::UTILS_ERROR_WEBHOOK.get_config()
}
AniRustError::NoDomainExists(_) => String::new(),
AniRustError::UnknownError(_) => EnvVar::UNKNOWN_ERROR_WEBHOOK.get_config(),
}
}
}
impl Drop for AniRustError {
fn drop(&mut self) {
let webhook_url = self.webhook_url();
let error_message = format!("{}", self);
send_error_to_webhook(&webhook_url, &error_message);
}
}
fn send_error_to_webhook(webhook_url: &str, error_message: &str) {
if webhook_url.is_empty() {
return;
}
let webhook_url = webhook_url.to_string();
let error_message = error_message.to_string();
tokio::task::spawn_blocking(move || {
if webhook_url.is_empty() {
return;
}
let client = Client::new();
let now: DateTime<Utc> = Utc::now();
let timestamp = now.format("%Y-%m-%d %H:%M:%S").to_string();
let content = format!(
r#"{{"Timestamp": "{}", "Error": "{}"}}"#,
timestamp, error_message
);
let payload = json!({
"content": content,
});
let _res = client.post(&webhook_url).json(&payload).send();
});
}