1 use std::fs::File; 2 use std::io::{Error, ErrorKind, Result}; 3 use std::path::PathBuf; 4 use std::vec::Vec; 5 6 extern crate kqueue; 7 use kqueue::Watcher as KQueue; 8 use kqueue::FilterFlag as FilterFlag; 9 10 const FILTER: kqueue::EventFilter = kqueue::EventFilter::EVFILT_VNODE; 11 12 pub struct FileWatcherImpl { 13 kq: KQueue, 14 watches: Vec<FileWatchImpl> 15 } 16 17 pub struct FileWatchImpl { 18 file: File, 19 } 20 21 impl FileWatcherImpl { init() -> Result<FileWatcherImpl>22 pub fn init() -> Result<FileWatcherImpl> { 23 let kq = match KQueue::new() { 24 Ok(value) => value, 25 Err(msg) => return Result::Err(msg), 26 }; 27 28 return Result::Ok(FileWatcherImpl { 29 kq, 30 watches: vec![] 31 }); 32 } 33 add_watch(&mut self, file_path: &PathBuf) -> Result<&FileWatchImpl>34 pub fn add_watch(&mut self, file_path: &PathBuf) -> Result<&FileWatchImpl> { 35 let flags: FilterFlag = 36 FilterFlag::NOTE_WRITE | 37 FilterFlag::NOTE_EXTEND | 38 FilterFlag::NOTE_RENAME | 39 FilterFlag::NOTE_DELETE | 40 FilterFlag::NOTE_LINK; 41 42 let file = File::open(file_path)?; 43 let _ = match self.kq.add_file(&file, FILTER, flags) { 44 Ok(w) => w, 45 Err(msg) => return Result::Err(msg), 46 }; 47 48 let fw = FileWatchImpl { 49 file 50 }; 51 52 self.watches.push(fw); 53 return Result::Ok(&self.watches.last().unwrap()); 54 } 55 rm_watch(&mut self, fw: &FileWatchImpl) -> Result<()>56 pub fn rm_watch(&mut self, fw: &FileWatchImpl) -> Result<()> { 57 for i in 0..self.watches.len() { 58 let item_ref = self.watches.get(i).unwrap(); 59 if item_ref as *const FileWatchImpl == fw as *const FileWatchImpl { 60 let item = self.watches.remove(i); 61 return self.kq.remove_file(&item.file, FILTER); 62 } 63 } 64 65 return Result::Err(Error::new( 66 ErrorKind::InvalidInput, 67 "Passed FileWatch does not belong to this FileWatcher instance" 68 )); 69 } 70 start(&mut self) -> Result<()>71 pub fn start(&mut self) -> Result<()> { 72 return self.kq.watch(); 73 } 74 any_events(&mut self) -> Result<bool>75 pub fn any_events(&mut self) -> Result<bool> { 76 match self.kq.poll(None) { 77 Some(_) => return Result::Ok(true), 78 None => return Result::Ok(false), 79 } 80 } 81 } 82