Files
laika/src/main.rs
2023-04-17 12:09:26 +03:00

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()
}