128 lines
3.3 KiB
Rust
128 lines
3.3 KiB
Rust
//#![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<Tz: TimeZone> From<DateTime<Tz>> for TimeHM {
|
|
fn from(value: DateTime<Tz>) -> 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<Vec<String>>,
|
|
start: TimeHM,
|
|
end: TimeHM,
|
|
delay: u32,
|
|
}
|
|
|
|
impl Config {
|
|
fn read<P: AsRef<Path>>(path: P) -> Result<Self, String> {
|
|
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<PathBuf, String> {
|
|
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> = 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()
|
|
}
|