auto_discovery/
error.rs

1//! Error types for the auto-discovery library
2
3use std::{
4    error::Error as StdError,
5    fmt,
6    io,
7    num::ParseIntError,
8    time::SystemTimeError,
9};
10use base64::DecodeError;
11use ring::error::{KeyRejected, Unspecified};
12
13/// The primary error type for the auto-discovery crate
14#[derive(Debug)]
15pub enum DiscoveryError {
16    /// Invalid configuration error
17    Configuration(String),
18    /// Invalid service data error
19    InvalidData(String),
20    /// DNS resolution error
21    DnsResolution(String),
22    /// mDNS protocol error
23    Mdns(String),
24    /// UPnP/SSDP protocol error
25    Upnp(String),
26    /// DNS-SD protocol error
27    DnsSd(String),
28    /// Network operation error
29    Network(String),
30    /// Protocol operation timeout
31    Timeout(String),
32    /// Service verification error
33    Verification(String),
34    /// Protocol error
35    Protocol(String),
36    /// I/O error
37    Io(io::Error),
38    /// Security error
39    Security(String),
40    /// Other error types
41    Other(String),
42}
43
44impl fmt::Display for DiscoveryError {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        match self {
47            Self::Configuration(msg) => write!(f, "Configuration error: {}", msg),
48            Self::InvalidData(msg) => write!(f, "Invalid data: {}", msg),
49            Self::DnsResolution(msg) => write!(f, "DNS resolution error: {}", msg),
50            Self::Mdns(msg) => write!(f, "mDNS error: {}", msg),
51            Self::Upnp(msg) => write!(f, "UPnP error: {}", msg),
52            Self::DnsSd(msg) => write!(f, "DNS-SD error: {}", msg),
53            Self::Network(msg) => write!(f, "Network error: {}", msg),
54            Self::Timeout(msg) => write!(f, "Timeout: {}", msg),
55            Self::Verification(msg) => write!(f, "Verification error: {}", msg),
56            Self::Protocol(msg) => write!(f, "Protocol error: {}", msg),
57            Self::Io(err) => write!(f, "I/O error: {}", err),
58            Self::Security(msg) => write!(f, "Security error: {}", msg),
59            Self::Other(msg) => write!(f, "Error: {}", msg),
60        }
61    }
62}
63
64impl StdError for DiscoveryError {
65    fn source(&self) -> Option<&(dyn StdError + 'static)> {
66        match self {
67            Self::Io(err) => Some(err),
68            _ => None,
69        }
70    }
71}
72
73impl From<io::Error> for DiscoveryError {
74    fn from(err: io::Error) -> Self {
75        Self::Io(err)
76    }
77}
78
79impl From<ParseIntError> for DiscoveryError {
80    fn from(err: ParseIntError) -> Self {
81        Self::InvalidData(err.to_string())
82    }
83}
84
85impl From<SystemTimeError> for DiscoveryError {
86    fn from(err: SystemTimeError) -> Self {
87        Self::Other(err.to_string())
88    }
89}
90
91impl From<DecodeError> for DiscoveryError {
92    fn from(err: DecodeError) -> Self {
93        Self::Security(err.to_string())
94    }
95}
96
97impl From<Unspecified> for DiscoveryError {
98    fn from(err: Unspecified) -> Self {
99        Self::Security(err.to_string())
100    }
101}
102
103impl From<KeyRejected> for DiscoveryError {
104    fn from(err: KeyRejected) -> Self {
105        Self::Security(err.to_string())
106    }
107}
108
109impl From<mdns_sd::Error> for DiscoveryError {
110    fn from(err: mdns_sd::Error) -> Self {
111        Self::Mdns(err.to_string())
112    }
113}
114
115/// Error severity levels
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum ErrorSeverity {
118    /// Fatal error requiring immediate attention
119    Fatal,
120    /// Error condition
121    Error,
122    /// Warning condition
123    Warning,
124    /// Informational message
125    Info,
126}
127
128/// Common result type for library operations
129pub type Result<T> = std::result::Result<T, DiscoveryError>;
130
131impl DiscoveryError {
132    /// Create a new configuration error
133    pub fn configuration<S: Into<String>>(msg: S) -> Self {
134        Self::Configuration(msg.into())
135    }
136
137    /// Create a new invalid data error
138    pub fn invalid_data<S: Into<String>>(msg: S) -> Self {
139        Self::InvalidData(msg.into())
140    }
141
142    /// Create a new DNS resolution error
143    pub fn dns_resolution<S: Into<String>>(msg: S) -> Self {
144        Self::DnsResolution(msg.into())
145    }
146
147    /// Create a new mDNS protocol error
148    pub fn mdns<S: Into<String>>(msg: S) -> Self {
149        Self::Mdns(msg.into())
150    }
151
152    /// Create a new UPnP protocol error
153    pub fn upnp<S: Into<String>>(msg: S) -> Self {
154        Self::Upnp(msg.into())
155    }
156
157    /// Create a new DNS-SD protocol error
158    pub fn dns_sd<S: Into<String>>(msg: S) -> Self {
159        Self::DnsSd(msg.into())
160    }
161
162    /// Create a new network error
163    pub fn network<S: Into<String>>(msg: S) -> Self {
164        Self::Network(msg.into())
165    }
166
167    /// Create a new timeout error
168    pub fn timeout<S: Into<String>>(msg: S) -> Self {
169        Self::Timeout(msg.into())
170    }
171
172    /// Create a new verification error
173    pub fn verification<S: Into<String>>(msg: S) -> Self {
174        Self::Verification(msg.into())
175    }
176
177    /// Create a new protocol error
178    pub fn protocol<S: Into<String>>(msg: S) -> Self {
179        Self::Protocol(msg.into())
180    }
181
182    /// Create a new security error
183    pub fn security<S: Into<String>>(msg: S) -> Self {
184        Self::Security(msg.into())
185    }
186
187    /// Create a new other error
188    pub fn other<S: Into<String>>(msg: S) -> Self {
189        Self::Other(msg.into())
190    }
191
192    /// Create a new invalid service error
193    pub fn invalid_service<S: Into<String>>(msg: S) -> Self {
194        Self::InvalidData(msg.into())
195    }
196
197    /// Check if error is retryable
198    pub fn is_retryable(&self) -> bool {
199        matches!(
200            self,
201            Self::Network(_) | Self::Timeout(_) | Self::Protocol(_)
202        )
203    }
204
205    /// Get error severity
206    pub fn severity(&self) -> ErrorSeverity {
207        match self {
208            Self::Configuration(_) | Self::InvalidData(_) => ErrorSeverity::Fatal,
209            Self::Security(_) | Self::Verification(_) => ErrorSeverity::Error,
210            Self::Network(_) | Self::DnsResolution(_) | Self::Protocol(_) => ErrorSeverity::Warning,
211            Self::Timeout(_) => ErrorSeverity::Info,
212            _ => ErrorSeverity::Warning,
213        }
214    }
215}
216
217// Test module
218#[cfg(test)]
219mod tests {
220    use super::*;
221
222    #[test]
223    fn test_error_severity() {
224        assert_eq!(
225            DiscoveryError::DnsResolution("test".to_string()).severity(),
226            ErrorSeverity::Warning
227        );
228        assert_eq!(
229            DiscoveryError::protocol("test".to_string()).severity(),
230            ErrorSeverity::Warning
231        );
232    }
233
234    #[test]
235    fn test_error_retryable() {
236        assert!(DiscoveryError::Timeout("5".to_string()).is_retryable());
237        assert!(!DiscoveryError::invalid_service("test".to_string()).is_retryable());
238    }
239}