use actix_web::ResponseError;
use chrono::{DateTime, Local};
use std::convert::Into;
use std::error::Error as StdError;
use std::fmt;
#[derive(Debug)]
pub enum ErrorKind {
Msg(String),
Io(::std::io::Error),
Custom { code: i32, msg: String },
}
#[derive(Debug)]
pub struct ChimesError {
pub kind: ErrorKind,
pub source: Option<Box<dyn StdError>>,
}
unsafe impl Sync for ChimesError {}
unsafe impl Send for ChimesError {}
impl StdError for ChimesError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.source.as_deref()
}
}
impl fmt::Display for ChimesError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.kind {
ErrorKind::Msg(ref message) => write!(f, "{}", message),
ErrorKind::Custom { code, ref msg } => {
write!(f, "custom error code: {}, message: {}", code, msg)
}
ErrorKind::Io(ref e) => write!(f, "{}", e),
}
}
}
impl ChimesError {
pub fn msg(value: impl ToString) -> Self {
Self {
kind: ErrorKind::Msg(value.to_string()),
source: None,
}
}
pub fn chain(value: impl ToString, source: impl Into<Box<dyn StdError>>) -> Self {
Self {
kind: ErrorKind::Msg(value.to_string()),
source: Some(source.into()),
}
}
pub fn custom(code: i32, msg: impl ToString) -> Self {
Self {
kind: ErrorKind::Custom {
code,
msg: msg.to_string(),
},
source: None,
}
}
pub fn custom_err(code: i32, msg: impl ToString, source: impl Into<Box<dyn StdError>>) -> Self {
Self {
kind: ErrorKind::Custom {
code,
msg: msg.to_string(),
},
source: Some(source.into()),
}
}
pub fn write_to_file(content: String) {
use std::fs::OpenOptions;
use std::io::prelude::*;
let mut name = String::from("logs");
if let Ok(p) = std::env::current_exe() {
let s = p.file_name().unwrap().to_str().unwrap();
name = String::from(s);
}
let mut file_path = format!("log/{}.log", name);
let mut dir_path_str = "log/".to_owned();
if !cfg!(debug_assertions) {
if !file_path.starts_with('/') {
if let Ok(p) = std::env::current_exe() {
let workdir = format!("{}", p.parent().unwrap().display());
file_path = format!("{}/{}", &workdir, file_path.replace("./", ""));
dir_path_str = format!("{}/{}", &workdir, dir_path_str.replace("./", ""));
}
}
}
let dir_path = std::path::Path::new(&dir_path_str);
if !dir_path.exists() {
let _ = std::fs::create_dir_all(dir_path);
}
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.append(true)
.open(file_path);
let local: DateTime<Local> = Local::now();
let now_str = local.format("%Y-%m-%d %H:%M:%S").to_string();
match file {
Ok(mut stream) => {
stream
.write_all(format!("[{}] {}\n", now_str, content).as_bytes())
.unwrap();
}
Err(err) => {
println!("{:?}", err);
}
}
}
}
impl ResponseError for ChimesError {}
impl From<ChimesError> for rbatis::Error {
fn from(val: ChimesError) -> Self {
rbatis::Error::E(val.to_string())
}
}
impl From<rbatis::Error> for ChimesError {
fn from(value: rbatis::Error) -> Self {
match value {
rbatis::Error::E(desc) => Self::msg(desc),
rbatis::Error::Deserialize(desc) => Self::msg(desc),
rbatis::Error::Database(desc) => Self::msg(desc),
_ => Self::msg("Unknown Error".to_string()),
}
}
}
#[macro_export]
macro_rules! error {
(code: $code: expr, msg: $msg: expr) => {{
ChimesError::custom($code, $msg)
}};
(code: $code: expr, msg: $msg: expr,) => {{
ChimesError::custom($code, $msg)
}};
($($arg:tt)*) => {{
let content = format!($($arg)*);
ChimesError::msg(content)
}};
}