use std::{error::Error, path::PathBuf};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Config {
pub watchmen: Watchmen,
pub sock: Sock,
pub socket: Socket,
pub http: Http,
pub redis: Redis,
}
impl Config {
pub fn init(path: Option<String>) -> Result<Config, Box<dyn Error>> {
let path: PathBuf = if let Some(path) = path {
PathBuf::from(path)
} else {
let home: PathBuf = match dirs::home_dir() {
Some(p) => p,
None => return Err("No home dir found".into()),
};
let config_path = home.join(".watchmen/config.toml");
if config_path.exists() {
config_path
} else {
let config_path = PathBuf::from("/etc/watchmen/config.toml");
if config_path.exists() {
config_path
} else {
return Err("No config file found".into());
}
}
};
let config: Config = Config::from(path)?;
Ok(config)
}
}
pub fn get_with_home(input: &str) -> String {
let home_dir = dirs::home_dir().unwrap();
let home_dir_str = home_dir.to_string_lossy().into_owned();
if input.starts_with("$HOME") {
let replaced = input.replace("$HOME", &home_dir_str);
replaced
} else if input.starts_with("~") {
let replaced = input.replace("~", &home_dir_str);
replaced
} else {
input.to_string()
}
}
pub fn get_with_home_path(input: &str) -> PathBuf {
PathBuf::from(get_with_home(input))
}
impl Config {
fn from(s: PathBuf) -> Result<Self, Box<dyn Error>> {
let config_str = std::fs::read_to_string(s)?;
let mut config: Config = toml::from_str(&config_str)?;
if let Some(log_dir) = &config.watchmen.log_dir {
let log_dir = get_with_home_path(log_dir);
if !log_dir.exists() {
std::fs::create_dir_all(&log_dir)?;
}
config.watchmen.log_dir = Some(log_dir.to_str().unwrap().to_string());
}
if let Some(log_level) = &config.watchmen.log_level {
let allowed = ["debug", "info", "warn", "error"];
if !allowed.contains(&log_level.as_str()) {
config.watchmen.log_level = Some("info".to_string());
}
}
if let Some(stdout) = &config.watchmen.stdout {
let stdout = get_with_home_path(stdout);
let parent = stdout.parent().unwrap();
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
config.watchmen.stdout = Some(stdout.to_str().unwrap().to_string());
}
if let Some(stderr) = &config.watchmen.stderr {
let stderr = get_with_home_path(stderr);
let parent = stderr.parent().unwrap();
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
config.watchmen.stderr = Some(stderr.to_str().unwrap().to_string());
}
if let Some(pid) = &config.watchmen.pid {
let pid = get_with_home_path(pid);
let parent = pid.parent().unwrap();
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
config.watchmen.pid = Some(pid.to_str().unwrap().to_string());
}
if config.watchmen.mat.is_none() {
config.watchmen.mat = Some(r"^.*\.(toml|ini|json)$".to_string());
}
let path = get_with_home_path(&config.sock.path);
let parent = path.parent().unwrap();
if !parent.exists() {
std::fs::create_dir_all(parent)?;
}
config.sock.path = path.to_str().unwrap().to_string();
Ok(config)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Watchmen {
pub engine: String,
pub engines: Vec<String>,
pub log_dir: Option<String>,
pub log_level: Option<String>,
pub stdout: Option<String>,
pub stderr: Option<String>,
pub pid: Option<String>,
pub mat: Option<String>,
pub cache: Option<String>,
pub interval: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Sock {
pub path: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Socket {
pub host: String,
pub port: u16,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Http {
pub host: String,
pub port: u16,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Redis {
pub host: String,
pub port: u16,
pub username: String,
pub password: String,
pub queue_index: u8,
pub queue_name: String,
pub subscribe_channels: Vec<String>,
pub subscribe_name: String,
}