Skip to main content

log_full/
watcher.rs

1//! 文件监控模块
2//! 
3//! 提供日志文件变化监控功能
4
5use crate::error::{LogError, LogResult};
6use std::path::{Path, PathBuf};
7use std::sync::mpsc::{self, Receiver, Sender};
8use std::thread;
9use std::time::Duration;
10
11// File watching functionality using standard library
12
13/// 文件变化事件类型
14#[derive(Debug, Clone)]
15pub enum FileEvent {
16    /// 文件创建
17    Created(PathBuf),
18    /// 文件修改
19    Modified(PathBuf),
20    /// 文件删除
21    Deleted(PathBuf),
22    /// 文件重命名
23    Renamed { from: PathBuf, to: PathBuf },
24    /// 监控错误
25    Error(String),
26}
27
28/// 文件监控器配置
29#[derive(Debug, Clone)]
30pub struct WatcherConfig {
31    /// 监控的文件路径
32    pub paths: Vec<PathBuf>,
33    /// 是否递归监控子目录
34    pub recursive: bool,
35    /// 事件过滤器
36    pub filters: Vec<String>,
37    /// 轮询间隔(毫秒)
38    pub poll_interval: Option<u64>,
39}
40
41impl Default for WatcherConfig {
42    fn default() -> Self {
43        Self {
44            paths: Vec::new(),
45            recursive: false,
46            filters: Vec::new(),
47            poll_interval: None,
48        }
49    }
50}
51
52/// 文件监控器
53pub struct FileWatcher {
54    config: WatcherConfig,
55    event_sender: Option<Sender<FileEvent>>,
56}
57
58impl FileWatcher {
59    /// 创建新的文件监控器
60    pub fn new(config: WatcherConfig) -> Self {
61        Self {
62            config,
63            event_sender: None,
64        }
65    }
66    
67    /// 启动监控
68    pub fn start(&mut self) -> LogResult<Receiver<FileEvent>> {
69        let (sender, receiver) = mpsc::channel();
70        self.event_sender = Some(sender.clone());
71        
72        // 使用轮询方式监控文件变化
73        self.start_polling(sender);
74        
75        Ok(receiver)
76    }
77    
78    /// 停止监控
79    pub fn stop(&mut self) {
80        self.event_sender = None;
81    }
82    
83    /// 添加监控路径
84    pub fn add_path<P: AsRef<Path>>(&mut self, path: P) -> LogResult<()> {
85        let path_buf = path.as_ref().to_path_buf();
86        
87        if !self.config.paths.contains(&path_buf) {
88            self.config.paths.push(path_buf.clone());
89        }
90        
91        Ok(())
92    }
93    
94    /// 移除监控路径
95    pub fn remove_path<P: AsRef<Path>>(&mut self, path: P) -> LogResult<()> {
96        let path_buf = path.as_ref().to_path_buf();
97        
98        if let Some(pos) = self.config.paths.iter().position(|p| p == &path_buf) {
99            self.config.paths.remove(pos);
100        }
101        
102        Ok(())
103    }
104    
105    /// 启动轮询监控
106    fn start_polling(&self, sender: Sender<FileEvent>) {
107        let paths = self.config.paths.clone();
108        let interval = Duration::from_millis(self.config.poll_interval.unwrap_or(1000));
109        
110        thread::spawn(move || {
111            let mut last_modified = std::collections::HashMap::new();
112            
113            loop {
114                for path in &paths {
115                    if let Ok(metadata) = std::fs::metadata(path) {
116                        if let Ok(modified) = metadata.modified() {
117                            if let Some(&last_time) = last_modified.get(path) {
118                                if modified > last_time {
119                                    let _ = sender.send(FileEvent::Modified(path.clone()));
120                                }
121                            }
122                            last_modified.insert(path.clone(), modified);
123                        }
124                    }
125                }
126                
127                thread::sleep(interval);
128            }
129        });
130    }
131}
132
133/// 文件监控器构建器
134pub struct WatcherBuilder {
135    config: WatcherConfig,
136}
137
138impl WatcherBuilder {
139    /// 创建新的监控器构建器
140    pub fn new() -> Self {
141        Self {
142            config: WatcherConfig::default(),
143        }
144    }
145    
146    /// 添加监控路径
147    pub fn path<P: AsRef<Path>>(mut self, path: P) -> Self {
148        self.config.paths.push(path.as_ref().to_path_buf());
149        self
150    }
151    
152    /// 设置递归监控
153    pub fn recursive(mut self, recursive: bool) -> Self {
154        self.config.recursive = recursive;
155        self
156    }
157    
158    /// 添加过滤器
159    pub fn filter<S: Into<String>>(mut self, filter: S) -> Self {
160        self.config.filters.push(filter.into());
161        self
162    }
163    
164    /// 设置轮询间隔
165    pub fn poll_interval(mut self, interval_ms: u64) -> Self {
166        self.config.poll_interval = Some(interval_ms);
167        self
168    }
169    
170    /// 构建监控器
171    pub fn build(self) -> FileWatcher {
172        FileWatcher::new(self.config)
173    }
174}
175
176/// 日志文件轮转监控器
177pub struct LogRotationWatcher {
178    base_path: PathBuf,
179    max_size: u64,
180    current_size: u64,
181    max_files: u32,
182}
183
184impl LogRotationWatcher {
185    /// 创建新的轮转监控器
186    pub fn new<P: AsRef<Path>>(base_path: P, max_size: u64, max_files: u32) -> Self {
187        Self {
188            base_path: base_path.as_ref().to_path_buf(),
189            max_size,
190            current_size: 0,
191            max_files,
192        }
193    }
194    
195    /// 检查是否需要轮转
196    pub fn should_rotate(&mut self) -> LogResult<bool> {
197        if let Ok(metadata) = std::fs::metadata(&self.base_path) {
198            self.current_size = metadata.len();
199            Ok(self.current_size >= self.max_size)
200        } else {
201            Ok(false)
202        }
203    }
204    
205    /// 执行文件轮转
206    pub fn rotate(&mut self) -> LogResult<()> {
207        // 移动现有文件
208        for i in (1..self.max_files).rev() {
209            let old_path = self.get_rotated_path(i);
210            let new_path = self.get_rotated_path(i + 1);
211            
212            if old_path.exists() {
213                std::fs::rename(&old_path, &new_path)
214                    .map_err(|e| LogError::file_operation(
215                        old_path.to_string_lossy().to_string(),
216                        format!("Failed to rotate file: {}", e)
217                    ))?;
218            }
219        }
220        
221        // 移动当前文件
222        if self.base_path.exists() {
223            let rotated_path = self.get_rotated_path(1);
224            std::fs::rename(&self.base_path, &rotated_path)
225                .map_err(|e| LogError::file_operation(
226                    self.base_path.to_string_lossy().to_string(),
227                    format!("Failed to rotate current file: {}", e)
228                ))?;
229        }
230        
231        // 删除超出限制的文件
232        let excess_path = self.get_rotated_path(self.max_files + 1);
233        if excess_path.exists() {
234            std::fs::remove_file(&excess_path)
235                .map_err(|e| LogError::file_operation(
236                    excess_path.to_string_lossy().to_string(),
237                    format!("Failed to remove excess file: {}", e)
238                ))?;
239        }
240        
241        self.current_size = 0;
242        Ok(())
243    }
244    
245    /// 获取轮转文件路径
246    fn get_rotated_path(&self, index: u32) -> PathBuf {
247        let mut path = self.base_path.clone();
248        let file_name = path.file_name().unwrap().to_string_lossy();
249        let new_name = format!("{}.{}", file_name, index);
250        path.set_file_name(new_name);
251        path
252    }
253    
254    /// 更新当前文件大小
255    pub fn update_size(&mut self, additional_bytes: u64) {
256        self.current_size += additional_bytes;
257    }
258    
259    /// 获取当前文件大小
260    pub fn current_size(&self) -> u64 {
261        self.current_size
262    }
263}