ddns_a/config/error.rs
1//! Error types for configuration parsing and validation.
2
3use std::path::PathBuf;
4
5use thiserror::Error;
6
7/// Error type for configuration operations.
8///
9/// Covers errors from parsing, validation, and file operations.
10#[derive(Debug, Error)]
11pub enum ConfigError {
12 /// Failed to read the configuration file.
13 #[error("Failed to read config file '{}': {source}", path.display())]
14 FileRead {
15 /// Path to the config file
16 path: PathBuf,
17 /// Underlying I/O error
18 #[source]
19 source: std::io::Error,
20 },
21
22 /// Failed to parse the TOML configuration.
23 #[error("Failed to parse TOML config: {0}")]
24 TomlParse(#[from] toml::de::Error),
25
26 /// Failed to write configuration file (for init command).
27 #[error("Failed to write config file '{}': {source}", path.display())]
28 FileWrite {
29 /// Path to the config file
30 path: PathBuf,
31 /// Underlying I/O error
32 #[source]
33 source: std::io::Error,
34 },
35
36 /// Missing required field that must be provided by CLI or config file.
37 #[error("Missing required field: {field}. {hint}")]
38 MissingRequired {
39 /// Name of the missing field
40 field: &'static str,
41 /// Hint for how to provide the value
42 hint: &'static str,
43 },
44
45 /// Invalid URL provided.
46 #[error("Invalid URL '{url}': {reason}")]
47 InvalidUrl {
48 /// The invalid URL string
49 url: String,
50 /// Reason for invalidity
51 reason: String,
52 },
53
54 /// Invalid regex pattern for adapter filtering.
55 #[error("Invalid regex pattern '{pattern}': {source}")]
56 InvalidRegex {
57 /// The invalid pattern
58 pattern: String,
59 /// Underlying regex error
60 #[source]
61 source: regex::Error,
62 },
63
64 /// Invalid duration value (zero or too large).
65 #[error("Invalid duration for {field}: {reason}")]
66 InvalidDuration {
67 /// Name of the field
68 field: &'static str,
69 /// Reason for invalidity
70 reason: String,
71 },
72
73 /// Invalid retry configuration.
74 #[error("Invalid retry configuration: {0}")]
75 InvalidRetry(String),
76
77 /// Invalid HTTP method.
78 #[error("Invalid HTTP method '{0}'")]
79 InvalidMethod(String),
80
81 /// Invalid IP version value.
82 #[error("Invalid IP version '{value}': expected ipv4, ipv6, or both")]
83 InvalidIpVersion {
84 /// The invalid value provided
85 value: String,
86 },
87
88 /// Invalid adapter kind value.
89 #[error("Invalid adapter kind '{value}': expected ethernet, wireless, virtual, or loopback")]
90 InvalidAdapterKind {
91 /// The invalid value provided
92 value: String,
93 },
94
95 /// Invalid change kind value.
96 #[error("Invalid change kind '{value}': expected added, removed, or both")]
97 InvalidChangeKind {
98 /// The invalid value provided
99 value: String,
100 },
101
102 /// Invalid header format.
103 #[error("Invalid header format '{value}': expected 'Key=Value' or 'Key: Value'")]
104 InvalidHeader {
105 /// The invalid header string
106 value: String,
107 },
108
109 /// Invalid header name.
110 #[error("Invalid header name '{name}': {reason}")]
111 InvalidHeaderName {
112 /// The invalid header name
113 name: String,
114 /// Reason for invalidity
115 reason: String,
116 },
117
118 /// Invalid header value.
119 #[error("Invalid header value for '{name}': {reason}")]
120 InvalidHeaderValue {
121 /// The header name
122 name: String,
123 /// Reason for invalidity
124 reason: String,
125 },
126
127 /// Invalid body template (Handlebars syntax error).
128 #[error("Invalid body template: {reason}")]
129 InvalidTemplate {
130 /// Reason for invalidity
131 reason: String,
132 },
133}
134
135/// Well-known field names for `MissingRequired` errors.
136///
137/// Use these constants for compile-time safety when matching field names.
138pub mod field {
139 /// The webhook URL field.
140 pub const URL: &str = "url";
141 /// The IP version field.
142 pub const IP_VERSION: &str = "ip_version";
143}
144
145impl ConfigError {
146 /// Creates a `MissingRequired` error for a required field.
147 #[must_use]
148 pub const fn missing(field: &'static str, hint: &'static str) -> Self {
149 Self::MissingRequired { field, hint }
150 }
151}