1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
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) } } }