pub mod files; pub mod prcs; pub mod services; use crate::options::structs::TrackingProcess; use files::create_watcher; use files::file_handler; use inotify::Inotify; use log::{error, warn}; use prcs::{ freeze_process, is_active, is_frozen, restart_process, start_process, terminate_process, unfreeze_process, }; use services::service_handler; use std::process::Command; use std::sync::Arc; use tokio::join; use tokio::sync::mpsc; use tokio::time::Duration; const GET_ID_CMD: &str = "hostname"; /// # async func to run 3 main daemons (now it's more like tree-form than classical 0.1.0 form ) /// > hint : give mpsc with capacity 1 to jump over potential errors during running process /// > ** in [developing](https://github.com/prplV/runner-rs "REPOSITORY") ** pub async fn run_daemons( proc: Arc, tx: Arc>, rx: &mut mpsc::Receiver, ) { // creating watchers + ---buffers--- let mut watchers: Vec = vec![]; for file in proc.dependencies.files.clone().into_iter() { watchers.push(create_watcher(&file.filename, &file.src).await.unwrap()); } let watchers_clone: Arc>> = Arc::new(tokio::sync::Mutex::new(watchers)); loop { let run_hand = running_handler(proc.clone(), tx.clone(), watchers_clone.clone()); tokio::select! { _ = run_hand => {}, _val = rx.recv() => { match _val.unwrap() { // 1 - File-dependency handling error -> terminating (after waiting) 1 => { if is_active(&proc.name).await { error!("File-dependency handling error: Terminating {} process ..." , &proc.name); terminate_process(&proc.name).await; tokio::time::sleep(Duration::from_millis(100)).await; } return; }, // 2 - File-dependency handling error -> holding (after waiting) 2 => { if !is_frozen(&proc.name).await { error!("File-dependency handling error: Freezing {} process ..." , &proc.name); freeze_process(&proc.name).await; tokio::time::sleep(Duration::from_millis(100)).await; } }, // 3 - Running process error 3 => { error!("Error due to starting {} process", &proc.name); break; }, // 4 - Timeout of waiting service-dependency -> staying (after waiting) 4 => { // warn!("Timeout of waiting service-dependency: Ignoring on {} process ..." , &proc.name); tokio::time::sleep(Duration::from_millis(100)).await; }, // 5 - Timeout of waiting service-dependency -> terminating (after waiting) 5 => { if is_active(&proc.name).await { error!("Timeout of waiting service-dependency: Terminating {} process ..." , &proc.name); terminate_process(&proc.name).await; tokio::time::sleep(Duration::from_millis(1000)).await; } }, // 6 - Timeout of waiting service-dependency -> holding (after waiting) 6 => { // println!("holding {}-{}", proc.name, is_active(&proc.name).await); if !is_frozen(&proc.name).await { error!("Timeout of waiting service-dependency: Freezing {} process ..." , &proc.name); freeze_process(&proc.name).await; tokio::time::sleep(Duration::from_secs(1)).await; } }, // // 7 - File-dependency change -> terminating (after check) 7 => { error!("File-dependency warning (file changed). Terminating {} process...", &proc.name); terminate_process(&proc.name).await; tokio::time::sleep(Duration::from_millis(100)).await; return; }, // // 8 - File-dependency change -> restarting (after check) 8 => { warn!("File-dependency warning (file changed). Restarting {} process...", &proc.name); let _ = restart_process(&proc.name, &proc.path).await; tokio::time::sleep(Duration::from_millis(100)).await; }, // // 9 - File-dependency change -> staying (after check) 9 => { // no need to trash logs warn!("File-dependency warning (file changed). Ignoring event on {} process...", &proc.name); tokio::time::sleep(Duration::from_millis(100)).await; }, // 10 - Process unfreaze call via file handler (or service handler) 10 | 11 => { if is_frozen(&proc.name).await { warn!("Unfreezing process {} call...", &proc.name); unfreeze_process(&proc.name).await; } tokio::time::sleep(Duration::from_millis(100)).await; }, // 11 - Process unfreaze call via service handler // 11 => { // if is_frozen(&proc.name).await { // warn!("Unfreezing process {} call...", &proc.name); // unfreeze_process(&proc.name).await; // } // tokio::time::sleep(Duration::from_millis(100)).await; // }, // 101 - Impermissible trigger values in JSON 101 => { error!("Impermissible trigger values in JSON in {}'s block. Killing thread...", proc.name); if is_active(&proc.name).await { terminate_process(&proc.name).await; } break; }, // 111 - global thread termination with killing current child in a face // of a current process 111 => { warn!("Terminating {}'s child processes...", &proc.name); match is_active(&proc.name).await { true => { terminate_process(&proc.name).await; }, false => { log::info!("Process {} is already terminated!", proc.name); }, } break; }, _ => {}, } }, } tokio::task::yield_now().await; } tokio::task::yield_now().await; } // check process status daemon pub async fn running_handler( prc: Arc, tx: Arc>, watchers: Arc>>, ) { // services and files check (once) let files_check = file_handler( &prc.name, &prc.dependencies.files, tx.clone(), watchers.clone(), ); let services_check = service_handler(&prc.name, &prc.dependencies.services, tx.clone()); let res = join!(files_check, services_check); // if inactive -> spawn checks -> active is true if !is_active(&prc.name).await && res.0.is_ok() && res.1.is_ok() { if start_process(&prc.name, &prc.path).await.is_err() { tx.send(3).await.unwrap(); return; } } // if frozen -> spawn checks -> unfreeze is true else if is_frozen(&prc.name).await && res.0.is_ok() && res.1.is_ok() { tx.send(10).await.unwrap(); return; } // tokio::time::sleep(Duration::from_millis(100)).await; tokio::task::yield_now().await; } // todo: cmd across cat /proc/self/mountinfo | grep "/docker/containers/" | head -1 | awk -F '/' '{print $5}' pub fn get_container_id() -> Option { match Command::new(GET_ID_CMD).output() { Ok(output) => { if !output.status.success() { return None; } let id = String::from_utf8_lossy(&output.stdout).to_string(); if id.is_empty() { return None; } Some(String::from_utf8_lossy(&output.stdout).to_string()) } Err(er) => { println!("failed( : {}", er); None } } }