From 24fe803aaa3943f705c0f5c7b771966af3d6321b Mon Sep 17 00:00:00 2001 From: Muaz Ahmad Date: Mon, 25 Nov 2024 16:16:43 +0500 Subject: [PATCH] Basic config file reading --- .gitignore | 1 + Cargo.lock | 54 ++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/config/errors.rs | 21 ++++++++++++++++ src/config/file.rs | 35 +++++++++++++++++++++++++++ src/config/mod.rs | 23 ++++++++++++++++-- src/config/validate.rs | 19 +++++++++++++++ src/main.rs | 12 ++++++---- src/utils.rs | 2 +- 9 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 src/config/errors.rs create mode 100644 src/config/file.rs create mode 100644 src/config/validate.rs diff --git a/.gitignore b/.gitignore index 2f7896d..401267f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target/ +subtails.toml diff --git a/Cargo.lock b/Cargo.lock index d73e400..6512393 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1161,6 +1161,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1287,6 +1296,8 @@ dependencies = [ "crossterm", "ratatui", "reqwest", + "serde", + "toml", ] [[package]] @@ -1419,6 +1430,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.3" @@ -1746,6 +1791,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index da77b96..035daa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,5 @@ edition = "2021" crossterm = "0.28.1" ratatui = "0.29.0" reqwest = "0.12.9" +serde = { version = "1.0.215", features = ["derive"] } +toml = "0.8.19" diff --git a/src/config/errors.rs b/src/config/errors.rs new file mode 100644 index 0000000..c2f1f59 --- /dev/null +++ b/src/config/errors.rs @@ -0,0 +1,21 @@ +use std::fmt::Display; + +#[derive(Debug)] +pub enum ConfigError { + ConfigNotFound, + MissingConfigValue(&'static str), +} + +impl std::error::Error for ConfigError {} + +impl Display for ConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ConfigNotFound => write!( + f, + "Config File was not found in either the current directory or ~/.config." + ), + Self::MissingConfigValue(var_name) => write!(f, "Neither the Env variable \"{}\" was set, nor the equivalent field in the config file was found.", var_name) + } + } +} diff --git a/src/config/file.rs b/src/config/file.rs new file mode 100644 index 0000000..54fdf9e --- /dev/null +++ b/src/config/file.rs @@ -0,0 +1,35 @@ +use std::fs::{exists, read_to_string}; + +use toml::{de::from_str, Table}; + +use crate::{config::errors::ConfigError, utils::Error}; + +use super::{validate::validate_config, Settings}; + +const CONFIG_PATHS: [&str; 2] = ["./", "~/.config/"]; +const CONFIG_FILENAME: &str = "subtails.toml"; + +fn read_config() -> Result { + let mut filename = String::new(); + let mut config_found = false; + for path in CONFIG_PATHS.iter() { + filename = format!("{}{}", path, CONFIG_FILENAME); + if exists(&filename)? { + config_found = true; + break; + } + } + if !config_found { + return Err(Box::new(ConfigError::ConfigNotFound)); + }; + let raw_config = read_to_string(filename)?; + let toml_table = from_str(raw_config.as_str())?; + Ok(toml_table) +} + +pub fn parse_config() -> Result { + let toml_table = read_config()?; + let mut settings: Settings = toml_table.try_into()?; + validate_config(&mut settings)?; + return Ok(settings); +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 20fb513..76d294b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,9 +1,28 @@ use std::sync::Arc; +use file::parse_config; +use serde::Deserialize; + use crate::utils::Error; -pub struct Settings {} +#[derive(Deserialize)] +pub struct Settings { + pub subsonic: Subsonic, +} + +#[derive(Deserialize)] +pub struct Subsonic { + pub server_address: String, + pub username: String, + #[serde(default)] + pub password: String, // Only optional in file, will otherwise pull from Env var +} pub fn init() -> Result, Error> { - unimplemented!() + let settings = parse_config()?; + Ok(Arc::new(settings)) } + +mod errors; +mod file; +mod validate; diff --git a/src/config/validate.rs b/src/config/validate.rs new file mode 100644 index 0000000..cd079e4 --- /dev/null +++ b/src/config/validate.rs @@ -0,0 +1,19 @@ +use std::env::var; + +use crate::{config::errors::ConfigError, utils::Error}; + +use super::Settings; + +pub fn validate_config(settings: &mut Settings) -> Result<(), Error> { + if settings.subsonic.password == "" { + settings.subsonic.password = match var("SUBSONIC_PASSWORD") { + Ok(pass) => pass, + Err(_) => { + return Err(Box::new(ConfigError::MissingConfigValue( + "SUBSONIC_PASSWORD", + ))) + } + } + } + unimplemented!() +} diff --git a/src/main.rs b/src/main.rs index ed1e061..0fa00d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use std::process::exit; -use std::error::Error; -use std::sync::mpsc::channel; +use std::sync::mpsc::{channel, Receiver}; mod audio; mod config; @@ -9,7 +8,7 @@ mod player; mod ssonic; mod utils; -fn init() -> Result<(), Box> { +fn init() -> Result, utils::Error> { let settings = config::init()?; let (error_in, error_out) = channel(); let audio_event_chan = audio::init(settings.clone(), error_in.clone())?; @@ -21,12 +20,15 @@ fn init() -> Result<(), Box> { error_in.clone(), )?; player.begin()?; - Ok(()) + Ok(error_out) } fn main() { match init() { - Err(_) => exit(1), + Err(x) => { + eprintln!("{}", x); + exit(1) + } Ok(_) => exit(0), }; } diff --git a/src/utils.rs b/src/utils.rs index 42de187..f34e60e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1 +1 @@ -pub type Error = Box; +pub type Error = Box;