use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use std::sync::mpsc::Sender;
use std::fs;
use std::thread;
use super::{Error, Event, op, Watcher};
use std::path::{Path, PathBuf};
use self::walker::Walker;
use filetime::FileTime;
extern crate walker;
pub struct PollWatcher {
tx: Sender<Event>,
watches: Arc<RwLock<HashSet<PathBuf>>>,
open: Arc<RwLock<bool>>
}
impl PollWatcher {
pub fn with_delay(tx: Sender<Event>, delay: u32) -> Result<PollWatcher, Error> {
let mut p = PollWatcher {
tx: tx,
watches: Arc::new(RwLock::new(HashSet::new())),
open: Arc::new(RwLock::new(true))
};
p.run(delay);
Ok(p)
}
fn run(&mut self, delay: u32) {
let tx = self.tx.clone();
let watches = self.watches.clone();
let open = self.open.clone();
thread::spawn(move || {
let mut mtimes: HashMap<PathBuf, u64> = HashMap::new();
loop {
if delay != 0 {
thread::sleep_ms(delay);
}
if !(*open.read().unwrap()) {
break
}
for watch in watches.read().unwrap().iter() {
let meta = fs::metadata(watch);
if !meta.is_ok() {
let _ = tx.send(Event {
path: Some(watch.clone()),
op: Err(Error::PathNotFound)
});
continue
}
match meta {
Err(e) => {
let _ = tx.send(Event {
path: Some(watch.clone()),
op: Err(Error::Io(e))
});
continue
},
Ok(stat) => {
let modified =
FileTime::from_last_modification_time(&stat)
.seconds();
match mtimes.insert(watch.clone(), modified) {
None => continue, Some(old) => {
if modified > old {
let _ = tx.send(Event {
path: Some(watch.clone()),
op: Ok(op::WRITE)
});
continue
}
}
}
if !stat.is_dir() { continue }
}
}
match Walker::new(watch) {
Err(e) => {
let _ = tx.send(Event {
path: Some(watch.clone()),
op: Err(Error::Io(e))
});
continue
},
Ok(iter) => {
for entry in iter {
match entry {
Ok(entry) => {
let path = entry.path();
match fs::metadata(&path) {
Err(e) => {
let _ = tx.send(Event {
path: Some(path.clone()),
op: Err(Error::Io(e))
});
continue
},
Ok(stat) => {
let modified =
FileTime::from_last_modification_time(&stat)
.seconds();
match mtimes.insert(path.clone(), modified) {
None => continue, Some(old) => {
if modified > old {
let _ = tx.send(Event {
path: Some(path.clone()),
op: Ok(op::WRITE)
});
continue
}
}
}
}
}
},
Err(e) => {
let _ = tx.send(Event {
path: Some(watch.clone()),
op: Err(Error::Io(e))
});
},
}
}
}
}
}
}
});
}
}
impl Watcher for PollWatcher {
fn new(tx: Sender<Event>) -> Result<PollWatcher, Error> {
PollWatcher::with_delay(tx, 10)
}
fn watch<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
(*self.watches).write().unwrap().insert(path.as_ref().to_path_buf());
Ok(())
}
fn unwatch<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
if (*self.watches).write().unwrap().remove(path.as_ref()) {
Ok(())
} else {
Err(Error::WatchNotFound)
}
}
}
impl Drop for PollWatcher {
fn drop(&mut self) {
{
let mut open = (*self.open).write().unwrap();
(*open) = false;
}
}
}