log-full 0.0.1

A simple, asynchronous log library
Documentation
//! 文件监控模块
//! 
//! 提供日志文件变化监控功能

use crate::error::{LogError, LogResult};
use std::path::{Path, PathBuf};
use std::sync::mpsc::{self, Receiver, Sender};
use std::thread;
use std::time::Duration;

// File watching functionality using standard library

/// 文件变化事件类型
#[derive(Debug, Clone)]
pub enum FileEvent {
    /// 文件创建
    Created(PathBuf),
    /// 文件修改
    Modified(PathBuf),
    /// 文件删除
    Deleted(PathBuf),
    /// 文件重命名
    Renamed { from: PathBuf, to: PathBuf },
    /// 监控错误
    Error(String),
}

/// 文件监控器配置
#[derive(Debug, Clone)]
pub struct WatcherConfig {
    /// 监控的文件路径
    pub paths: Vec<PathBuf>,
    /// 是否递归监控子目录
    pub recursive: bool,
    /// 事件过滤器
    pub filters: Vec<String>,
    /// 轮询间隔(毫秒)
    pub poll_interval: Option<u64>,
}

impl Default for WatcherConfig {
    fn default() -> Self {
        Self {
            paths: Vec::new(),
            recursive: false,
            filters: Vec::new(),
            poll_interval: None,
        }
    }
}

/// 文件监控器
pub struct FileWatcher {
    config: WatcherConfig,
    event_sender: Option<Sender<FileEvent>>,
}

impl FileWatcher {
    /// 创建新的文件监控器
    pub fn new(config: WatcherConfig) -> Self {
        Self {
            config,
            event_sender: None,
        }
    }
    
    /// 启动监控
    pub fn start(&mut self) -> LogResult<Receiver<FileEvent>> {
        let (sender, receiver) = mpsc::channel();
        self.event_sender = Some(sender.clone());
        
        // 使用轮询方式监控文件变化
        self.start_polling(sender);
        
        Ok(receiver)
    }
    
    /// 停止监控
    pub fn stop(&mut self) {
        self.event_sender = None;
    }
    
    /// 添加监控路径
    pub fn add_path<P: AsRef<Path>>(&mut self, path: P) -> LogResult<()> {
        let path_buf = path.as_ref().to_path_buf();
        
        if !self.config.paths.contains(&path_buf) {
            self.config.paths.push(path_buf.clone());
        }
        
        Ok(())
    }
    
    /// 移除监控路径
    pub fn remove_path<P: AsRef<Path>>(&mut self, path: P) -> LogResult<()> {
        let path_buf = path.as_ref().to_path_buf();
        
        if let Some(pos) = self.config.paths.iter().position(|p| p == &path_buf) {
            self.config.paths.remove(pos);
        }
        
        Ok(())
    }
    
    /// 启动轮询监控
    fn start_polling(&self, sender: Sender<FileEvent>) {
        let paths = self.config.paths.clone();
        let interval = Duration::from_millis(self.config.poll_interval.unwrap_or(1000));
        
        thread::spawn(move || {
            let mut last_modified = std::collections::HashMap::new();
            
            loop {
                for path in &paths {
                    if let Ok(metadata) = std::fs::metadata(path) {
                        if let Ok(modified) = metadata.modified() {
                            if let Some(&last_time) = last_modified.get(path) {
                                if modified > last_time {
                                    let _ = sender.send(FileEvent::Modified(path.clone()));
                                }
                            }
                            last_modified.insert(path.clone(), modified);
                        }
                    }
                }
                
                thread::sleep(interval);
            }
        });
    }
}

/// 文件监控器构建器
pub struct WatcherBuilder {
    config: WatcherConfig,
}

impl WatcherBuilder {
    /// 创建新的监控器构建器
    pub fn new() -> Self {
        Self {
            config: WatcherConfig::default(),
        }
    }
    
    /// 添加监控路径
    pub fn path<P: AsRef<Path>>(mut self, path: P) -> Self {
        self.config.paths.push(path.as_ref().to_path_buf());
        self
    }
    
    /// 设置递归监控
    pub fn recursive(mut self, recursive: bool) -> Self {
        self.config.recursive = recursive;
        self
    }
    
    /// 添加过滤器
    pub fn filter<S: Into<String>>(mut self, filter: S) -> Self {
        self.config.filters.push(filter.into());
        self
    }
    
    /// 设置轮询间隔
    pub fn poll_interval(mut self, interval_ms: u64) -> Self {
        self.config.poll_interval = Some(interval_ms);
        self
    }
    
    /// 构建监控器
    pub fn build(self) -> FileWatcher {
        FileWatcher::new(self.config)
    }
}

/// 日志文件轮转监控器
pub struct LogRotationWatcher {
    base_path: PathBuf,
    max_size: u64,
    current_size: u64,
    max_files: u32,
}

impl LogRotationWatcher {
    /// 创建新的轮转监控器
    pub fn new<P: AsRef<Path>>(base_path: P, max_size: u64, max_files: u32) -> Self {
        Self {
            base_path: base_path.as_ref().to_path_buf(),
            max_size,
            current_size: 0,
            max_files,
        }
    }
    
    /// 检查是否需要轮转
    pub fn should_rotate(&mut self) -> LogResult<bool> {
        if let Ok(metadata) = std::fs::metadata(&self.base_path) {
            self.current_size = metadata.len();
            Ok(self.current_size >= self.max_size)
        } else {
            Ok(false)
        }
    }
    
    /// 执行文件轮转
    pub fn rotate(&mut self) -> LogResult<()> {
        // 移动现有文件
        for i in (1..self.max_files).rev() {
            let old_path = self.get_rotated_path(i);
            let new_path = self.get_rotated_path(i + 1);
            
            if old_path.exists() {
                std::fs::rename(&old_path, &new_path)
                    .map_err(|e| LogError::file_operation(
                        old_path.to_string_lossy().to_string(),
                        format!("Failed to rotate file: {}", e)
                    ))?;
            }
        }
        
        // 移动当前文件
        if self.base_path.exists() {
            let rotated_path = self.get_rotated_path(1);
            std::fs::rename(&self.base_path, &rotated_path)
                .map_err(|e| LogError::file_operation(
                    self.base_path.to_string_lossy().to_string(),
                    format!("Failed to rotate current file: {}", e)
                ))?;
        }
        
        // 删除超出限制的文件
        let excess_path = self.get_rotated_path(self.max_files + 1);
        if excess_path.exists() {
            std::fs::remove_file(&excess_path)
                .map_err(|e| LogError::file_operation(
                    excess_path.to_string_lossy().to_string(),
                    format!("Failed to remove excess file: {}", e)
                ))?;
        }
        
        self.current_size = 0;
        Ok(())
    }
    
    /// 获取轮转文件路径
    fn get_rotated_path(&self, index: u32) -> PathBuf {
        let mut path = self.base_path.clone();
        let file_name = path.file_name().unwrap().to_string_lossy();
        let new_name = format!("{}.{}", file_name, index);
        path.set_file_name(new_name);
        path
    }
    
    /// 更新当前文件大小
    pub fn update_size(&mut self, additional_bytes: u64) {
        self.current_size += additional_bytes;
    }
    
    /// 获取当前文件大小
    pub fn current_size(&self) -> u64 {
        self.current_size
    }
}