1use std::{
2 sync::{Arc, RwLock},
3 thread,
4 time::Duration,
5};
6
7use chrono::Utc;
8use isahc::{config::Configurable, Request, RequestExt};
9
10use log::{set_logger, Metadata, Record};
11
12use crate::{VioletLog, VioletLogSeverity};
13pub type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>;
14pub type GResult<T> = Result<T, GenericError>;
15
16lazy_static::lazy_static! {
17 static ref CLIENT: HttpVioletData = HttpVioletData::new();
18}
19
20#[derive(Clone)]
21#[non_exhaustive]
22pub struct HttpVioletData {
23 config: Arc<RwLock<Option<VioletBuilder>>>,
24}
25
26#[derive(Debug, Clone)]
27pub struct VioletBuilder {
28 indentifier: u64,
29 token: String,
30 send_err_async: bool,
31 default_title: String,
32 send_level: VioletLogSeverity,
33}
34
35impl VioletBuilder {
36 pub fn new(token: impl AsRef<str>, indentifier: u64) -> Self {
37 Self {
38 token: token.as_ref().to_string(),
39 indentifier,
40 default_title: env!("CARGO_PKG_NAME").into(),
41 send_err_async: false,
42 send_level: VioletLogSeverity::Error,
43 }
44 }
45
46 pub fn enable_async(mut self) -> Self {
47 self.send_err_async = true;
48 self
49 }
50
51 pub fn set_title(mut self, title: impl AsRef<str>) -> Self {
52 self.default_title = title.as_ref().to_string();
53 self
54 }
55
56 pub fn set_send_min_level(mut self, level: VioletLogSeverity) -> Self {
57 self.send_level = level;
58 self
59 }
60
61 pub fn init(self) -> GResult<()> {
62 if CLIENT
63 .config
64 .read()
65 .map_err(|err| format!("Poisoded mutex here: {:?}", &err))?
66 .is_some()
67 {
68 return Ok(());
69 }
70
71 CLIENT.set_config(self)?;
72 set_logger(&*CLIENT).unwrap();
73
74 Ok(())
75 }
76}
77
78impl HttpVioletData {
79 fn new() -> Self {
80 Self {
81 config: Arc::new(RwLock::new(None)),
82 }
83 }
84
85 pub fn get_http() -> &'static Self {
86 &CLIENT
87 }
88
89 fn set_config(&self, config: VioletBuilder) -> GResult<()> {
90 *self
91 .config
92 .write()
93 .map_err(|err| format!("Mutex is poisoned: {:?}", err))? = Some(config);
94 Ok(())
95 }
96
97 pub async fn send_data(
98 &self,
99 title: String,
100 severity: VioletLogSeverity,
101 message: String,
102 ) -> GResult<()> {
103 let log_vio = VioletLog::new(severity, title, message);
104 let log_vio_json = serde_json::to_string(&log_vio)?;
105 let config = self
106 .config
107 .clone()
108 .read()
109 .map_err(|err| format!("Poisoned mutex: {:?}", err))?
110 .as_ref()
111 .ok_or("Violet não foi inicializada")?
112 .clone();
113 println!("{:?}", &log_vio_json);
114 Request::post(format!(
115 "https://violet.zuraaa.com/api/apps/{}/events",
116 config.indentifier
117 ))
118 .header("Content-Type", "application/json")
119 .header("Authorization", config.token)
120 .timeout(Duration::from_secs(20))
121 .body(log_vio_json)?
122 .send_async()
123 .await?;
124 Ok(())
125 }
126}
127
128impl log::Log for HttpVioletData {
129 fn enabled(&self, _metadata: &Metadata) -> bool {
130 true
131 }
132
133 fn flush(&self) {
134 todo!()
135 }
136
137 fn log(&self, record: &Record) {
138 if self.config.read().unwrap().is_none() {
139 panic!("Violet não foi inicializado");
140 }
141
142 let config = self
143 .config
144 .read()
145 .as_ref()
146 .unwrap()
147 .as_ref()
148 .unwrap()
149 .clone();
150
151 let pointer_data = (record.level(), record.args().to_string());
152
153 {
154 let level = crate::convert_level_to_string(&pointer_data.0);
155 let data = Utc::now();
156 let data_formated = data.format("%d/%m/%Y %H:%M:%S").to_string();
157 println!("[({}) ({})]: {}", data_formated, level, &pointer_data.1)
158 }
159
160 {
161 let level_u8 = u8::from(config.send_level.clone());
162 let level_event_u8 = crate::convert_level_to_u8(&pointer_data.0);
163 if level_event_u8 > level_u8 {
164 return;
165 }
166 }
167
168 if config.send_err_async {
169 let cloned_self = self.clone();
170 thread::spawn(move || {
171 futures::executor::block_on(async {
172 cloned_self
173 .send_data(config.default_title, pointer_data.0.into(), pointer_data.1)
174 .await
175 .ok();
176 });
177 });
178 } else {
179 futures::executor::block_on(async {
180 self.send_data(config.default_title, pointer_data.0.into(), pointer_data.1)
181 .await
182 .ok();
183 })
184 }
185 }
186}