From 5866076b216bc7a2d02c6519004fa48d364f3c67 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Mon, 8 May 2017 22:47:15 -0700 Subject: [PATCH] Use serde to parse config file --- Cargo.lock | 8 +- Cargo.toml | 2 +- src/collection.rs | 11 +-- src/config.rs | 189 +++++++++++----------------------------------- src/ddns.rs | 2 +- src/errors.rs | 2 + 6 files changed, 51 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 402d1fb..1ae0f83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ dependencies = [ "shell32-sys 0.1.1 (git+https://github.com/retep998/winapi-rs?branch=0.2)", "sqlite 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "staticfile 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "user32-sys 0.2.0 (git+https://github.com/retep998/winapi-rs?branch=0.2)", "uuid 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1070,10 +1070,10 @@ dependencies = [ [[package]] name = "toml" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1334,7 +1334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af" -"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" +"checksum toml 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3063405db158de3dce8efad5fc89cf1baffb9501a3647dc9505ba109694ce31f" "checksum traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07eaeb7689bb7fca7ce15628319635758eda769fed481ecfe6686ddef2600616" "checksum traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9dc23794ff47c95882da6f9d15de9a6be14987760a28cc0aafb40b7675ef09d8" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" diff --git a/Cargo.toml b/Cargo.toml index 7ae9ab7..1037728 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ serde_derive = "1.0.2" serde_json = "1.0.2" sqlite = "0.23.0" staticfile = "0.3.0" -toml = "0.2" +toml = "0.4" url = "1.2.0" winapi = { git = "https://github.com/retep998/winapi-rs", branch="0.2" } diff --git a/src/collection.rs b/src/collection.rs index be762eb..eab4e5d 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -9,21 +9,12 @@ use index::*; use vfs::*; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize)] pub struct User { name: String, password: String, } -impl User { - pub fn new(name: String, password: String) -> User { - User { - name: name, - password: password, - } - } -} - pub struct Collection { vfs: Arc, users: Vec, diff --git a/src/config.rs b/src/config.rs index 4e1915d..f987d0e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use regex; +use regex::Regex; use std::fs; use std::io::Read; use std::path; @@ -13,19 +13,22 @@ use vfs::VfsConfig; const DEFAULT_CONFIG_FILE_NAME: &'static str = "polaris.toml"; const INDEX_FILE_NAME: &'static str = "index.sqlite"; -const CONFIG_SECRET: &'static str = "auth_secret"; -const CONFIG_MOUNT_DIRS: &'static str = "mount_dirs"; -const CONFIG_MOUNT_DIR_NAME: &'static str = "name"; -const CONFIG_MOUNT_DIR_SOURCE: &'static str = "source"; -const CONFIG_USERS: &'static str = "users"; -const CONFIG_USER_NAME: &'static str = "name"; -const CONFIG_USER_PASSWORD: &'static str = "password"; -const CONFIG_ALBUM_ART_PATTERN: &'static str = "album_art_pattern"; -const CONFIG_INDEX_SLEEP_DURATION: &'static str = "reindex_every_n_seconds"; -const CONFIG_DDNS: &'static str = "ydns"; -const CONFIG_DDNS_HOST: &'static str = "host"; -const CONFIG_DDNS_USERNAME: &'static str = "username"; -const CONFIG_DDNS_PASSWORD: &'static str = "password"; + +#[derive(Deserialize)] +struct MountDir { + pub name: String, + pub source: String, +} + +#[derive(Deserialize)] +struct UserConfig { + pub auth_secret: String, + pub album_art_pattern: Option, + pub reindex_every_n_seconds: Option, + pub mount_dirs: Vec, + pub users: Vec, + pub ydns: Option, +} pub struct Config { pub secret: String, @@ -48,154 +51,46 @@ impl Config { }; println!("Config file path: {}", config_path.to_string_lossy()); + // Parse user config let mut config_file = fs::File::open(config_path)?; let mut config_file_content = String::new(); config_file.read_to_string(&mut config_file_content)?; - let parsed_config = toml::Parser::new(config_file_content.as_str()).parse(); - let parsed_config = parsed_config - .ok_or("Could not parse config as valid TOML")?; + let user_config = toml::de::from_str::(config_file_content.as_str())?; - let mut config = Config { - secret: String::new(), - vfs: VfsConfig::new(), - users: Vec::new(), - index: IndexConfig::new(), - ddns: None, - }; - - config.parse_secret(&parsed_config)?; - config.parse_index_sleep_duration(&parsed_config)?; - config.parse_mount_points(&parsed_config)?; - config.parse_users(&parsed_config)?; - config.parse_album_art_pattern(&parsed_config)?; - config.parse_ddns(&parsed_config)?; - - let mut index_path = utils::get_cache_root()?; - index_path.push(INDEX_FILE_NAME); - config.index.path = index_path; - - Ok(config) - } - - fn parse_secret(&mut self, source: &toml::Table) -> Result<()> { - self.secret = source - .get(CONFIG_SECRET) - .and_then(|s| s.as_str()) - .map(|s| s.to_owned()) - .ok_or("Could not parse config secret")?; - Ok(()) - } - - fn parse_index_sleep_duration(&mut self, source: &toml::Table) -> Result<()> { - let sleep_duration = match source.get(CONFIG_INDEX_SLEEP_DURATION) { - Some(s) => s, - None => return Ok(()), - }; - let sleep_duration = match sleep_duration { - &toml::Value::Integer(s) => s as u64, - _ => bail!("Could not parse index sleep duration"), - }; - self.index.sleep_duration = sleep_duration; - Ok(()) - } - - fn parse_album_art_pattern(&mut self, source: &toml::Table) -> Result<()> { - let pattern = match source.get(CONFIG_ALBUM_ART_PATTERN) { - Some(s) => s, - None => return Ok(()), - }; - let pattern = match pattern { - &toml::Value::String(ref s) => s, - _ => bail!("Could not parse album art pattern"), - }; - self.index.album_art_pattern = Some(regex::Regex::new(pattern)?); - Ok(()) - } - - fn parse_users(&mut self, source: &toml::Table) -> Result<()> { - let users = match source.get(CONFIG_USERS) { - Some(s) => s, - None => return Ok(()), - }; - - let users = match users { - &toml::Value::Array(ref a) => a, - _ => bail!("Could not parse users array"), - }; - - for user in users { - let name = user.lookup(CONFIG_USER_NAME) - .and_then(|n| n.as_str()) - .ok_or("Could not parse username")?; - let password = user.lookup(CONFIG_USER_PASSWORD) - .and_then(|n| n.as_str()) - .ok_or("Could not parse user password")?; - let user = User::new(name.to_owned(), password.to_owned()); - self.users.push(user); - } - - Ok(()) - } - - fn parse_mount_points(&mut self, source: &toml::Table) -> Result<()> { - let mount_dirs = match source.get(CONFIG_MOUNT_DIRS) { - Some(s) => s, - None => return Ok(()), - }; - - let mount_dirs = match mount_dirs { - &toml::Value::Array(ref a) => a, - _ => bail!("Could not parse mount directories array"), - }; - - for dir in mount_dirs { - let name = dir.lookup(CONFIG_MOUNT_DIR_NAME) - .and_then(|n| n.as_str()) - .ok_or("Could not parse mount directory name")?; - let source = dir.lookup(CONFIG_MOUNT_DIR_SOURCE) - .and_then(|n| n.as_str()) - .ok_or("Could not parse mount directory source")?; - let source = clean_path_string(source); - if self.vfs.mount_points.contains_key(name) { + // Init VFS config + let mut vfs_config = VfsConfig::new(); + for dir in user_config.mount_dirs { + if vfs_config.mount_points.contains_key(&dir.name) { bail!("Conflicting mount directories"); } - self.vfs.mount_points.insert(name.to_owned(), source); + vfs_config.mount_points.insert(dir.name.to_owned(), clean_path_string(dir.source.as_str())); } - Ok(()) - } + // Init Index config + let mut index_config = IndexConfig::new(); + index_config.album_art_pattern = user_config.album_art_pattern.and_then(|s| Regex::new(s.as_str()).ok()); + if let Some(duration) = user_config.reindex_every_n_seconds { + index_config.sleep_duration = duration; + } + let mut index_path = utils::get_cache_root()?; + index_path.push(INDEX_FILE_NAME); + index_config.path = index_path; - fn parse_ddns(&mut self, source: &toml::Table) -> Result<()> { - let ddns = match source.get(CONFIG_DDNS) { - Some(s) => s, - None => return Ok(()), - }; - let ddns = match ddns { - &toml::Value::Table(ref a) => a, - _ => bail!("Could not parse DDNS settings table"), + // Init master config + let config = Config { + secret: user_config.auth_secret, + vfs: vfs_config, + users: user_config.users, + index: index_config, + ddns: user_config.ydns, }; - let host = ddns.get(CONFIG_DDNS_HOST) - .and_then(|n| n.as_str()) - .ok_or("Could not parse DDNS host")?; - let username = ddns.get(CONFIG_DDNS_USERNAME) - .and_then(|n| n.as_str()) - .ok_or("Could not parse DDNS username")?; - let password = ddns.get(CONFIG_DDNS_PASSWORD) - .and_then(|n| n.as_str()) - .ok_or("Could not parse DDNS password")?; - - self.ddns = Some(DDNSConfig { - host: host.to_owned(), - username: username.to_owned(), - password: password.to_owned(), - }); - Ok(()) + Ok(config) } } fn clean_path_string(path_string: &str) -> path::PathBuf { - let separator_regex = regex::Regex::new(r"\\|/").unwrap(); + let separator_regex = Regex::new(r"\\|/").unwrap(); let mut correct_separator = String::new(); correct_separator.push(path::MAIN_SEPARATOR); let path_string = separator_regex.replace_all(path_string, correct_separator.as_str()); diff --git a/src/ddns.rs b/src/ddns.rs index b324c20..8635680 100644 --- a/src/ddns.rs +++ b/src/ddns.rs @@ -6,7 +6,7 @@ use std::io::Read; use std::thread; use std::time; -#[derive(Debug, Clone)] +#[derive(Clone, Debug, Deserialize)] pub struct DDNSConfig { pub host: String, pub username: String, diff --git a/src/errors.rs b/src/errors.rs index 60aac6a..2362079 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -10,6 +10,7 @@ use metaflac; use regex; use sqlite; use std; +use toml; error_chain! { foreign_links { @@ -21,6 +22,7 @@ error_chain! { Image(image::ImageError); Io(std::io::Error); Time(std::time::SystemTimeError); + Toml(toml::de::Error); Regex(regex::Error); SQLite(sqlite::Error); Vorbis(lewton::VorbisError);