//! TOML configuration file use anyhow::Context; use serde::{Deserialize, Serialize}; use tokio::{fs, io}; /// Path to the configuration file. Currently a file in the working directory. const CONFIG_FILENAME: &str = "mullvad-release.toml"; #[derive(Default, Deserialize, Serialize)] pub struct Config { /// URLs to use as bases for installers. /// Files are expected at (example): `//MullvadVPN-.exe`. pub base_urls: Vec, } impl Config { /// Try to load [CONFIG_FILENAME] from the working directory, create one if it does not exist. pub async fn load_or_create() -> anyhow::Result { match fs::read_to_string(CONFIG_FILENAME).await { Ok(toml_str) => toml::from_str(&toml_str).context("Failed to parse TOML file"), Err(err) if err.kind() == io::ErrorKind::NotFound => { eprintln!("Creating default {CONFIG_FILENAME}"); let self_ = Self::default(); self_.save().await?; Ok(self_) } Err(err) => Err(err).with_context(|| format!("Failed to read {CONFIG_FILENAME}")), } } async fn save(&self) -> anyhow::Result<()> { let toml_str = toml::to_string_pretty(self).expect("Expected valid toml"); fs::write(CONFIG_FILENAME, toml_str.as_bytes()) .await .with_context(|| format!("Failed to save {CONFIG_FILENAME}")) } }