use std::cell::RefCell;
use std::env;
use std::path::Path;
use notify::event::DataChange::Any;
use notify::event::ModifyKind::Data;
use notify::EventKind::Modify;
use notify::RecursiveMode::NonRecursive;
use notify::{Event, RecommendedWatcher, Watcher};
use serde_derive::Deserialize;
use tokio::fs;
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
use tracing::debug;
use crate::bar::{Block, Update};
use crate::err::Res;
#[derive(Debug, Deserialize)]
pub struct Config {
pub default: RefCell<Block>,
pub bar: Vec<RefCell<Block>>,
}
impl Default for Config {
fn default() -> Self {
Self {
default: RefCell::new(Block::default()),
bar: Vec::new(),
}
}
}
pub async fn watch_config(tx_updates: UnboundedSender<Update>) -> Res<()> {
debug!("in watch_config thread");
let (tx_watcher, mut rx_watcher) = unbounded_channel::<()>();
let mut config: RecommendedWatcher = Watcher::new(move |e|
if let Ok(event) = e {
if let Event {
kind: Modify(Data(Any)),
paths: ref p,
..
} = event
{
let watched_file = get_config_file("barnine").unwrap();
if p.contains(&std::path::PathBuf::from(watched_file)) {
debug!("got event-->>{:?}", event);
tx_watcher.send(()).unwrap();
}
}
}
)
.unwrap();
debug!(
"about to watch config file:{:?}",
get_config_file("barnine").unwrap()
);
config
.watch(
get_config_file("barnine").unwrap().parent().unwrap(),
NonRecursive,
)
.unwrap();
send_config_update("barnine", tx_updates.clone()).await?;
while let Some(()) = rx_watcher.recv().await {
debug!("got Modify(Data()) recv");
send_config_update("barnine", tx_updates.clone()).await?;
}
Ok(())
}
async fn send_config_update(app_name: &str, tx_updates: UnboundedSender<Update>) -> Res<()> {
let config_file = get_config_file(app_name).unwrap();
if config_file.is_file() {
let toml: String = fs::read_to_string(&config_file).await.unwrap();
let config: Result<Config, _> = toml::from_str(&toml);
tx_updates
.send(Update::Config(Box::new(config.unwrap())))
.unwrap();
tx_updates.send(Update::Redraw).unwrap();
}
Ok(())
}
fn get_config_file(app_name: &str) -> Res<Box<Path>> {
let mut dev_dir = app_name.to_uppercase();
dev_dir.push_str("_DEV_DIR");
let mut config_path = match env::var(&dev_dir) {
Ok(dev_dir) => Path::new(&dev_dir).join(app_name),
Err(_) => match env::var("XDG_CONFIG_HOME") {
Ok(dir) => Path::new(&dir).join(app_name).join(app_name),
Err(_) => match env::var("HOME") {
Ok(dir) => Path::new(&dir)
.join(".config")
.join(app_name)
.join(app_name),
Err(_) => Path::new("/tmp").join(app_name),
},
},
};
config_path.set_extension("toml");
Ok(config_path.into_boxed_path())
}