1use 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#[derive(Debug)]
15pub enum DiscoveryError {
16 Configuration(String),
18 InvalidData(String),
20 DnsResolution(String),
22 Mdns(String),
24 Upnp(String),
26 DnsSd(String),
28 Network(String),
30 Timeout(String),
32 Verification(String),
34 Protocol(String),
36 Io(io::Error),
38 Security(String),
40 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum ErrorSeverity {
118 Fatal,
120 Error,
122 Warning,
124 Info,
126}
127
128pub type Result<T> = std::result::Result<T, DiscoveryError>;
130
131impl DiscoveryError {
132 pub fn configuration<S: Into<String>>(msg: S) -> Self {
134 Self::Configuration(msg.into())
135 }
136
137 pub fn invalid_data<S: Into<String>>(msg: S) -> Self {
139 Self::InvalidData(msg.into())
140 }
141
142 pub fn dns_resolution<S: Into<String>>(msg: S) -> Self {
144 Self::DnsResolution(msg.into())
145 }
146
147 pub fn mdns<S: Into<String>>(msg: S) -> Self {
149 Self::Mdns(msg.into())
150 }
151
152 pub fn upnp<S: Into<String>>(msg: S) -> Self {
154 Self::Upnp(msg.into())
155 }
156
157 pub fn dns_sd<S: Into<String>>(msg: S) -> Self {
159 Self::DnsSd(msg.into())
160 }
161
162 pub fn network<S: Into<String>>(msg: S) -> Self {
164 Self::Network(msg.into())
165 }
166
167 pub fn timeout<S: Into<String>>(msg: S) -> Self {
169 Self::Timeout(msg.into())
170 }
171
172 pub fn verification<S: Into<String>>(msg: S) -> Self {
174 Self::Verification(msg.into())
175 }
176
177 pub fn protocol<S: Into<String>>(msg: S) -> Self {
179 Self::Protocol(msg.into())
180 }
181
182 pub fn security<S: Into<String>>(msg: S) -> Self {
184 Self::Security(msg.into())
185 }
186
187 pub fn other<S: Into<String>>(msg: S) -> Self {
189 Self::Other(msg.into())
190 }
191
192 pub fn invalid_service<S: Into<String>>(msg: S) -> Self {
194 Self::InvalidData(msg.into())
195 }
196
197 pub fn is_retryable(&self) -> bool {
199 matches!(
200 self,
201 Self::Network(_) | Self::Timeout(_) | Self::Protocol(_)
202 )
203 }
204
205 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#[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}