Basic config file reading
This commit is contained in:
parent
cd106914a1
commit
24fe803aaa
9 changed files with 161 additions and 8 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
target/
|
target/
|
||||||
|
subtails.toml
|
||||||
|
|
54
Cargo.lock
generated
54
Cargo.lock
generated
|
@ -1161,6 +1161,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -1287,6 +1296,8 @@ dependencies = [
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1419,6 +1430,40 @@ dependencies = [
|
||||||
"tokio",
|
"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]]
|
[[package]]
|
||||||
name = "tower-service"
|
name = "tower-service"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -1746,6 +1791,15 @@ version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.6.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "write16"
|
name = "write16"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
|
@ -7,3 +7,5 @@ edition = "2021"
|
||||||
crossterm = "0.28.1"
|
crossterm = "0.28.1"
|
||||||
ratatui = "0.29.0"
|
ratatui = "0.29.0"
|
||||||
reqwest = "0.12.9"
|
reqwest = "0.12.9"
|
||||||
|
serde = { version = "1.0.215", features = ["derive"] }
|
||||||
|
toml = "0.8.19"
|
||||||
|
|
21
src/config/errors.rs
Normal file
21
src/config/errors.rs
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/config/file.rs
Normal file
35
src/config/file.rs
Normal file
|
@ -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<Table, Error> {
|
||||||
|
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<Settings, Error> {
|
||||||
|
let toml_table = read_config()?;
|
||||||
|
let mut settings: Settings = toml_table.try_into()?;
|
||||||
|
validate_config(&mut settings)?;
|
||||||
|
return Ok(settings);
|
||||||
|
}
|
|
@ -1,9 +1,28 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use file::parse_config;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::utils::Error;
|
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<Arc<Settings>, Error> {
|
pub fn init() -> Result<Arc<Settings>, Error> {
|
||||||
unimplemented!()
|
let settings = parse_config()?;
|
||||||
|
Ok(Arc::new(settings))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod errors;
|
||||||
|
mod file;
|
||||||
|
mod validate;
|
||||||
|
|
19
src/config/validate.rs
Normal file
19
src/config/validate.rs
Normal file
|
@ -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!()
|
||||||
|
}
|
12
src/main.rs
12
src/main.rs
|
@ -1,7 +1,6 @@
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
use std::error::Error;
|
use std::sync::mpsc::{channel, Receiver};
|
||||||
use std::sync::mpsc::channel;
|
|
||||||
|
|
||||||
mod audio;
|
mod audio;
|
||||||
mod config;
|
mod config;
|
||||||
|
@ -9,7 +8,7 @@ mod player;
|
||||||
mod ssonic;
|
mod ssonic;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn init() -> Result<(), Box<dyn Error>> {
|
fn init() -> Result<Receiver<utils::Error>, utils::Error> {
|
||||||
let settings = config::init()?;
|
let settings = config::init()?;
|
||||||
let (error_in, error_out) = channel();
|
let (error_in, error_out) = channel();
|
||||||
let audio_event_chan = audio::init(settings.clone(), error_in.clone())?;
|
let audio_event_chan = audio::init(settings.clone(), error_in.clone())?;
|
||||||
|
@ -21,12 +20,15 @@ fn init() -> Result<(), Box<dyn Error>> {
|
||||||
error_in.clone(),
|
error_in.clone(),
|
||||||
)?;
|
)?;
|
||||||
player.begin()?;
|
player.begin()?;
|
||||||
Ok(())
|
Ok(error_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match init() {
|
match init() {
|
||||||
Err(_) => exit(1),
|
Err(x) => {
|
||||||
|
eprintln!("{}", x);
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
Ok(_) => exit(0),
|
Ok(_) => exit(0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
pub type Error = Box<dyn std::error::Error>;
|
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
|
|
Loading…
Reference in a new issue