use crate::ConfigError;
use conjure_runtime_config::ServicesConfig;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use staged_builder::{staged_builder, Validate};
use std::collections::HashMap;
use witchcraft_log::LevelFilter;
mod de;
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
pub struct RuntimeConfig {
diagnostics: DiagnosticsConfig,
health_checks: HealthChecksConfig,
#[builder(default)]
logging: LoggingConfig,
#[builder(default)]
service_discovery: ServicesConfig,
}
impl<'de> Deserialize<'de> for RuntimeConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::RuntimeConfig::deserialize(deserializer)?;
let mut builder = RuntimeConfig::builder()
.diagnostics(raw.diagnostics)
.health_checks(raw.health_checks);
if let Some(logging) = raw.logging {
builder = builder.logging(logging);
}
if let Some(service_discovery) = raw.service_discovery {
builder = builder.service_discovery(service_discovery);
}
Ok(builder.build())
}
}
impl AsRef<RuntimeConfig> for RuntimeConfig {
#[inline]
fn as_ref(&self) -> &RuntimeConfig {
self
}
}
impl RuntimeConfig {
#[inline]
pub fn diagnostics(&self) -> &DiagnosticsConfig {
&self.diagnostics
}
#[inline]
pub fn health_checks(&self) -> &HealthChecksConfig {
&self.health_checks
}
#[inline]
pub fn logging(&self) -> &LoggingConfig {
&self.logging
}
#[inline]
pub fn service_discovery(&self) -> &ServicesConfig {
&self.service_discovery
}
}
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
pub struct DiagnosticsConfig {
#[builder(into)]
debug_shared_secret: String,
}
impl<'de> Deserialize<'de> for DiagnosticsConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::DiagnosticsConfig::deserialize(deserializer)?;
let builder = DiagnosticsConfig::builder().debug_shared_secret(raw.debug_shared_secret);
Ok(builder.build())
}
}
impl DiagnosticsConfig {
#[inline]
pub fn debug_shared_secret(&self) -> &str {
&self.debug_shared_secret
}
}
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
pub struct HealthChecksConfig {
#[builder(into)]
shared_secret: String,
}
impl<'de> Deserialize<'de> for HealthChecksConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::HealthChecksConfig::deserialize(deserializer)?;
let builder = HealthChecksConfig::builder().shared_secret(raw.shared_secret);
Ok(builder.build())
}
}
impl HealthChecksConfig {
#[inline]
pub fn shared_secret(&self) -> &str {
&self.shared_secret
}
}
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
#[builder(validate)]
pub struct LoggingConfig {
#[builder(default = LevelFilter::Info)]
level: LevelFilter,
#[builder(map(key(type = String, into), value(type = LevelFilter)))]
loggers: HashMap<String, LevelFilter>,
#[builder(default = 0.0005)]
trace_rate: f32,
}
impl Validate for LoggingConfig {
type Error = ConfigError;
fn validate(&self) -> Result<(), Self::Error> {
if !(0.0..=1.0).contains(&self.trace_rate()) {
return Err(ConfigError(
"trace-rate must be between 0 and 1, inclusive".to_string(),
));
}
Ok(())
}
}
impl<'de> Deserialize<'de> for LoggingConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::LoggingConfig::deserialize(deserializer)?;
let mut builder = LoggingConfig::builder();
if let Some(level) = raw.level {
builder = builder.level(level);
}
if let Some(loggers) = raw.loggers {
builder = builder.loggers(loggers);
}
if let Some(trace_rate) = raw.trace_rate {
builder = builder.trace_rate(trace_rate);
}
builder.build().map_err(Error::custom)
}
}
impl Default for LoggingConfig {
#[inline]
fn default() -> Self {
LoggingConfig::builder().build().unwrap()
}
}
impl LoggingConfig {
#[inline]
pub fn level(&self) -> LevelFilter {
self.level
}
#[inline]
pub fn loggers(&self) -> &HashMap<String, LevelFilter> {
&self.loggers
}
#[inline]
pub fn trace_rate(&self) -> f32 {
self.trace_rate
}
}