//#![windows_subsystem = "windows"] use chrono::prelude::*; use chrono::{DateTime, Local, TimeZone}; use serde::Deserialize; use std::path::Path; use std::{thread, time::Duration}; use sysinfo::{System, SystemExt}; use std::{env, fs, path::PathBuf, process::Command}; #[derive(Deserialize, Default, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)] struct TimeHM { hour: u8, minute: u8, } impl From> for TimeHM { fn from(value: DateTime) -> TimeHM { TimeHM { hour: value.hour() as u8, minute: value.minute() as u8, } } } #[derive(Deserialize, Default)] struct Config { command: String, target: String, workdir: String, args: Option>, start: TimeHM, end: TimeHM, delay: u32, } impl Config { fn read>(path: P) -> Result { let data = fs::read_to_string(path).map_err(|e| format!("can't read config: {:?}", e))?; toml::from_str(&data).map_err(|e| format!("can't parse config: {:?}", e)) } fn file_location() -> Result { let res = env::current_exe() .map_err(|e| format!("can't get current exe path: {:?}", e))? .with_extension("toml"); Ok(res) } fn get() -> Self { let path = Config::file_location(); if let Err(_e) = path { //println!("{}", _e); return Config::default(); } let path = path.unwrap(); let cfg = Config::read(path); match cfg { Err(_e) => { //println!("{}", _e); Config::default() } Ok(cfg) => cfg, } } fn target_name(&self) -> String { if !self.target.is_empty() { self.target.clone() } else { PathBuf::from(self.command.clone()) .file_name() .unwrap() .to_os_string() .into_string() .unwrap() } } fn is_in_time(&self, value: TimeHM) -> bool { dbg!(value); dbg!(self.start <= value && value <= self.end); self.start <= value && value <= self.end } fn is_active(&self) -> bool { let now: DateTime = Local::now(); self.is_in_time(now.into()) } fn sleep(&self) { thread::sleep(Duration::from_secs(self.delay.into())); } fn is_target_alive(&self) -> bool { let name = self.target_name(); dbg!(&name); let sp = System::new_all(); let procs = sp.processes_by_exact_name(&name); let count = procs.count(); dbg!(count); count > 0 } fn relaunch_target(&self) { dbg!(&self.command); let mut cmd = Command::new(&self.command); cmd.current_dir(&self.workdir); if let Some(args) = &self.args { cmd.args(args); } let _res = cmd.spawn(); } fn is_valid(&self) -> bool { (!self.command.is_empty()) && self.delay > 0 } fn main_loop(self) { dbg!(self.is_valid()); if !self.is_valid() { return; } loop { if self.is_active() && !self.is_target_alive() { self.relaunch_target(); } self.sleep(); } } } fn main() { Config::get().main_loop() }