about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-24 11:27:31 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-24 11:45:28 +0200
commit43522ef7898c60ffd3e7c5ff056fd765635bbc5c (patch)
tree4c9bea495ca8e2ba779d6c9fc952f0aca7770c72
parentfeat(videos): Allow limiting the number of videos to show (diff)
downloadyt-43522ef7898c60ffd3e7c5ff056fd765635bbc5c.tar.gz
yt-43522ef7898c60ffd3e7c5ff056fd765635bbc5c.zip
fix(config): Check for wrong keys in the config file
-rw-r--r--src/config/default.rs4
-rw-r--r--src/config/definitions.rs59
-rw-r--r--src/config/file_system.rs91
-rw-r--r--src/config/mod.rs5
4 files changed, 105 insertions, 54 deletions
diff --git a/src/config/default.rs b/src/config/default.rs
index e99b255..8eedb18 100644
--- a/src/config/default.rs
+++ b/src/config/default.rs
@@ -54,13 +54,13 @@ pub mod select {
 }
 
 pub mod watch {
-    pub fn local_comments_length() -> i64 {
+    pub fn local_comments_length() -> usize {
         1000
     }
 }
 
 pub mod update {
-    pub fn max_backlog() -> i64 {
+    pub fn max_backlog() -> u32 {
         20
     }
 }
diff --git a/src/config/definitions.rs b/src/config/definitions.rs
new file mode 100644
index 0000000..d37e6da
--- /dev/null
+++ b/src/config/definitions.rs
@@ -0,0 +1,59 @@
+// yt - A fully featured command line YouTube client
+//
+// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This file is part of Yt.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+use std::path::PathBuf;
+
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct ConfigFile {
+    pub select: Option<SelectConfig>,
+    pub watch: Option<WatchConfig>,
+    pub paths: Option<PathsConfig>,
+    pub download: Option<DownloadConfig>,
+    pub update: Option<UpdateConfig>,
+}
+
+#[derive(Debug, Deserialize, PartialEq, Clone, Copy)]
+#[serde(deny_unknown_fields)]
+pub struct UpdateConfig {
+    pub max_backlog: Option<u32>,
+}
+
+#[derive(Debug, Deserialize, PartialEq, Clone)]
+#[serde(deny_unknown_fields)]
+pub struct DownloadConfig {
+    /// This will then be converted to an u64
+    pub max_cache_size: Option<String>,
+}
+
+#[derive(Debug, Deserialize, PartialEq, Clone)]
+#[serde(deny_unknown_fields)]
+pub struct SelectConfig {
+    pub playback_speed: Option<f64>,
+    pub subtitle_langs: Option<String>,
+}
+
+#[derive(Debug, Deserialize, PartialEq, Clone, Copy)]
+#[serde(deny_unknown_fields)]
+pub struct WatchConfig {
+    pub local_comments_length: Option<usize>,
+}
+
+#[derive(Debug, Deserialize, PartialEq, Clone)]
+#[serde(deny_unknown_fields)]
+pub struct PathsConfig {
+    pub download_dir: Option<PathBuf>,
+    pub mpv_config_path: Option<PathBuf>,
+    pub mpv_input_path: Option<PathBuf>,
+    pub database_path: Option<PathBuf>,
+    pub last_selection_path: Option<PathBuf>,
+}
diff --git a/src/config/file_system.rs b/src/config/file_system.rs
index 396b854..fd3a8d8 100644
--- a/src/config/file_system.rs
+++ b/src/config/file_system.rs
@@ -19,17 +19,34 @@ use std::{fs::read_to_string, path::PathBuf};
 
 use anyhow::{Context, Result};
 use bytes::Bytes;
-use toml::Table;
 
 macro_rules! get {
-    ($default:path, $config:expr, $get_fn:ident, $key_one:expr, $($keys:expr),*) => {
-        try_get!{@default $default, $config, $get_fn, $key_one, $($keys),*}
-             .with_context(|| format!("Failed to parse '{}' as a '{}'", stringify!($key_one), stringify!($get_fn)))?
+    ($default:path, $config:expr, $key_one:ident, $($keys:ident),*) => {
+        {
+            let maybe_value = get!{@option $config, $key_one, $($keys),*};
+            if let Some(value) = maybe_value {
+                value
+            } else {
+                $default().to_owned()
+            }
+        }
+    };
+
+    (@option $config:expr, $key_one:ident, $($keys:ident),*) => {
+        if let Some(key) = $config.$key_one.clone() {
+            get!{@option key, $($keys),*}
+        } else {
+            None
+        }
+    };
+    (@option $config:expr, $key_one:ident) => {
+        $config.$key_one
     };
-    (@path_if_none $config:expr, $option_default:expr, $default:path, $key_one:expr, $($keys:expr),*) => {
+
+    (@path_if_none $config:expr, $option_default:expr, $default:path, $key_one:ident, $($keys:ident),*) => {
         {
-            let maybe_download_dir =
-                try_get! {@option $config, as_str, $key_one, $($keys),*};
+            let maybe_download_dir: Option<PathBuf> =
+                get! {@option $config, $key_one, $($keys),*};
 
             let down_dir = if let Some(dir) = maybe_download_dir {
                 PathBuf::from(dir)
@@ -44,35 +61,10 @@ macro_rules! get {
             create_path(down_dir)?
         }
     };
-    (@path $config:expr, $default:path, $key_one:expr, $($keys:expr),*) => {
+    (@path $config:expr, $default:path, $key_one:ident, $($keys:ident),*) => {
         get! {@path_if_none $config, None, $default, $key_one, $($keys),*}
     };
 }
-macro_rules! try_get {
-    (@option $config:expr, $get_fn:ident, $key_one:expr, $($keys:expr),*) => {
-        $config.get($key_one).map(|val| {
-            try_get! {@option val, $get_fn, $($keys),*}
-        }).flatten().flatten()
-    };
-    (@option $config:expr, $get_fn:ident, $key_one:expr) => {
-        $config.get($key_one).map(|val| val.$get_fn())
-    };
-
-    (@default $default:path, $config:expr, $get_fn:ident, $key_one:expr, $($keys:expr),*) => {
-        if let Some(a) = $config.get($key_one) {
-            try_get! {@default $default, a, $get_fn, $($keys),*}
-        } else {
-            Some($default())
-        }
-    };
-    (@default $default:path, $config:expr, $get_fn:ident, $key_one:expr) => {
-        if let Some(a) = $config.get($key_one) {
-            a.$get_fn()
-        } else {
-            Some($default())
-        }
-    };
-}
 
 impl Config {
     pub fn from_config_file(
@@ -83,39 +75,36 @@ impl Config {
             .map(|val| Ok(val))
             .unwrap_or_else(|| -> Result<_> { paths::config_path() })?;
 
-        let config: Table = read_to_string(config_file_path).unwrap_or("".to_owned())
-            .parse()
-            .context("Failed to parse the config file as toml")?;
+        let config: super::definitions::ConfigFile =
+            toml::from_str(&read_to_string(config_file_path).unwrap_or("".to_owned()))
+                .context("Failed to parse the config file as toml")?;
 
         Ok(Self {
             select: SelectConfig {
-                playback_speed: get! {select::playback_speed, config, as_float, "select", "playback_speed"},
-                subtitle_langs:
-                    get! {select::subtitle_langs, config, as_str, "select", "subtitle_langs"}
-                        .to_owned(),
+                playback_speed: get! {select::playback_speed, config, select, playback_speed},
+                subtitle_langs: get! {select::subtitle_langs, config, select, subtitle_langs},
             },
             watch: WatchConfig {
-                local_comments_length: get! {watch::local_comments_length, config, as_integer, "watch", "local_comments_length"}
-                    as usize,
+                local_comments_length: get! {watch::local_comments_length, config, watch, local_comments_length},
             },
             update: UpdateConfig {
-                max_backlog: get! {update::max_backlog, config, as_integer, "update", "max_backlog"}
-                    as u32,
+                max_backlog: get! {update::max_backlog, config, update, max_backlog},
             },
             paths: PathsConfig {
-                download_dir: get! {@path config, paths::download_dir, "paths", "download_dir"},
-                mpv_config_path: get! {@path config, paths::mpv_config_path, "paths", "mpv_config_path"},
-                mpv_input_path: get! {@path config, paths::mpv_input_path, "paths", "mpv_input_path"},
-                database_path: get! {@path_if_none config, db_path, paths::database_path, "paths", "database_path"},
-                last_selection_path: get! {@path config, paths::last_selection_path, "paths", "last_selection_path"},
+                download_dir: get! {@path config, paths::download_dir, paths, download_dir},
+                mpv_config_path: get! {@path config, paths::mpv_config_path, paths, mpv_config_path},
+                mpv_input_path: get! {@path config, paths::mpv_input_path, paths, mpv_input_path},
+                database_path: get! {@path_if_none config, db_path, paths::database_path, paths, database_path},
+                last_selection_path: get! {@path config, paths::last_selection_path, paths, last_selection_path},
             },
             download: DownloadConfig {
                 max_cache_size: {
-                    let bytes_str = get! {download::max_cache_size, config, as_str, "download", "max_cache_path"};
+                    let bytes_str: String =
+                        get! {download::max_cache_size, config, download, max_cache_size};
                     let number: Bytes = bytes_str
                         .parse()
                         .context("Failed to parse max_cache_size")?;
-                    number.as_u64()
+                    number
                 },
             },
         })
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 26d27eb..3d0d0b5 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -10,7 +10,10 @@
 
 use std::path::PathBuf;
 
+use bytes::Bytes;
+
 mod default;
+mod definitions;
 pub mod file_system;
 
 pub struct Config {
@@ -24,7 +27,7 @@ pub struct UpdateConfig {
     pub max_backlog: u32,
 }
 pub struct DownloadConfig {
-    pub max_cache_size: u64,
+    pub max_cache_size: Bytes,
 }
 pub struct SelectConfig {
     pub playback_speed: f64,