1use actix_web::ResponseError;
5use chrono::{DateTime, Local};
6use std::convert::Into;
7use std::error::Error as StdError;
8use std::fmt;
9
10#[derive(Debug)]
11pub enum ErrorKind {
12 Msg(String),
13 Io(::std::io::Error),
14 Custom { code: i32, msg: String },
15}
16
17#[derive(Debug)]
19pub struct ChimesError {
20 pub kind: ErrorKind,
22 pub source: Option<Box<dyn StdError>>,
23}
24unsafe impl Sync for ChimesError {}
25unsafe impl Send for ChimesError {}
26
27impl StdError for ChimesError {
29 fn source(&self) -> Option<&(dyn StdError + 'static)> {
30 self.source.as_deref()
31 }
32}
33
34impl fmt::Display for ChimesError {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match self.kind {
38 ErrorKind::Msg(ref message) => write!(f, "{}", message),
39 ErrorKind::Custom { code, ref msg } => {
40 write!(f, "custom error code: {}, message: {}", code, msg)
41 }
42 ErrorKind::Io(ref e) => write!(f, "{}", e),
43 }
44 }
45}
46
47impl ChimesError {
48 pub fn msg(value: impl ToString) -> Self {
50 Self {
51 kind: ErrorKind::Msg(value.to_string()),
52 source: None,
53 }
54 }
55
56 pub fn chain(value: impl ToString, source: impl Into<Box<dyn StdError>>) -> Self {
58 Self {
59 kind: ErrorKind::Msg(value.to_string()),
60 source: Some(source.into()),
61 }
62 }
63
64 pub fn custom(code: i32, msg: impl ToString) -> Self {
66 Self {
67 kind: ErrorKind::Custom {
68 code,
69 msg: msg.to_string(),
70 },
71 source: None,
72 }
73 }
74
75 pub fn custom_err(code: i32, msg: impl ToString, source: impl Into<Box<dyn StdError>>) -> Self {
77 Self {
78 kind: ErrorKind::Custom {
79 code,
80 msg: msg.to_string(),
81 },
82 source: Some(source.into()),
83 }
84 }
85
86 pub fn write_to_file(content: String) {
89 use std::fs::OpenOptions;
90 use std::io::prelude::*;
91 let mut name = String::from("logs");
92 if let Ok(p) = std::env::current_exe() {
94 let s = p.file_name().unwrap().to_str().unwrap();
95 name = String::from(s);
96 }
97
98 let mut file_path = format!("log/{}.log", name);
99 let mut dir_path_str = "log/".to_owned();
100 if !cfg!(debug_assertions) {
102 if !file_path.starts_with('/') {
104 if let Ok(p) = std::env::current_exe() {
105 let workdir = format!("{}", p.parent().unwrap().display());
106 file_path = format!("{}/{}", &workdir, file_path.replace("./", ""));
107 dir_path_str = format!("{}/{}", &workdir, dir_path_str.replace("./", ""));
108 }
109 }
110 }
111
112 let dir_path = std::path::Path::new(&dir_path_str);
113 if !dir_path.exists() {
114 let _ = std::fs::create_dir_all(dir_path);
115 }
116 let file = OpenOptions::new()
119 .read(true)
120 .write(true)
121 .create(true)
122 .append(true)
123 .open(file_path);
124
125 let local: DateTime<Local> = Local::now();
126 let now_str = local.format("%Y-%m-%d %H:%M:%S").to_string();
127
128 match file {
130 Ok(mut stream) => {
131 stream
132 .write_all(format!("[{}] {}\n", now_str, content).as_bytes())
133 .unwrap();
134 }
135 Err(err) => {
136 println!("{:?}", err);
137 }
138 }
139 }
140}
141
142impl ResponseError for ChimesError {}
143
144impl From<ChimesError> for rbatis::Error {
145 fn from(val: ChimesError) -> Self {
146 rbatis::Error::E(val.to_string())
147 }
148}
149
150impl From<rbatis::Error> for ChimesError {
151 fn from(value: rbatis::Error) -> Self {
152 match value {
153 rbatis::Error::E(desc) => Self::msg(desc),
154 rbatis::Error::Deserialize(desc) => Self::msg(desc),
155 rbatis::Error::Database(desc) => Self::msg(desc),
156 _ => Self::msg("Unknown Error".to_string()),
157 }
158 }
159}
160
161#[macro_export]
205macro_rules! error {
206 (code: $code: expr, msg: $msg: expr) => {{
208 ChimesError::custom($code, $msg)
209 }};
210 (code: $code: expr, msg: $msg: expr,) => {{
212 ChimesError::custom($code, $msg)
213 }};
214
215 ($($arg:tt)*) => {{
217 let content = format!($($arg)*);
218 ChimesError::msg(content)
221 }};
222}