use crate::{Result, TraceSrc};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf, sync::Arc};
use tracing::{error, trace, warn};
const GLOBAL_SETTINGS_FILE_NAME: &str = "dioxus/settings.toml";
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub(crate) struct CliSettings {
pub(crate) always_hot_reload: Option<bool>,
pub(crate) always_open_browser: Option<bool>,
pub(crate) always_on_top: Option<bool>,
#[serde(default = "default_wsl_file_poll_interval")]
pub(crate) wsl_file_poll_interval: Option<u16>,
pub(crate) no_downloads: Option<bool>,
}
impl CliSettings {
pub(crate) fn load() -> Arc<Self> {
static SETTINGS: Lazy<Arc<CliSettings>> =
Lazy::new(|| Arc::new(CliSettings::from_global().unwrap_or_default()));
SETTINGS.clone()
}
pub(crate) fn from_global() -> Option<Self> {
let Some(path) = dirs::data_local_dir() else {
warn!("failed to get local data directory, some config keys may be missing");
return None;
};
let path = path.join(GLOBAL_SETTINGS_FILE_NAME);
let Some(data) = fs::read_to_string(path).ok() else {
trace!("failed to read `{}` config file", GLOBAL_SETTINGS_FILE_NAME);
return None;
};
let data = toml::from_str::<CliSettings>(&data).ok();
if data.is_none() {
warn!(
"failed to parse `{}` config file",
GLOBAL_SETTINGS_FILE_NAME
);
}
data
}
pub(crate) fn save(&self) -> Result<()> {
let path = Self::get_settings_path().ok_or_else(|| {
error!(dx_src = ?TraceSrc::Dev, "failed to get settings path");
anyhow::anyhow!("failed to get settings path")
})?;
let data = toml::to_string_pretty(&self).map_err(|e| {
error!(dx_src = ?TraceSrc::Dev, ?self, "failed to parse config into toml");
anyhow::anyhow!("failed to parse config into toml: {e}")
})?;
let parent_path = path.parent().unwrap();
if let Err(e) = fs::create_dir_all(parent_path) {
error!(
dx_src = ?TraceSrc::Dev,
?data,
?path,
"failed to create directories for settings file"
);
return Err(
anyhow::anyhow!("failed to create directories for settings file: {e}").into(),
);
}
let result = fs::write(&path, data.clone());
if let Err(e) = result {
error!(?data, ?path, "failed to save global cli settings");
return Err(anyhow::anyhow!("failed to save global cli settings: {e}").into());
}
Ok(())
}
pub(crate) fn get_settings_path() -> Option<PathBuf> {
let Some(path) = dirs::data_local_dir() else {
warn!("failed to get local data directory, some config keys may be missing");
return None;
};
Some(path.join(GLOBAL_SETTINGS_FILE_NAME))
}
pub(crate) fn modify_settings(with: impl FnOnce(&mut CliSettings)) -> Result<()> {
let mut _settings = CliSettings::load();
let settings: &mut CliSettings = Arc::make_mut(&mut _settings);
with(settings);
settings.save()?;
Ok(())
}
pub(crate) fn prefer_no_downloads() -> bool {
if cfg!(feature = "no-downloads") {
return true;
}
if std::env::var("NO_DOWNLOADS").is_ok() {
return true;
}
CliSettings::load().no_downloads.unwrap_or_default()
}
}
fn default_wsl_file_poll_interval() -> Option<u16> {
Some(2)
}