use std::io; use std::path::Path; use std::sync::mpsc; use std::thread; use std::time::Duration; use crossbeam_channel::Receiver; use notify::{watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent}; /// `VfsBackend` that uses `std::fs` and the `notify` crate. pub struct StdBackend { watcher: RecommendedWatcher, watcher_receiver: Receiver, } impl StdBackend { pub fn new() -> StdBackend { let (notify_tx, notify_rx) = mpsc::channel(); let watcher = watcher(notify_tx, Duration::from_millis(50)).unwrap(); let (tx, rx) = crossbeam_channel::unbounded(); thread::spawn(move || { for event in notify_rx { match event { DebouncedEvent::Create(path) => { tx.send(VfsEvent::Create(path))?; } DebouncedEvent::Write(path) => { tx.send(VfsEvent::Write(path))?; } DebouncedEvent::Remove(path) => { tx.send(VfsEvent::Remove(path))?; } DebouncedEvent::Rename(from, to) => { tx.send(VfsEvent::Remove(from))?; tx.send(VfsEvent::Create(to))?; } _ => {} } } Result::<(), crossbeam_channel::SendError>::Ok(()) }); Self { watcher, watcher_receiver: rx, } } } impl VfsBackend for StdBackend { fn read(&mut self, path: &Path) -> io::Result> { fs_err::read(path) } fn write(&mut self, path: &Path, data: &[u8]) -> io::Result<()> { fs_err::write(path, data) } fn read_dir(&mut self, path: &Path) -> io::Result { let entries: Result, _> = fs_err::read_dir(path)?.collect(); let mut entries = entries?; entries.sort_by_cached_key(|entry| entry.file_name()); let inner = entries .into_iter() .map(|entry| Ok(DirEntry { path: entry.path() })); Ok(ReadDir { inner: Box::new(inner), }) } fn remove_file(&mut self, path: &Path) -> io::Result<()> { fs_err::remove_file(path) } fn remove_dir_all(&mut self, path: &Path) -> io::Result<()> { fs_err::remove_dir_all(path) } fn metadata(&mut self, path: &Path) -> io::Result { let inner = fs_err::metadata(path)?; Ok(Metadata { is_file: inner.is_file(), }) } fn event_receiver(&self) -> crossbeam_channel::Receiver { self.watcher_receiver.clone() } fn watch(&mut self, path: &Path) -> io::Result<()> { self.watcher .watch(path, RecursiveMode::NonRecursive) .map_err(|inner| io::Error::new(io::ErrorKind::Other, inner)) } fn unwatch(&mut self, path: &Path) -> io::Result<()> { self.watcher .unwatch(path) .map_err(|inner| io::Error::new(io::ErrorKind::Other, inner)) } }