1 use std::{collections::BTreeMap, fmt::Debug, fs::File, io::Write, path::PathBuf};
2 
3 use log::error;
4 
5 use crate::constant::CMD_ARGS;
6 
7 /// 日志集合
8 ///
9 /// 所有的日志都会被存到这个集合中, 以便于进行各种操作
10 ///
11 /// 日志集合的后端可以在日志插入前后做一些操作(需要实现[`LogSetBackend`])
12 #[derive(Debug)]
13 #[allow(dead_code)]
14 pub struct LogSet<K, V> {
15     inner: BTreeMap<K, V>,
16     backend: Box<dyn LogSetBackend<K, V>>,
17     name: String,
18     file_path: PathBuf,
19     log_file: Option<File>,
20 }
21 
22 #[allow(dead_code)]
23 impl<K: Ord, V: Clone + PartialEq + Debug> LogSet<K, V> {
new(name: String, backend: Option<Box<dyn LogSetBackend<K, V>>>) -> Self24     pub fn new(name: String, backend: Option<Box<dyn LogSetBackend<K, V>>>) -> Self {
25         let mut file_path = CMD_ARGS.read().unwrap().as_ref().unwrap().log_dir.clone();
26         file_path.push(format!("{}-{}.log", name, std::process::id()));
27 
28         let log_file = File::create(&file_path).expect("Failed to create log file.");
29 
30         Self {
31             inner: BTreeMap::new(),
32             backend: backend.unwrap_or_else(|| Box::new(DefaultBackend::new())),
33             name,
34             file_path,
35             log_file: Some(log_file),
36         }
37     }
38 
insert(&mut self, key: K, value: V)39     pub fn insert(&mut self, key: K, value: V) {
40         let cloned_value = value.clone();
41         self.backend.before_insert(&self.name, &value);
42 
43         let prev = self.inner.insert(key, value);
44         if let Some(prev) = prev {
45             if prev.ne(&cloned_value) {
46                 error!(
47                     "LogSet::insert(): prev != cloned_value: prev: {:?}, cloned_value: {:?}",
48                     prev, cloned_value
49                 );
50             }
51         } else {
52             self.log_file
53                 .as_mut()
54                 .map(|f| writeln!(f, "{:?}", cloned_value).ok());
55         }
56 
57         self.backend.after_insert(&self.name, &cloned_value);
58     }
59 
file_path(&self) -> &PathBuf60     pub fn file_path(&self) -> &PathBuf {
61         &self.file_path
62     }
63 
len(&self) -> usize64     pub fn len(&self) -> usize {
65         self.inner.len()
66     }
67 
get(&self, key: &K) -> Option<&V>68     pub fn get(&self, key: &K) -> Option<&V> {
69         self.inner.get(key)
70     }
71 
get_mut(&mut self, key: &K) -> Option<&mut V>72     pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
73         self.inner.get_mut(key)
74     }
75 
remove(&mut self, key: &K) -> Option<V>76     pub fn remove(&mut self, key: &K) -> Option<V> {
77         self.inner.remove(key)
78     }
79 
clear(&mut self)80     pub fn clear(&mut self) {
81         self.inner.clear();
82     }
83 
iter(&self) -> impl Iterator<Item = (&K, &V)>84     pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
85         self.inner.iter()
86     }
87 
contains_key(&self, key: &K) -> bool88     pub fn contains_key(&self, key: &K) -> bool {
89         self.inner.contains_key(key)
90     }
91 }
92 
93 /// 日志集合的后端, 用于在日志插入前后做一些操作
94 pub trait LogSetBackend<K, V>: Debug {
before_insert(&mut self, _log_set_name: &str, _log: &V)95     fn before_insert(&mut self, _log_set_name: &str, _log: &V) {}
96 
after_insert(&mut self, _log_set_name: &str, _log: &V)97     fn after_insert(&mut self, _log_set_name: &str, _log: &V) {}
98 }
99 
100 #[derive(Debug)]
101 struct DefaultBackend(());
102 
103 impl DefaultBackend {
new() -> Self104     pub const fn new() -> Self {
105         Self(())
106     }
107 }
108 
109 impl<K, V> LogSetBackend<K, V> for DefaultBackend {
before_insert(&mut self, _log_set_name: &str, _log: &V)110     fn before_insert(&mut self, _log_set_name: &str, _log: &V) {}
111 
after_insert(&mut self, _log_set_name: &str, _log: &V)112     fn after_insert(&mut self, _log_set_name: &str, _log: &V) {}
113 }
114