use crate::structs::{Files, CustomError}; use inotify::{ EventMask, Inotify, WatchMask }; use log::error; use tokio::sync::mpsc; use crate::prcs::{is_frozen, is_active}; use tokio::time::Duration; use std::sync::Arc; use std::path::Path; use std::borrow::BorrowMut; pub async fn create_watcher(filename: &str, path: &str) -> Result { let src = format!("{}{}", path, filename); let mut inotify = Inotify::init().unwrap_or_else(|_| { error!("{}",format!("Cannot create watcher for {}", &src)); std::process::exit(101); }); _ = inotify .watches() .add( &src, WatchMask::ALL_EVENTS ); Ok(inotify) } pub async fn file_handler ( name: &str, files: &Vec, tx: Arc>, watchers: Arc>> ) -> Result<(), CustomError> { // println!("file daemon on {}", name); for (i, file) in files.iter().enumerate() { // let src = format!("{}{}", file.src, file.filename); if check_file(&file.filename, &file.src).await.is_err() { if !is_active(name).await || is_frozen(name).await { return Err(CustomError::Fatal); } match file.triggers.on_delete.as_str() { "stay" => { continue; }, "stop" => { if is_active(name).await { tx.send(1).await.unwrap(); } return Err(CustomError::Fatal); }, "hold" => { if is_active(name).await { tx.send(2).await.unwrap(); return Err(CustomError::Fatal); } }, _ => { tokio::time::sleep(Duration::from_millis(50)).await; tx.send(101).await.unwrap(); return Err(CustomError::Fatal); }, } } else if is_active(name).await && !is_frozen(name).await{ let watchers = watchers.clone(); // println!("mutex: {:?}", watchers); let mut buffer = [0; 128]; let mut mutex_guard = watchers.lock().await; if let Some(notify) = mutex_guard.get_mut(i) { let events = notify.read_events(&mut buffer); // println!("{:?}", events); if events.is_ok(){ let events: Vec = events.unwrap() .into_iter() .map(|mask| {mask.mask}) .filter(|mask| { *mask == EventMask::MODIFY || *mask == EventMask::DELETE_SELF }) .collect(); for event in events { if let EventMask::DELETE_SELF = event { // ! warning (DELETE_SELF event) ! // println!("! warning (DELETE_SELF event) !"); // * watcher recreation after dealing with file recreation mech in text editors let mutex = notify.borrow_mut(); *mutex = create_watcher(&file.filename, &file.src).await.unwrap(); } match file.triggers.on_change.as_str() { "stop" => { let _ = tx.send(7).await; }, "restart" => { let _ = tx.send(8).await; }, "stay" => { let _ = tx.send(9).await; }, _ => { let _ = tx.send(101).await; }, } } } } } } tokio::task::yield_now().await; Ok(()) } pub async fn check_file(filename: &str, path: &str) -> Result<(), CustomError> { let arc_name = Arc::new(filename.to_string()); let arc_path = Arc::new(path.to_string()); tokio::task::spawn_blocking(move || { let fileconcat = format!("{}{}", arc_path, arc_name); let path = Path::new(&fileconcat); if path.exists() { Ok(()) } else { Err(CustomError::Fatal) } }) .await .unwrap_or_else(|_| { panic!("Corrupted while file check process"); }) }