aboutsummaryrefslogtreecommitdiffstats
path: root/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs194
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")]