diff --git a/bffhd/config/dhall.rs b/bffhd/config/dhall.rs index 169e39f..8e3e873 100644 --- a/bffhd/config/dhall.rs +++ b/bffhd/config/dhall.rs @@ -1,6 +1,169 @@ -use crate::Config; +use std::collections::HashMap; +use std::default::Default; +use std::error::Error; +use std::fmt::{Debug, Display}; +use std::marker::PhantomData; +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +use crate::authorization::permissions::PrivilegesBuf; +use crate::authorization::roles::Role; +use crate::capnp::{Listen, TlsListen}; +use crate::logging::LogConfig; + use std::path::Path; +use miette::IntoDiagnostic; + +#[derive(Debug)] +struct DhallConfig<'a> { + path: &'a Path, +} pub fn read_config_file(path: impl AsRef) -> Result { serde_dhall::from_file(path).parse().map_err(Into::into) } + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +/// A description of a machine +/// +/// This is the struct that a machine is serialized to/from. +/// Combining this with the actual state of the system will return a machine +pub struct MachineDescription { + /// The name of the machine. Doesn't need to be unique but is what humans will be presented. + pub name: String, + + /// An optional description of the Machine. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "deser_option" + )] + pub description: Option, + + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "deser_option" + )] + pub wiki: Option, + + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "deser_option" + )] + pub category: Option, + + /// The permission required + #[serde(flatten)] + pub privs: PrivilegesBuf, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + /// A list of address/port pairs to listen on. + pub listens: Vec, + + /// Machine descriptions to load + pub machines: HashMap, + + /// Actors to load and their configuration options + pub actors: HashMap, + + /// Initiators to load and their configuration options + pub initiators: HashMap, + + pub mqtt_url: String, + + pub actor_connections: Vec<(String, String)>, + pub init_connections: Vec<(String, String)>, + + pub db_path: PathBuf, + pub auditlog_path: PathBuf, + + pub roles: HashMap, + + #[serde(flatten)] + pub tlsconfig: TlsListen, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub tlskeylog: Option, + + #[serde(default, skip)] + pub verbosity: isize, + + #[serde(default, skip)] + pub logging: LogConfig, +} + +impl Config { + pub fn is_quiet(&self) -> bool { + self.verbosity < 0 + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ModuleConfig { + pub module: String, + pub params: HashMap, +} + +pub(crate) fn deser_option<'de, D, T>(d: D) -> std::result::Result, D::Error> + where + D: serde::Deserializer<'de>, + T: serde::Deserialize<'de>, +{ + Ok(T::deserialize(d).ok()) +} + +impl Default for Config { + fn default() -> Self { + let mut actors: HashMap = HashMap::new(); + let mut initiators: HashMap = HashMap::new(); + let machines = HashMap::new(); + + actors.insert( + "Actor".to_string(), + ModuleConfig { + module: "Shelly".to_string(), + params: HashMap::new(), + }, + ); + initiators.insert( + "Initiator".to_string(), + ModuleConfig { + module: "TCP-Listen".to_string(), + params: HashMap::new(), + }, + ); + + Config { + listens: vec![Listen { + address: "127.0.0.1".to_string(), + port: None, + }], + actors, + initiators, + machines, + mqtt_url: "tcp://localhost:1883".to_string(), + actor_connections: vec![("Testmachine".to_string(), "Actor".to_string())], + init_connections: vec![("Initiator".to_string(), "Testmachine".to_string())], + + db_path: PathBuf::from("/run/bffh/database"), + auditlog_path: PathBuf::from("/var/log/bffh/audit.log"), + roles: HashMap::new(), + + tlsconfig: TlsListen { + certfile: PathBuf::from("./bffh.crt"), + keyfile: PathBuf::from("./bffh.key"), + ..Default::default() + }, + + tlskeylog: None, + verbosity: 0, + logging: LogConfig::default(), + } + } +} diff --git a/bffhd/config/mod.rs b/bffhd/config/mod.rs index fe02283..3adabb9 100644 --- a/bffhd/config/mod.rs +++ b/bffhd/config/mod.rs @@ -1,157 +1,10 @@ -use std::collections::HashMap; -use std::default::Default; -use std::path::PathBuf; - -use serde::{Deserialize, Serialize}; - mod dhall; pub use dhall::read_config_file as read; +pub use dhall::{Config, ModuleConfig, MachineDescription}; +pub(crate) use dhall::deser_option; -use crate::authorization::permissions::PrivilegesBuf; -use crate::authorization::roles::Role; -use crate::capnp::{Listen, TlsListen}; -use crate::logging::LogConfig; +struct ConfigBuilder; +impl ConfigBuilder { -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -/// A description of a machine -/// -/// This is the struct that a machine is serialized to/from. -/// Combining this with the actual state of the system will return a machine -pub struct MachineDescription { - /// The name of the machine. Doesn't need to be unique but is what humans will be presented. - pub name: String, - - /// An optional description of the Machine. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deser_option" - )] - pub description: Option, - - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deser_option" - )] - pub wiki: Option, - - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "deser_option" - )] - pub category: Option, - - /// The permission required - #[serde(flatten)] - pub privs: PrivilegesBuf, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Config { - /// A list of address/port pairs to listen on. - pub listens: Vec, - - /// Machine descriptions to load - pub machines: HashMap, - - /// Actors to load and their configuration options - pub actors: HashMap, - - /// Initiators to load and their configuration options - pub initiators: HashMap, - - pub mqtt_url: String, - - pub actor_connections: Vec<(String, String)>, - pub init_connections: Vec<(String, String)>, - - pub db_path: PathBuf, - pub auditlog_path: PathBuf, - - pub roles: HashMap, - - #[serde(flatten)] - pub tlsconfig: TlsListen, - - #[serde(default, skip_serializing_if = "Option::is_none")] - pub tlskeylog: Option, - - #[serde(default, skip)] - pub verbosity: isize, - - #[serde(default, skip)] - pub logging: LogConfig, -} - -impl Config { - pub fn is_quiet(&self) -> bool { - self.verbosity < 0 - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ModuleConfig { - pub module: String, - pub params: HashMap, -} - -pub(crate) fn deser_option<'de, D, T>(d: D) -> std::result::Result, D::Error> -where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de>, -{ - Ok(T::deserialize(d).ok()) -} - -impl Default for Config { - fn default() -> Self { - let mut actors: HashMap = HashMap::new(); - let mut initiators: HashMap = HashMap::new(); - let machines = HashMap::new(); - - actors.insert( - "Actor".to_string(), - ModuleConfig { - module: "Shelly".to_string(), - params: HashMap::new(), - }, - ); - initiators.insert( - "Initiator".to_string(), - ModuleConfig { - module: "TCP-Listen".to_string(), - params: HashMap::new(), - }, - ); - - Config { - listens: vec![Listen { - address: "127.0.0.1".to_string(), - port: None, - }], - actors, - initiators, - machines, - mqtt_url: "tcp://localhost:1883".to_string(), - actor_connections: vec![("Testmachine".to_string(), "Actor".to_string())], - init_connections: vec![("Initiator".to_string(), "Testmachine".to_string())], - - db_path: PathBuf::from("/run/bffh/database"), - auditlog_path: PathBuf::from("/var/log/bffh/audit.log"), - roles: HashMap::new(), - - tlsconfig: TlsListen { - certfile: PathBuf::from("./bffh.crt"), - keyfile: PathBuf::from("./bffh.key"), - ..Default::default() - }, - - tlskeylog: None, - verbosity: 0, - logging: LogConfig::default(), - } - } -}