Config hot reloading API
This commit is contained in:
@@ -81,52 +81,53 @@ impl SimpleCron {
|
||||
}
|
||||
|
||||
impl ParseValue for SimpleCron {
|
||||
fn parse_value(key: impl super::utils::AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
let mut hour = 0;
|
||||
let mut minute = 0;
|
||||
let key = key.as_key();
|
||||
|
||||
for (pos, value) in value.split(' ').enumerate() {
|
||||
if pos == 0 {
|
||||
minute = value.parse::<u32>().map_err(|_| {
|
||||
format!("Invalid cron key {key:?}: failed to parse cron minute")
|
||||
})?;
|
||||
minute = value
|
||||
.parse::<u32>()
|
||||
.map_err(|_| "Invalid cron key: failed to parse cron minute".to_string())?;
|
||||
if !(0..=59).contains(&minute) {
|
||||
return Err(format!(
|
||||
"Invalid cron key {key:?}: failed to parse minute, invalid value: {minute}"
|
||||
"Invalid cron key: failed to parse minute, invalid value: {minute}"
|
||||
));
|
||||
}
|
||||
} else if pos == 1 {
|
||||
if value
|
||||
.as_bytes()
|
||||
.first()
|
||||
.ok_or_else(|| format!("Invalid cron key {key:?}: failed to parse cron hour"))?
|
||||
.ok_or_else(|| "Invalid cron key: failed to parse cron hour".to_string())?
|
||||
== &b'*'
|
||||
{
|
||||
return Ok(SimpleCron::Hour { minute });
|
||||
} else {
|
||||
hour = value.parse::<u32>().map_err(|_| {
|
||||
format!("Invalid cron key {key:?}: failed to parse cron hour")
|
||||
})?;
|
||||
hour = value
|
||||
.parse::<u32>()
|
||||
.map_err(|_| "Invalid cron key: failed to parse cron hour".to_string())?;
|
||||
if !(0..=23).contains(&hour) {
|
||||
return Err(format!(
|
||||
"Invalid cron key {key:?}: failed to parse hour, invalid value: {hour}"
|
||||
"Invalid cron key: failed to parse hour, invalid value: {hour}"
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if pos == 2 {
|
||||
if value.as_bytes().first().ok_or_else(|| {
|
||||
format!("Invalid cron key {key:?}: failed to parse cron weekday")
|
||||
})? == &b'*'
|
||||
if value
|
||||
.as_bytes()
|
||||
.first()
|
||||
.ok_or_else(|| "Invalid cron key: failed to parse cron weekday".to_string())?
|
||||
== &b'*'
|
||||
{
|
||||
return Ok(SimpleCron::Day { hour, minute });
|
||||
} else {
|
||||
let day = value.parse::<u32>().map_err(|_| {
|
||||
format!("Invalid cron key {key:?}: failed to parse cron weekday")
|
||||
"Invalid cron key: failed to parse cron weekday".to_string()
|
||||
})?;
|
||||
if !(1..=7).contains(&hour) {
|
||||
return Err(format!(
|
||||
"Invalid cron key {key:?}: failed to parse weekday, invalid value: {}, range is 1 (Monday) to 7 (Sunday).",
|
||||
"Invalid cron key: failed to parse weekday, invalid value: {}, range is 1 (Monday) to 7 (Sunday).",
|
||||
hour,
|
||||
));
|
||||
}
|
||||
@@ -136,7 +137,7 @@ impl ParseValue for SimpleCron {
|
||||
}
|
||||
}
|
||||
|
||||
Err(format!("Invalid cron key {key:?}: parse cron expression."))
|
||||
Err("Invalid cron key: parse cron expression.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
use rustls::{crypto::ring::cipher_suite::*, SupportedCipherSuite};
|
||||
|
||||
use super::utils::{AsKey, ParseKey, ParseValue};
|
||||
use super::utils::ParseValue;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum IpAddrMask {
|
||||
@@ -91,7 +91,7 @@ impl IpAddrMask {
|
||||
}
|
||||
|
||||
impl ParseValue for IpAddrMask {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
if let Some((addr, mask)) = value.rsplit_once('/') {
|
||||
if let (Ok(addr), Ok(mask)) =
|
||||
(addr.trim().parse::<IpAddr>(), mask.trim().parse::<u32>())
|
||||
@@ -130,38 +130,30 @@ impl ParseValue for IpAddrMask {
|
||||
}
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"Invalid IP address {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
))
|
||||
Err(format!("Invalid IP address {:?}", value,))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for IpAddrOrMask {
|
||||
fn parse_value(key: impl AsKey, ip: &str) -> super::Result<Self> {
|
||||
fn parse_value(ip: &str) -> super::Result<Self> {
|
||||
if ip.contains('/') {
|
||||
ip.parse_key(key).map(IpAddrOrMask::Mask)
|
||||
IpAddrMask::parse_value(ip).map(IpAddrOrMask::Mask)
|
||||
} else {
|
||||
ip.parse_key(key).map(IpAddrOrMask::Ip)
|
||||
IpAddr::parse_value(ip).map(IpAddrOrMask::Ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for SocketAddr {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid socket address {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid socket address {:?}.", value,))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for SupportedCipherSuite {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
Ok(match value {
|
||||
// TLS1.3 suites
|
||||
"TLS13_AES_256_GCM_SHA384" => TLS13_AES_256_GCM_SHA384,
|
||||
@@ -178,13 +170,7 @@ impl ParseValue for SupportedCipherSuite {
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" => {
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
}
|
||||
cipher => {
|
||||
return Err(format!(
|
||||
"Unsupported TLS cipher suite {:?} found in key {:?}",
|
||||
cipher,
|
||||
key.as_key()
|
||||
))
|
||||
}
|
||||
cipher => return Err(format!("Unsupported TLS cipher suite {:?}", cipher,)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -200,7 +186,7 @@ mod tests {
|
||||
("10.0.0.0/8", "10.0.13.73"),
|
||||
("192.168.1.1", "192.168.1.1"),
|
||||
] {
|
||||
let mask = IpAddrMask::parse_value("test", mask).unwrap();
|
||||
let mask = IpAddrMask::parse_value(mask).unwrap();
|
||||
let ip = ip.parse::<IpAddr>().unwrap();
|
||||
assert!(mask.matches(&ip));
|
||||
}
|
||||
@@ -209,7 +195,7 @@ mod tests {
|
||||
("10.0.0.0/8", "11.30.20.11"),
|
||||
("192.168.1.1", "193.168.1.1"),
|
||||
] {
|
||||
let mask = IpAddrMask::parse_value("test", mask).unwrap();
|
||||
let mask = IpAddrMask::parse_value(mask).unwrap();
|
||||
let ip = ip.parse::<IpAddr>().unwrap();
|
||||
assert!(!mask.matches(&ip));
|
||||
}
|
||||
|
||||
@@ -29,15 +29,25 @@ pub mod utils;
|
||||
use std::{collections::BTreeMap, time::Duration};
|
||||
|
||||
use ahash::AHashMap;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct Config {
|
||||
#[serde(skip)]
|
||||
pub keys: BTreeMap<String, String>,
|
||||
pub missing: AHashMap<String, Option<String>>,
|
||||
pub warnings: AHashMap<String, ConfigWarning>,
|
||||
pub errors: AHashMap<String, ConfigError>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ConfigWarning {
|
||||
Missing,
|
||||
AppliedDefault(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ConfigError {
|
||||
Parse(String),
|
||||
Build(String),
|
||||
@@ -184,12 +194,12 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn log_warnings(&self, use_stderr: bool) {
|
||||
for (key, value) in &self.missing {
|
||||
let message = match value {
|
||||
Some(replaced) => {
|
||||
format!("WARNING: Missing setting {key:?}, applied default {replaced:?}")
|
||||
for (key, warn) in &self.warnings {
|
||||
let message = match warn {
|
||||
ConfigWarning::AppliedDefault(default) => {
|
||||
format!("WARNING: Missing setting {key:?}, applied default {default:?}")
|
||||
}
|
||||
None => {
|
||||
ConfigWarning::Missing => {
|
||||
format!("WARNING: Missing setting {key:?}")
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,13 +34,13 @@ use mail_auth::{
|
||||
};
|
||||
use smtp_proto::MtPriority;
|
||||
|
||||
use super::{Config, ConfigError, Rate};
|
||||
use super::{Config, ConfigError, ConfigWarning, Rate};
|
||||
|
||||
impl Config {
|
||||
pub fn property<T: ParseValue>(&mut self, key: impl AsKey) -> Option<T> {
|
||||
let key = key.as_key();
|
||||
if let Some(value) = self.keys.get(&key) {
|
||||
match T::parse_value(key.as_str(), value) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
self.new_parse_error(key, err);
|
||||
@@ -61,11 +61,14 @@ impl Config {
|
||||
let value = match self.keys.get(&key) {
|
||||
Some(value) => value.as_str(),
|
||||
None => {
|
||||
self.missing.insert(key.clone(), default.to_string().into());
|
||||
self.warnings.insert(
|
||||
key.clone(),
|
||||
ConfigWarning::AppliedDefault(default.to_string()),
|
||||
);
|
||||
default
|
||||
}
|
||||
};
|
||||
match T::parse_value(key.as_str(), value) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
self.new_parse_error(key, err);
|
||||
@@ -83,12 +86,13 @@ impl Config {
|
||||
let value = match self.value_or_else(key.as_str(), default.clone()) {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
self.missing.insert(default.as_key(), None);
|
||||
self.warnings
|
||||
.insert(default.as_key(), ConfigWarning::Missing);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
match T::parse_value(key.as_str(), value) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
self.new_parse_error(key, err);
|
||||
@@ -100,7 +104,7 @@ impl Config {
|
||||
pub fn property_require<T: ParseValue>(&mut self, key: impl AsKey) -> Option<T> {
|
||||
let key = key.as_key();
|
||||
if let Some(value) = self.keys.get(&key) {
|
||||
match T::parse_value(key.as_str(), value) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
self.new_parse_error(key, err);
|
||||
@@ -169,7 +173,7 @@ impl Config {
|
||||
|
||||
for (key, value) in &self.keys {
|
||||
if key.starts_with(&prefix) || key == &full_prefix {
|
||||
match T::parse_value(key.as_str(), value) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => {
|
||||
results.push((key.to_string(), value));
|
||||
}
|
||||
@@ -203,7 +207,7 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn try_parse_value<T: ParseValue>(&mut self, key: impl AsKey, value: &str) -> Option<T> {
|
||||
match T::parse_value(key.clone(), value) {
|
||||
match T::parse_value(value) {
|
||||
Ok(value) => Some(value),
|
||||
Err(err) => {
|
||||
self.errors.insert(key.as_key(), ConfigError::Parse(err));
|
||||
@@ -261,7 +265,7 @@ impl Config {
|
||||
match self.keys.get(&key) {
|
||||
Some(value) => Some(value.as_str()),
|
||||
None => {
|
||||
self.missing.insert(key, None);
|
||||
self.warnings.insert(key, ConfigWarning::Missing);
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -278,38 +282,16 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn new_missing_property(&mut self, key: impl AsKey) {
|
||||
self.missing.insert(key.as_key(), None);
|
||||
self.warnings.insert(key.as_key(), ConfigWarning::Missing);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseValue: Sized {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self>;
|
||||
}
|
||||
|
||||
pub trait ParseKey<T: ParseValue> {
|
||||
fn parse_key(&self, key: impl AsKey) -> super::Result<T>;
|
||||
}
|
||||
|
||||
impl<T: ParseValue> ParseKey<T> for &str {
|
||||
fn parse_key(&self, key: impl AsKey) -> super::Result<T> {
|
||||
T::parse_value(key, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParseValue> ParseKey<T> for String {
|
||||
fn parse_key(&self, key: impl AsKey) -> super::Result<T> {
|
||||
T::parse_value(key, self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParseValue> ParseKey<T> for &String {
|
||||
fn parse_key(&self, key: impl AsKey) -> super::Result<T> {
|
||||
T::parse_value(key, self.as_str())
|
||||
}
|
||||
fn parse_value(value: &str) -> super::Result<Self>;
|
||||
}
|
||||
|
||||
impl<T: ParseValue> ParseValue for Option<T> {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
if !value.is_empty()
|
||||
&& !value.eq_ignore_ascii_case("false")
|
||||
&& !value.eq_ignore_ascii_case("disable")
|
||||
@@ -317,7 +299,7 @@ impl<T: ParseValue> ParseValue for Option<T> {
|
||||
&& !value.eq_ignore_ascii_case("never")
|
||||
&& !value.eq("0")
|
||||
{
|
||||
T::parse_value(key, value).map(Some)
|
||||
T::parse_value(value).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -325,137 +307,101 @@ impl<T: ParseValue> ParseValue for Option<T> {
|
||||
}
|
||||
|
||||
impl ParseValue for String {
|
||||
fn parse_value(_key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
Ok(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for u64 {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid integer value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid integer value {:?}.", value,))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for f64 {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid floating point value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid floating point value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for u16 {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid integer value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid integer value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for i16 {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid integer value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid integer value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for u32 {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid integer value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid integer value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for i32 {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid integer value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid integer value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for IpAddr {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid IP address value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid IP address value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for usize {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid integer value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid integer value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for bool {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
value.parse().map_err(|_| {
|
||||
format!(
|
||||
"Invalid boolean value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid boolean value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for Ipv4Addr {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid IPv4 value {:?} for key {:?}.", value, key.as_key()))
|
||||
.map_err(|_| format!("Invalid IPv4 value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for Ipv6Addr {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
value
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid IPv6 value {:?} for key {:?}.", value, key.as_key()))
|
||||
.map_err(|_| format!("Invalid IPv6 value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for PathBuf {
|
||||
fn parse_value(_key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
let path = PathBuf::from(value);
|
||||
|
||||
if path.exists() {
|
||||
@@ -467,84 +413,62 @@ impl ParseValue for PathBuf {
|
||||
}
|
||||
|
||||
impl ParseValue for MtPriority {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
match value.to_ascii_lowercase().as_str() {
|
||||
"mixer" => Ok(MtPriority::Mixer),
|
||||
"stanag4406" => Ok(MtPriority::Stanag4406),
|
||||
"nsep" => Ok(MtPriority::Nsep),
|
||||
_ => Err(format!(
|
||||
"Invalid priority value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)),
|
||||
_ => Err(format!("Invalid priority value {:?}.", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for Canonicalization {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
match value {
|
||||
"relaxed" => Ok(Canonicalization::Relaxed),
|
||||
"simple" => Ok(Canonicalization::Simple),
|
||||
_ => Err(format!(
|
||||
"Invalid canonicalization value {:?} for key {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)),
|
||||
_ => Err(format!("Invalid canonicalization value {:?}.", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for IpLookupStrategy {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
Ok(match value.to_lowercase().as_str() {
|
||||
"ipv4_only" => IpLookupStrategy::Ipv4Only,
|
||||
"ipv6_only" => IpLookupStrategy::Ipv6Only,
|
||||
//"ipv4_and_ipv6" => IpLookupStrategy::Ipv4AndIpv6,
|
||||
"ipv6_then_ipv4" => IpLookupStrategy::Ipv6thenIpv4,
|
||||
"ipv4_then_ipv6" => IpLookupStrategy::Ipv4thenIpv6,
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"Invalid IP lookup strategy {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
))
|
||||
}
|
||||
_ => return Err(format!("Invalid IP lookup strategy {:?}.", value)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for Algorithm {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
match value {
|
||||
"ed25519-sha256" | "ed25519-sha-256" => Ok(Algorithm::Ed25519Sha256),
|
||||
"rsa-sha-256" | "rsa-sha256" => Ok(Algorithm::RsaSha256),
|
||||
"rsa-sha-1" | "rsa-sha1" => Ok(Algorithm::RsaSha1),
|
||||
_ => Err(format!(
|
||||
"Invalid algorithm {:?} for key {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)),
|
||||
_ => Err(format!("Invalid algorithm {:?}.", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for HashAlgorithm {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
match value {
|
||||
"sha256" | "sha-256" => Ok(HashAlgorithm::Sha256),
|
||||
"sha-1" | "sha1" => Ok(HashAlgorithm::Sha1),
|
||||
_ => Err(format!(
|
||||
"Invalid hash algorithm {:?} for key {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)),
|
||||
_ => Err(format!("Invalid hash algorithm {:?}.", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for Duration {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
let mut digits = String::new();
|
||||
let mut multiplier = String::new();
|
||||
|
||||
@@ -562,13 +486,7 @@ impl ParseValue for Duration {
|
||||
"m" => 60 * 1000,
|
||||
"s" => 1000,
|
||||
"ms" | "" => 1,
|
||||
_ => {
|
||||
return Err(format!(
|
||||
"Invalid duration value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
))
|
||||
}
|
||||
_ => return Err(format!("Invalid duration value {:?}.", value)),
|
||||
};
|
||||
|
||||
digits
|
||||
@@ -581,18 +499,12 @@ impl ParseValue for Duration {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"Invalid duration value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})
|
||||
.ok_or_else(|| format!("Invalid duration value {:?}.", value))
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseValue for Rate {
|
||||
fn parse_value(key: impl AsKey, value: &str) -> super::Result<Self> {
|
||||
fn parse_value(value: &str) -> super::Result<Self> {
|
||||
if let Some((requests, period)) = value.split_once('/') {
|
||||
Ok(Rate {
|
||||
requests: requests
|
||||
@@ -600,23 +512,13 @@ impl ParseValue for Rate {
|
||||
.parse::<u64>()
|
||||
.ok()
|
||||
.and_then(|r| if r > 0 { Some(r) } else { None })
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"Invalid rate value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
)
|
||||
})?,
|
||||
period: std::cmp::max(period.parse_key(key)?, Duration::from_secs(1)),
|
||||
.ok_or_else(|| format!("Invalid rate value {:?}.", value))?,
|
||||
period: std::cmp::max(Duration::parse_value(period)?, Duration::from_secs(1)),
|
||||
})
|
||||
} else if ["false", "none", "unlimited"].contains(&value) {
|
||||
Ok(Rate::default())
|
||||
} else {
|
||||
Err(format!(
|
||||
"Invalid rate value {:?} for property {:?}.",
|
||||
value,
|
||||
key.as_key()
|
||||
))
|
||||
Err(format!("Invalid rate value {:?}.", value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user