diff options
author | metamuffin <metamuffin@disroot.org> | 2024-05-29 16:37:44 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-05-29 16:37:44 +0200 |
commit | 886a18e0c67624d0882f04c7f6659bcfee6b4d8d (patch) | |
tree | 32a5389076b199c4e06fa10ce6b54d165d5466c5 /src/config.rs | |
parent | 6cebab912dcf01bbe225c20ec2e7656f61ba160e (diff) | |
download | gnix-886a18e0c67624d0882f04c7f6659bcfee6b4d8d.tar gnix-886a18e0c67624d0882f04c7f6659bcfee6b4d8d.tar.bz2 gnix-886a18e0c67624d0882f04c7f6659bcfee6b4d8d.tar.zst |
refactor filter system
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 126 |
1 files changed, 50 insertions, 76 deletions
diff --git a/src/config.rs b/src/config.rs index e661996..dfc4e73 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,34 +1,38 @@ -use crate::State; -use anyhow::Context; +use crate::{ + filters::{Node, NodeKind}, + State, +}; +use anyhow::{anyhow, Context}; use inotify::{EventMask, Inotify, WatchMask}; use log::{error, info}; use serde::{ de::{value, Error, SeqAccess, Visitor}, Deserialize, Deserializer, Serialize, }; +use serde_yaml::value::TaggedValue; use std::{ - collections::{HashMap, HashSet}, + collections::BTreeMap, fmt, fs::read_to_string, marker::PhantomData, net::SocketAddr, + ops::Deref, path::{Path, PathBuf}, - sync::Arc, + sync::{Arc, RwLock}, }; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Deserialize)] pub struct Config { - #[serde(default = "true_default")] + #[serde(default = "return_true")] pub watch_config: bool, pub http: Option<HttpConfig>, pub https: Option<HttpsConfig>, #[serde(default)] pub limits: Limits, - #[serde(default)] - pub hosts: HashMap<String, Route>, + pub handler: DynNode, } -fn true_default() -> bool { +pub fn return_true() -> bool { true } @@ -53,72 +57,8 @@ pub struct HttpsConfig { pub tls_key: PathBuf, } -#[derive(Debug, Serialize, Deserialize)] -pub struct Route(#[serde(deserialize_with = "seq_or_not")] pub Vec<RouteFilter>); - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum RouteFilter { - HttpBasicAuth { - #[serde(flatten)] - config: HttpBasicAuthConfig, - }, - Proxy { - backend: SocketAddr, - }, - Files { - #[serde(flatten)] - config: FileserverConfig, - }, - AccessLog { - #[serde(flatten)] - config: AccessLogConfig, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct AccessLogConfig { - pub file: PathBuf, - #[serde(default)] - pub flush: bool, - #[serde(default)] - pub reject_on_fail: bool, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct HttpBasicAuthConfig { - pub realm: String, - pub valid: HashSet<String>, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct FileserverConfig { - pub root: PathBuf, - #[serde(default)] - pub index: bool, - #[serde(default = "return_true")] - pub last_modified: bool, - #[serde(default = "return_true")] - pub etag: bool, - #[serde(default)] - pub cache: CacheConfig, -} - -#[derive(Debug, Default, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum CacheConfig { - #[default] - Public, - Private, - NoStore, -} - -fn return_true() -> bool { - true -} - // try deser Vec<T> but fall back to deser T and putting that in Vec -fn seq_or_not<'de, D, V: Deserialize<'de>>(des: D) -> Result<Vec<V>, D::Error> +pub fn seq_or_not<'de, D, V: Deserialize<'de>>(des: D) -> Result<Vec<V>, D::Error> where D: Deserializer<'de>, { @@ -194,11 +134,45 @@ where des.deserialize_any(StringOrList) } +pub static NODE_KINDS: RwLock<BTreeMap<String, &'static dyn NodeKind>> = + RwLock::new(BTreeMap::new()); + +#[derive(Clone)] +pub struct DynNode(Arc<dyn Node>); + +impl<'de> Deserialize<'de> for DynNode { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let tv = TaggedValue::deserialize(deserializer)?; + let s = tv.tag.to_string(); + let s = s.strip_prefix("!").unwrap_or(s.as_str()); + let inst = NODE_KINDS + .read() + .unwrap() + .get(s) + .ok_or(serde::de::Error::unknown_variant(s, &[]))? + .instanciate(tv.value) + .map_err(|e| { + serde::de::Error::custom(e.context(anyhow!("instanciating modules {s:?}"))) + })?; + + Ok(Self(inst)) + } +} +impl Deref for DynNode { + type Target = dyn Node; + fn deref(&self) -> &Self::Target { + self.0.as_ref() + } +} + impl Config { pub fn load(path: &Path) -> anyhow::Result<Config> { info!("loading config from {path:?}"); let raw = read_to_string(path).context("reading config file")?; - let config: Config = serde_yaml::from_str(&raw).context("parsing config")?; + let config: Config = serde_yaml::from_str(&raw).context("during parsing")?; Ok(config) } } @@ -235,7 +209,7 @@ pub fn setup_file_watch(config_path: PathBuf, state: Arc<State>) { let mut r = state.config.blocking_write(); *r = Arc::new(conf) } - Err(e) => error!("config has errors: {e}"), + Err(e) => error!("config has errors: {e:?}"), } } } |