use std::collections::HashMap;
use std::path::Path;
use std::process::Child;
use std::sync::mpsc::Receiver;
use std::time::{Duration,SystemTime};
use crate::config::Config;
use crate::Result;
pub mod event_proxy;
mod ignore;
mod process;
use event_proxy::ChangeEvent;
const COLORS: &[&str] = &["bright green", "bright blue", "yellow", "magenta", "bright cyan"];
pub struct Monitor {
config: Config,
receiver: Receiver<ChangeEvent>,
running_processes: Vec<Child>,
last_restart_at: Option<SystemTime>,
ignore: ignore::Ignore
}
impl Monitor {
pub fn new(config: Config, receiver: Receiver<ChangeEvent>) -> Self {
let ignore = ignore::Ignore::new(&config);
Self {
config: config,
ignore: ignore,
receiver: receiver,
running_processes: Vec::new(),
last_restart_at: None
}
}
pub fn run(&mut self) -> Result<()> {
self.spawn_processes()?;
loop {
let event = self.receiver.recv()?;
if self.ignore.should_ignore(&event.path) {
if self.config.in_debug_mode() {
println!("Ignoring changed path {}", event.path.to_string_lossy());
}
continue
}
let restart = match self.last_restart_at {
Some(last_restart_at) => match event.time.duration_since(last_restart_at) {
Ok(time) => time > Duration::from_secs(2),
Err(_) => false,
},
None => true
};
if restart {
println!("Restarting ({} changed)", event.path.to_string_lossy());
self.kill_running_processes()?;
self.run_triggers(event.path.as_path())?;
self.spawn_processes()?;
self.last_restart_at = Some(SystemTime::now());
}
}
}
fn kill_running_processes(&mut self) -> Result<()> {
if self.config.in_debug_mode() {
println!("Killing {} running process(es)", self.running_processes.len());
}
for mut child in self.running_processes.drain(0..) {
child.kill()?;
child.wait()?;
}
Ok(())
}
fn spawn_processes(&mut self) -> Result<()> {
let mut color_i = 0;
for (name, command_config) in self.config.processes.iter() {
if self.config.in_debug_mode() {
println!("Starting process {} '{}'", name, command_config);
}
let child = process::spawn(
&name,
COLORS[color_i],
command_config,
None
)?;
self.running_processes.push(child);
if color_i == COLORS.len() - 1 {
color_i = 0;
} else {
color_i += 1;
}
}
Ok(())
}
fn run_triggers(&self, path: &Path) -> Result<()> {
match self.config.triggers {
Some(ref triggers) => {
let mut env = HashMap::new();
env.insert("TRIGGER_PATH".to_owned(), path.to_string_lossy().to_string());
for (name, command_config) in triggers.iter() {
if self.config.in_debug_mode() {
println!("Running trigger {} '{}'", name, command_config);
}
let mut child = process::spawn(
&name,
"green",
command_config,
Some(env.clone())
)?;
child.wait()?;
}
},
None if self.config.in_debug_mode() => println!("No triggers configured"),
None => ()
}
Ok(())
}
}