diff options
Diffstat (limited to 'src/config.rs')
-rw-r--r-- | src/config.rs | 194 |
1 files changed, 6 insertions, 188 deletions
diff --git a/src/config.rs b/src/config.rs index b04b72c..d3fc75b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,21 +1,22 @@ // SPDX-FileCopyrightText: 2025 Tomasz Kramkowski <tomasz@kramkow.ski> // SPDX-License-Identifier: GPL-3.0-or-later +mod helpers; + use std::{ - collections::HashMap, fmt, fs::File, io::Read, os::unix::fs::PermissionsExt, path::Path, + collections::HashMap, fs::File, io::Read, os::unix::fs::PermissionsExt, path::Path, time::Duration, }; use anyhow::bail; use log::LevelFilter; use rumqttc::{AsyncClient, EventLoop, MqttOptions, QoS}; -use serde::{ - de::{self, Visitor}, - Deserialize, Deserializer, -}; +use serde::Deserialize; use crate::PROGRAM; +use helpers::*; + #[derive(Deserialize, Debug, PartialEq)] pub struct Logging { #[serde(default = "default_level_filter")] @@ -63,27 +64,6 @@ fn default_level_filter() -> LevelFilter { LevelFilter::Info } -#[allow(clippy::enum_variant_names)] -#[derive(Deserialize, Debug)] -#[serde(remote = "QoS", rename_all = "kebab-case")] -#[repr(u8)] -pub enum QoSDef { - AtMostOnce = 0, - AtLeastOnce = 1, - ExactlyOnce = 2, -} - -pub fn deserialize_qos_opt<'de, D>(deserializer: D) -> Result<Option<QoS>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Helper(#[serde(with = "QoSDef")] QoS); - - let helper = Option::deserialize(deserializer)?; - Ok(helper.map(|Helper(external)| external)) -} - #[derive(Debug, PartialEq, Clone)] pub struct Program { // TODO: Figure out a way to allow arbitrary unix paths (arbitrary @@ -92,174 +72,12 @@ pub struct Program { pub timeout: Option<Duration>, } -impl<'de> Deserialize<'de> for Program { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - struct VecOrProgram; - - impl<'de> Visitor<'de> for VecOrProgram { - type Value = Program; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("map or seq") - } - - fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error> - where - A: serde::de::SeqAccess<'de>, - { - let vec: Box<[String]> = - Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))?; - Ok(Program { - command: vec, - timeout: None, - }) - } - - fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> - where - A: serde::de::MapAccess<'de>, - { - #[derive(Deserialize)] - struct Helper { - command: Box<[String]>, - #[serde(default, deserialize_with = "deserialize_timeout_opt")] - timeout: Option<Duration>, - } - - let helper: Helper = - Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; - Ok(Program { - command: helper.command, - timeout: helper.timeout, - }) - } - } - - deserializer.deserialize_any(VecOrProgram) - } -} - #[derive(Debug)] pub struct Route { pub programs: Box<[Program]>, pub qos: Option<QoS>, } -impl<'de> Deserialize<'de> for Route { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - struct VecOrRoute; - - impl<'de> Visitor<'de> for VecOrRoute { - type Value = Route; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("map or seq") - } - - fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error> - where - A: serde::de::SeqAccess<'de>, - { - let vec: Box<[Program]> = - Deserialize::deserialize(de::value::SeqAccessDeserializer::new(seq))?; - Ok(Route { - programs: vec, - qos: None, - }) - } - - fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error> - where - A: serde::de::MapAccess<'de>, - { - #[derive(Deserialize)] - struct Helper { - programs: Box<[Program]>, - #[serde(default, deserialize_with = "deserialize_qos_opt")] - qos: Option<QoS>, - } - - let helper: Helper = - Deserialize::deserialize(de::value::MapAccessDeserializer::new(map))?; - Ok(Route { - programs: helper.programs, - qos: helper.qos, - }) - } - } - - deserializer.deserialize_any(VecOrRoute) - } -} - -pub fn deserialize_timeout<'de, D>(deserializer: D) -> Result<Duration, D::Error> -where - D: Deserializer<'de>, -{ - struct DurationVisitor; - - impl<'de> de::Visitor<'de> for DurationVisitor { - type Value = Duration; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a positive number") - } - - fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> - where - E: de::Error, - { - if v < 0 { - return Err(de::Error::invalid_value( - de::Unexpected::Signed(v), - &"a non-negative number", - )); - } - if v == 0 { - Ok(Duration::MAX) - } else { - Ok(Duration::from_secs(v as u64)) - } - } - - fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> - where - E: de::Error, - { - if v < 0.0 { - return Err(de::Error::invalid_value( - de::Unexpected::Float(v), - &"a non-negative number", - )); - } - if v == 0.0 { - Ok(Duration::MAX) - } else { - Ok(Duration::from_secs_f64(v)) - } - } - } - - deserializer.deserialize_any(DurationVisitor) -} - -pub fn deserialize_timeout_opt<'de, D>(deserializer: D) -> Result<Option<Duration>, D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Helper(#[serde(deserialize_with = "deserialize_timeout")] Duration); - - let helper = Option::deserialize(deserializer)?; - Ok(helper.map(|Helper(external)| external)) -} - #[derive(Deserialize, Debug)] pub struct Config { #[serde(default = "default_host")] |