Skip to main content

driven/sync/
watcher.rs

1//! File system watcher for auto-sync
2
3use crate::{DrivenError, Result};
4use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
5use std::path::Path;
6use std::sync::mpsc::{Receiver, channel};
7
8/// Watches for file changes
9#[derive(Debug)]
10pub struct FileWatcher {
11    /// The watcher instance
12    _watcher: RecommendedWatcher,
13    /// Receiver for events
14    rx: Receiver<notify::Result<notify::Event>>,
15}
16
17impl FileWatcher {
18    /// Create a new file watcher
19    pub fn new(path: &Path) -> Result<Self> {
20        let (tx, rx) = channel();
21
22        let mut watcher = RecommendedWatcher::new(
23            move |res| {
24                let _ = tx.send(res);
25            },
26            Config::default(),
27        )
28        .map_err(|e| DrivenError::Sync(format!("Failed to create watcher: {}", e)))?;
29
30        watcher
31            .watch(path, RecursiveMode::Recursive)
32            .map_err(|e| DrivenError::Sync(format!("Failed to watch path: {}", e)))?;
33
34        Ok(Self {
35            _watcher: watcher,
36            rx,
37        })
38    }
39
40    /// Get pending events (non-blocking)
41    pub fn pending_events(&self) -> Vec<WatchEvent> {
42        let mut events = Vec::new();
43
44        while let Ok(result) = self.rx.try_recv() {
45            if let Ok(event) = result {
46                events.push(WatchEvent::from_notify(event));
47            }
48        }
49
50        events
51    }
52
53    /// Wait for next event (blocking)
54    pub fn wait_for_event(&self) -> Option<WatchEvent> {
55        self.rx
56            .recv()
57            .ok()
58            .and_then(|r| r.ok())
59            .map(WatchEvent::from_notify)
60    }
61}
62
63/// Simplified watch event
64#[derive(Debug, Clone)]
65pub struct WatchEvent {
66    /// Event kind
67    pub kind: WatchEventKind,
68    /// Affected paths
69    pub paths: Vec<std::path::PathBuf>,
70}
71
72/// Watch event kinds
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub enum WatchEventKind {
75    /// File created
76    Create,
77    /// File modified
78    Modify,
79    /// File deleted
80    Remove,
81    /// Other event
82    Other,
83}
84
85impl WatchEvent {
86    fn from_notify(event: notify::Event) -> Self {
87        let kind = match event.kind {
88            notify::EventKind::Create(_) => WatchEventKind::Create,
89            notify::EventKind::Modify(_) => WatchEventKind::Modify,
90            notify::EventKind::Remove(_) => WatchEventKind::Remove,
91            _ => WatchEventKind::Other,
92        };
93
94        Self {
95            kind,
96            paths: event.paths,
97        }
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn test_watch_event_kind() {
107        assert_ne!(WatchEventKind::Create, WatchEventKind::Modify);
108    }
109}