use memmap::MmapOptions;
use std::fs::File;
use std::thread;
use std::error::Error;
pub struct TailReader<T> {
file_path: String,
processor: T,
}
impl<T> TailReader<T> where T: Fn(String) {
pub fn new(file_path: String, processor: T) -> TailReader<T> {
TailReader {
file_path,
processor,
}
}
pub fn tail(self) -> Result<(), Box<Error>> {
let mut offset: usize = 0;
let stop_char: u8 = "\n".as_bytes()[0];
let mut current_line = Vec::new();
let mut file = File::open(self.file_path.clone())?;
let mut mmap = unsafe { MmapOptions::new().map(&file)? };
loop {
let mmap_len = mmap.len();
if mmap_len > offset {
let bytes = match mmap.get(offset..mmap_len) {
Some(n) => n,
_ => continue
};
for byte in bytes {
if *byte == stop_char {
let line = String::from_utf8(current_line)
.unwrap_or(String::from("error parsing line"));
(self.processor)(line);
current_line = Vec::new();
} else {
current_line.push(*byte);
}
offset += 1;
}
} else {
file = File::open(self.file_path.clone())?;
mmap = unsafe { MmapOptions::new().map(&file)? };
}
thread::sleep_ms(1000)
}
}
}