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