aboutsummaryrefslogtreecommitdiff
path: root/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs126
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:?}"),
}
}
}