1use chrono::{DateTime, Local};
2use log::LevelFilter;
3use rbatis::DriverType;
4use std::collections::HashMap;
5use std::fmt::Debug;
6use std::fs::File;
7use std::io::Read;
8use std::mem::MaybeUninit;
9use std::str::FromStr;
10use std::sync::{Mutex, Once};
11use std::time::SystemTime;
12use std::time::UNIX_EPOCH;
13use openssl::sha::Sha256;
15use rbatis::log::LogPlugin;
16use rbatis::rbatis::Rbatis;
17use serde_derive::{Deserialize, Serialize};
18
19mod rbatis_dynamical;
20pub use rbatis_dynamical::*;
21
22mod redis_client;
23pub use redis_client::*;
24mod r2d2_pool;
25
26mod actix_client;
27pub use actix_client::*;
28
29mod script_engine;
30pub use script_engine::*;
31
32mod gpt_sdk;
33pub use gpt_sdk::*;
34
35mod common_search;
36pub use common_search::*;
37
38#[cfg(windows)]
39mod windows_service_utils;
40
41#[cfg(windows)]
42mod windows_performance;
43
44use serde_json::Value;
45#[cfg(windows)]
46pub use windows_service_utils::*;
47
48#[cfg(not(target_os = "windows"))]
49mod linux_performance;
50
51mod performance;
52pub use performance::*;
53
54#[allow(dead_code)]
55pub fn get_local_timestamp() -> u64 {
56 let now = SystemTime::now();
57 let date: DateTime<Local> = now.into();
58 date.timestamp_millis() as u64
59}
60
61#[allow(dead_code)]
62pub fn get_multiple_rbatis(url: &str) -> &'static Rbatis {
63 static mut STATIC_MULTI_RB: MaybeUninit<HashMap<String, Rbatis>> = MaybeUninit::uninit();
65 static ONCE_HASH: Once = Once::new();
67
68 ONCE_HASH.call_once(|| unsafe {
69 STATIC_MULTI_RB.as_mut_ptr().write(HashMap::new());
70 });
71
72 unsafe {
73 if (*STATIC_MULTI_RB.as_mut_ptr()).contains_key(url) {
74 let hashmap = &*STATIC_MULTI_RB.as_mut_ptr();
75 &hashmap[url]
76 } else {
77 async_std::task::block_on(async {
78 log::info!("Call the block on to create the sql connection.");
79 let mut rb = Rbatis::new();
80 match rb.link(url).await {
81 Ok(_) => {
82 log::info!(
83 "Database {} was connected. Rbatis was initialized successfully.",
84 url
85 );
86 }
87 Err(err) => {
88 log::warn!("Error: {}", err);
89 }
90 };
91 rb.add_sql_intercept(MultipleDatabaseIntercepter());
92 (*STATIC_MULTI_RB.as_mut_ptr()).insert(url.to_string(), rb);
93 });
94 let hashmap = &*STATIC_MULTI_RB.as_mut_ptr();
95 &hashmap[url]
96 }
97 }
98}
99
100#[allow(dead_code)]
101pub async fn get_multiple_rbatis_async(url: &str) -> &'static Rbatis {
102 static mut STATIC_MULTI_RB: MaybeUninit<HashMap<String, Rbatis>> = MaybeUninit::uninit();
104 static ONCE_HASH: Once = Once::new();
106
107 ONCE_HASH.call_once(|| unsafe {
108 STATIC_MULTI_RB.as_mut_ptr().write(HashMap::new());
109 });
110
111 unsafe {
112 if (*STATIC_MULTI_RB.as_mut_ptr()).contains_key(url) {
113 let hashmap = &*STATIC_MULTI_RB.as_mut_ptr();
114 &hashmap[url]
115 } else {
116 log::info!("Call the block on to create the sql connection.");
117 let mut rb = Rbatis::new();
118 match rb.link(url).await {
119 Ok(_) => {
120 log::info!(
121 "Database {} was connected. Rbatis was initialized successfully.",
122 url
123 );
124 }
125 Err(err) => {
126 log::warn!("Error: {}", err);
127 }
128 };
129 rb.add_sql_intercept(MultipleDatabaseIntercepter());
130 (*STATIC_MULTI_RB.as_mut_ptr()).insert(url.to_string(), rb);
131 let hashmap = &*STATIC_MULTI_RB.as_mut_ptr();
132 &hashmap[url]
133 }
134 }
135}
136
137#[allow(dead_code)]
138pub fn get_rbatis() -> &'static Rbatis {
139 static mut STATIC_RB: MaybeUninit<Rbatis> = MaybeUninit::uninit();
141 static ONCE: Once = Once::new();
143
144 ONCE.call_once(|| unsafe {
145 let conf = AppConfig::get().lock().unwrap().to_owned();
147 let url = conf.db_conf.url.clone();
148
149 async_std::task::block_on(async {
150 let mut rb = Rbatis::new();
151 match rb.link(&url).await {
152 Ok(_) => {
153 log::info!("Database was connected. Rbatis was initialized successfully.");
154 }
155 Err(err) => {
156 log::warn!("Error: {}", err);
157 }
158 };
159 let rb_log = rbatis::log::RbatisLogPlugin::default();
160 rb_log.set_level_filter(conf.db_conf.logger_level);
161 rb.set_log_plugin(rb_log);
162 rb.add_sql_intercept(MultipleDatabaseIntercepter());
163 STATIC_RB.as_mut_ptr().write(rb);
164 });
165 });
166 unsafe { &*STATIC_RB.as_ptr() }
167}
168
169#[derive(Debug, Clone)]
170pub struct MultipleDatabaseIntercepter();
171
172impl rbatis::intercept::SqlIntercept for MultipleDatabaseIntercepter {
173 fn do_intercept(
174 &self,
175 rb: &Rbatis,
176 sql: &mut String,
177 _args: &mut Vec<rbson::Bson>,
178 _is_prepared_sql: bool,
179 ) -> Result<(), rbatis::core::Error> {
180 log::debug!("Origal: {}", sql.clone());
181 let m_sql = rbatis_compatible_sql(rb, sql.as_str());
182 log::debug!("Modify: {}", m_sql.clone());
183 *sql = m_sql;
184 Ok(())
185 }
186}
187
188pub fn rbatis_compatible_sql(rb: &Rbatis, sql: &str) -> String {
194 match rb.driver_type() {
195 Ok(driver_type) => match driver_type {
196 DriverType::Postgres => {
197 let mut sql_out = String::new();
198 let mut spl = sql.split('?');
199 let mut i = 1;
200 let count = spl.clone().count();
201 loop {
202 let t = spl.next();
203 if t.is_some() {
204 sql_out.push_str(t.unwrap());
205 if i < count {
206 sql_out.push_str(format!("${}", i).as_str());
207 }
208 } else {
209 break;
210 }
211 i += 1;
212 }
213 sql_out
214 }
215 _ => sql.to_owned(),
216 },
217 Err(_) => sql.to_owned(),
218 }
219}
220
221#[derive(Debug, Clone)]
222pub struct AppConfig {
223 pub db_conf: DatabaseConfig,
224 pub webserver_conf: WebServerConfig,
225 pub email_conf: EmailServerConfig,
226 pub redis_conf: Option<RedisConfig>,
227 pub gateway_address: Option<String>,
228 pub app_id: Option<String>,
229 pub app_secret: Option<String>,
230 pub logger_level: LevelFilter,
231}
232
233impl Default for AppConfig {
234 fn default() -> Self {
235 Self {
236 db_conf: Default::default(),
237 webserver_conf: Default::default(),
238 email_conf: Default::default(),
239 redis_conf: Default::default(),
240 gateway_address: Default::default(),
241 app_id: Default::default(),
242 app_secret: Default::default(),
243 logger_level: LevelFilter::Info,
244 }
245 }
246}
247
248#[derive(Debug, Clone, Default)]
249pub struct RedisPoolConfig {
250 pub connection_timeout: u64,
251 pub max_size: u32,
252 pub mini_idel: u32,
253}
254
255#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Clone)]
256#[serde(rename_all = "lowercase")]
257pub enum InstanceType {
258 Single,
259 Cluster,
260}
261
262#[derive(Debug, Clone, Default)]
263pub struct RedisConfig {
264 pub urls: Vec<String>,
265 pub database: i64,
266 pub username: Option<String>,
267 pub password: Option<String>,
268 pub instance_type: Option<InstanceType>,
269 pub pool: RedisPoolConfig,
270}
271
272impl RedisConfig {
273 #[allow(dead_code)]
274 fn instance_type_default() -> InstanceType {
275 InstanceType::Single
276 }
277}
278
279#[derive(Debug, Clone, Default)]
280pub struct WebServerConfig {
281 pub port: i64,
282 pub rsa_key: String,
283 pub rsa_cert: String,
284 pub rsa_password_private_key: String,
285 pub rsa_password_public_key: String,
286 pub upload_store_path: String,
287 pub resources_path: String,
288 pub upload_temp_path: String,
289 pub access_url_prefix: String,
290}
291
292#[derive(Debug, Clone)]
293pub struct DatabaseConfig {
294 pub url: String,
295 pub logger_level: LevelFilter,
296}
297
298impl Default for DatabaseConfig {
299 fn default() -> Self {
300 Self {
301 url: Default::default(),
302 logger_level: LevelFilter::Info,
303 }
304 }
305}
306
307#[derive(Debug, Clone, Default, Deserialize, Serialize)]
308pub struct FaceDbConfig {
309 pub url: String,
310}
311
312impl AppConfig {
313 pub fn get() -> &'static Mutex<AppConfig> {
314 static mut CONF: MaybeUninit<Mutex<AppConfig>> = MaybeUninit::uninit();
316 static ONCE: Once = Once::new();
318
319 ONCE.call_once(|| unsafe {
320 CONF.as_mut_ptr().write(Mutex::new(AppConfig {
321 db_conf: DatabaseConfig {
322 url: "".to_string(),
323 logger_level: LevelFilter::Info,
324 },
325 webserver_conf: WebServerConfig {
326 port: 10089i64,
327 rsa_cert: String::new(),
328 rsa_key: String::new(),
329 rsa_password_private_key: String::new(),
330 rsa_password_public_key: String::new(),
331 upload_store_path: String::new(),
332 upload_temp_path: String::new(),
333 access_url_prefix: String::new(),
334 resources_path: String::new(),
335 },
336 email_conf: EmailServerConfig::default(),
337 redis_conf: None,
338 gateway_address: None,
339 app_id: None,
340 app_secret: None,
341 logger_level: LevelFilter::Info,
342 }));
343 });
344 unsafe { &*CONF.as_ptr() }
345 }
346
347 pub fn init(conf_path: &str) {
348 AppConfig::get().lock().unwrap().load_yaml(conf_path);
349 }
350
351 pub fn load_yaml(&mut self, conf_path: &str) {
352 use yaml_rust::yaml;
353 let mut f = match File::open(conf_path) {
355 Ok(f) => f,
356 Err(_) => return,
357 };
358 let mut s = String::new();
359 let _ = f.read_to_string(&mut s).is_ok();
360 let docs = yaml::YamlLoader::load_from_str(&s).unwrap();
363 let doc = &docs[0];
367 let db = &doc["database"];
368 let web = &doc["webserver"];
369 let email = &doc["email"];
370 let redis = &doc["redis"];
371 let reg = &doc["registry"];
372
373 let log_level = doc["log-level"]
374 .as_str()
375 .map(|s| match LevelFilter::from_str(s) {
376 Ok(ll) => ll,
377 Err(_) => LevelFilter::Info,
378 })
379 .unwrap_or_else(|| LevelFilter::Info);
380
381 let gatewaddr = reg["gateway_address"].as_str().map(|s| s.to_string());
382 let app_id = reg["app_id"].as_str().map(|s| s.to_string());
383 let app_secret = reg["app_secret"].as_str().map(|s| s.to_string());
384
385 let dbconf = DatabaseConfig {
386 url: db["url"].as_str().map(|s| s.to_owned()).unwrap_or_default(),
387 logger_level: if let Some(l) = db["log-level"].as_str() {
388 match LevelFilter::from_str(l) {
389 Ok(level) => level,
390 Err(_) => LevelFilter::Info,
391 }
392 } else {
393 LevelFilter::Info
394 },
395 };
396
397 let webconf = WebServerConfig {
398 port: web["port"].as_i64().unwrap_or(10089i64),
399 rsa_key: web["rsa_key"]
400 .as_str()
401 .map(|s| s.to_owned())
402 .unwrap_or_default(),
403 rsa_cert: web["rsa_cert"]
404 .as_str()
405 .map(|s| s.to_owned())
406 .unwrap_or_default(),
407 rsa_password_private_key: web["rsa_password_private_key"]
408 .as_str()
409 .map(|s| s.to_owned())
410 .unwrap_or_default(),
411 rsa_password_public_key: web["rsa_password_public_key"]
412 .as_str()
413 .map(|s| s.to_owned())
414 .unwrap_or_default(),
415 upload_store_path: web["upload-store-path"]
416 .as_str()
417 .map(|s| s.to_owned())
418 .unwrap_or_default(),
419 upload_temp_path: web["upload-temp-path"]
420 .as_str()
421 .map(|s| s.to_owned())
422 .unwrap_or_default(),
423 resources_path: web["resources-path"]
424 .as_str()
425 .map(|s| s.to_owned())
426 .unwrap_or_default(),
427 access_url_prefix: web["access-url-prefix"]
428 .as_str()
429 .map(|s| s.to_owned())
430 .unwrap_or_default(),
431 };
432 let emailconf = EmailServerConfig {
433 smtp_server: email["smtp-server"]
434 .as_str()
435 .map(|s| s.to_owned())
436 .unwrap_or_default(),
437 mine_email: email["account"]
438 .as_str()
439 .map(|s| s.to_owned())
440 .unwrap_or_default(),
441 password: email["password"]
442 .as_str()
443 .map(|s| s.to_owned())
444 .unwrap_or_default(),
445 port: email["port"]
446 .as_str()
447 .map(|s| s.to_owned())
448 .unwrap_or_default(),
449 ssl: email["ssl"].as_bool().unwrap_or_default(),
450 };
451
452 let redis_conf = if !redis.is_null() {
453 let pool = &redis["pool"];
454 Some(RedisConfig {
455 urls: if let Some(s) = redis["urls"].as_vec() {
456 let mut u = vec![];
457 for ps in s.clone() {
458 if let Some(st) = ps.as_str() {
459 u.push(st.to_string());
460 }
461 }
462 u
463 } else {
464 vec![]
465 },
466 database: redis["database"].as_i64().unwrap_or_default(),
467 username: redis["username"].as_str().map(|s| s.to_owned()),
468 password: redis["password"].as_str().map(|s| s.to_owned()),
469 instance_type: if let Some(s) = redis["instance-type"].as_str() {
470 if s == "cluster" {
471 Some(InstanceType::Cluster)
472 } else {
473 Some(InstanceType::Single)
474 }
475 } else {
476 Some(InstanceType::Single)
477 },
478 pool: RedisPoolConfig {
479 connection_timeout: pool["connection_timeout"].as_i64().unwrap_or_default()
480 as u64,
481 max_size: pool["max_size"].as_i64().unwrap_or_default() as u32,
482 mini_idel: pool["mini_idel"].as_i64().unwrap_or_default() as u32,
483 },
484 })
485 } else {
486 None
487 };
488
489 self.db_conf = dbconf;
490 self.webserver_conf = webconf;
491 self.email_conf = emailconf;
492 self.redis_conf = redis_conf;
493 self.gateway_address = gatewaddr;
494 self.app_id = app_id;
495 self.app_secret = app_secret;
496 self.logger_level = log_level;
497 }
498}
499
500#[cfg(unix)]
501pub fn set_file_permission(fcp: &str, mode: u32) {
502 use std::os::unix::fs::PermissionsExt;
503 let permissions = std::fs::Permissions::from_mode(mode);
504 match std::fs::set_permissions(fcp.clone(), permissions) {
505 Ok(_) => {}
506 Err(err) => {
507 log::warn!("Error on set permission: {}", err);
508 }
509 };
510}
511
512#[cfg(windows)]
513pub fn set_file_permission(fcp: &str, mode: u32) {
514 log::debug!(
515 "Updating the permission for {} to {} is ignored.",
516 fcp,
517 mode
518 );
519}
520
521pub fn current_timestamp_secs() -> u64 {
523 SystemTime::now()
524 .duration_since(UNIX_EPOCH)
525 .unwrap()
526 .as_secs()
527}
528
529pub fn current_timestamp() -> u128 {
530 SystemTime::now()
531 .duration_since(UNIX_EPOCH)
532 .unwrap()
533 .as_millis()
534}
535
536#[allow(dead_code)]
537pub fn text_insert_br(oldtext: Option<String>) -> Option<String> {
538 if oldtext.is_none() {
539 None
540 } else {
541 let text = oldtext.unwrap();
542 let mut newtext = String::new();
543 let lst = text.lines().collect::<Vec<&str>>();
544 for stx in 0..lst.len() {
545 let sxtr = lst[stx];
546 newtext.push_str(sxtr);
547 if stx < lst.len() - 1 {
548 newtext.push_str("<br />");
549 }
550 }
551 Some(newtext)
552 }
553}
554
555pub fn file_size_format(len: usize) -> String {
556 let t = len as f64 / (1024f64 * 1024f64 * 1024f64 * 1024f64);
557 if t >= 1.00f64 {
558 return format!("{:.02}TB", t);
559 }
560 let g = len as f64 / (1024f64 * 1024f64 * 1024f64);
561 if g >= 1.00f64 {
562 return format!("{:.02}GB", g);
563 }
564 let m = len as f64 / (1024f64 * 1024f64);
565 if m >= 1.00f64 {
566 return format!("{:.02}MB", m);
567 }
568 let k = len as f64 / 1024f64;
569 if k >= 1.00f64 {
570 return format!("{:.02}KB", k);
571 }
572
573 format!("{} B", len)
574}
575
576mod mail;
577pub use mail::*;
578
579mod queue;
580pub use queue::*;
581
582mod global_data;
583pub use global_data::*;
584
585#[allow(dead_code)]
586pub fn parse_query(query_string: &str) -> HashMap<String, String> {
587 if query_string.is_empty() {
588 return HashMap::new();
589 }
590 let q_a: Vec<&str> = query_string.split('&').collect();
591 let mut res: HashMap<String, String> = HashMap::new();
592 use percent_encoding::percent_decode;
593 for s in q_a {
594 let kv: Vec<&str> = s.split('=').collect();
596 let kvalue = percent_decode(kv[1].as_bytes()).decode_utf8().unwrap();
597 res.insert(kv[0].to_string(), kvalue.to_string());
598 }
599 res
600}
601
602#[allow(dead_code)]
603pub fn parse_query_as_value(query_string: &str) -> Value {
604 if query_string.is_empty() {
605 return Value::Null;
606 }
607 let q_a: Vec<&str> = query_string.split('&').collect();
608 let mut res: HashMap<String, String> = HashMap::new();
609 use percent_encoding::percent_decode;
610 for s in q_a {
611 let kv: Vec<&str> = s.split('=').collect();
613 let kvalue = percent_decode(kv[1].as_bytes()).decode_utf8().unwrap();
614 res.insert(kv[0].to_string(), kvalue.to_string());
615 }
616
617 match serde_json::to_value(res) {
618 Ok(tv) => tv,
619 Err(_) => Value::Null,
620 }
621}
622
623#[allow(dead_code)]
624pub fn get_hash_value(query_params: &HashMap<String, String>, key: &str) -> String {
625 match query_params.get(key) {
626 Some(val) => val.clone(),
627 None => "".to_owned(),
628 }
629}
630
631#[allow(dead_code)]
632pub fn calc_file_hash(filename: &str) -> Option<String> {
633 let mut file = match File::open(filename) {
634 Ok(file) => file,
635 Err(err) => {
636 log::info!("error for open file {} with err {}", filename, err);
637 return None;
638 }
639 };
640
641 let mut hasher = Sha256::new();
642 let mut buffer = [0; 1024 * 1024];
643 loop {
644 match file.read(&mut buffer) {
645 Ok(ts) => {
646 if ts == 1024 * 1024 {
647 hasher.update(&buffer);
648 } else if ts > 0 {
649 let lesbuf = &buffer[0..ts];
650 hasher.update(lesbuf);
651 } else {
652 break;
653 }
654 }
655 Err(err) => {
656 log::info!("read file {} with err {}", filename, err);
657 return None;
658 }
659 };
660 }
661
662 let result = hasher.finish();
663 Some(hex::encode(result))
664}
665
666pub fn datetime_to_date(dt: &Option<rbatis::DateTimeNative>) -> Option<rbatis::DateNative> {
667 dt.as_ref().map(|t| rbatis::DateNative { inner: t.date() })
668}
669
670pub fn pure_datetime_to_date(dt: &rbatis::DateTimeNative) -> rbatis::DateNative {
671 rbatis::DateNative { inner: dt.date() }
672}
673
674pub fn datetime_diff(last: &rbatis::DateTimeNative, prev: &rbatis::DateTimeNative) -> i64 {
675 last.and_utc().timestamp() - prev.and_utc().timestamp()
676}