Skip to main content

wp_conf_base/
structure.rs

1use orion_variate::EnvDict;
2use serde::{Deserialize, Serialize};
3use std::fmt::{Display, Formatter};
4use std::str::FromStr;
5
6use orion_conf::error::OrionConfResult;
7
8#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
9pub enum Protocol {
10    #[serde(rename = "tcp")]
11    TCP,
12    #[default]
13    #[serde(rename = "udp")]
14    UDP,
15}
16
17impl FromStr for Protocol {
18    type Err = anyhow::Error;
19
20    fn from_str(s: &str) -> Result<Self, Self::Err> {
21        match s {
22            "tcp" => Ok(Protocol::TCP),
23            "udp" => Ok(Protocol::UDP),
24            _ => Err(anyhow::anyhow!(
25                "Unsupported protocol '{}' for syslog server. Supported protocols are: tcp, udp",
26                s
27            )),
28        }
29    }
30}
31
32impl Display for Protocol {
33    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34        match self {
35            Protocol::TCP => {
36                write!(f, "tcp")?;
37            }
38            Protocol::UDP => {
39                write!(f, "udp")?;
40            }
41        }
42        Ok(())
43    }
44}
45
46/// 统一的配置对象操作接口
47pub trait ConfStdOperation {
48    fn try_load(path: &str, dict: &EnvDict) -> OrionConfResult<Option<Self>>
49    where
50        Self: Sized,
51    {
52        if std::path::Path::new(path).exists() {
53            match Self::load(path, dict) {
54                Ok(conf) => Ok(Some(conf)),
55                Err(e) => {
56                    log::warn!("load conf error: {}", e);
57                    Err(e)
58                }
59            }
60        } else {
61            Ok(None)
62        }
63    }
64
65    fn load(path: &str, dict: &EnvDict) -> OrionConfResult<Self>
66    where
67        Self: Sized;
68    fn init(path: &str) -> OrionConfResult<Self>
69    where
70        Self: Sized;
71    fn safe_clean(path: &str) -> OrionConfResult<()>;
72}
73
74// Unified validate hook for configuration structs
75pub trait Validate {
76    fn validate(&self) -> OrionConfResult<()> {
77        Ok(())
78    }
79}
80
81/// Backward‑compatible boolean deserializer that accepts:
82/// - native bool (true/false)
83/// - strings: "on"/"off", "true"/"false", "1"/"0", "yes"/"no" (case‑insensitive)
84///
85/// # Examples
86///
87/// ```json
88/// { "enabled": true }      // OK
89/// { "enabled": "on" }      // OK
90/// { "enabled": "1" }       // OK
91/// { "enabled": "yes" }     // OK
92/// { "enabled": "invalid" } // Error
93/// ```
94pub fn de_bool_onoff<'de, D>(deserializer: D) -> Result<bool, D::Error>
95where
96    D: serde::Deserializer<'de>,
97{
98    use serde::de::Error as DeError;
99    #[derive(Deserialize)]
100    #[serde(untagged)]
101    enum In {
102        B(bool),
103        S(String),
104        I(i64),
105    }
106    match In::deserialize(deserializer)? {
107        In::B(b) => Ok(b),
108        In::I(i) => match i {
109            0 => Ok(false),
110            1 => Ok(true),
111            other => Err(D::Error::custom(format!(
112                "invalid boolean value: {} (expect 0 or 1)",
113                other
114            ))),
115        },
116        In::S(s) => {
117            let v = s.trim().to_ascii_lowercase();
118            match v.as_str() {
119                "on" | "true" | "1" | "yes" | "y" => Ok(true),
120                "off" | "false" | "0" | "no" | "n" => Ok(false),
121                other => Err(D::Error::custom(format!(
122                    "invalid boolean value: {} (expect on/off or true/false)",
123                    other
124                ))),
125            }
126        }
127    }
128}