rust_mc_status/error.rs
1//! Error types for the Minecraft server status library.
2//!
3//! This module provides comprehensive error handling using [`thiserror`] for
4//! all operations that can fail during server status queries.
5//!
6//! # Example
7//!
8//! ```no_run
9//! use rust_mc_status::{McClient, ServerEdition, McError};
10//!
11//! #[tokio::main]
12//! async fn main() -> Result<(), McError> {
13//! let client = McClient::new();
14//!
15//! match client.ping("invalid-server", ServerEdition::Java).await {
16//! Ok(status) => println!("Server is online!"),
17//! Err(McError::Timeout) => println!("Request timed out"),
18//! Err(McError::DnsError(msg)) => println!("DNS error: {}", msg),
19//! Err(e) => println!("Other error: {}", e),
20//! }
21//!
22//! Ok(())
23//! }
24//! ```
25
26use thiserror::Error;
27
28/// Errors that can occur during Minecraft server status queries.
29///
30/// All errors implement `std::error::Error` and can be easily converted to
31/// user-friendly error messages using the `Display` trait.
32///
33/// # Error Types
34///
35/// - **DnsError**: DNS resolution failed (e.g., hostname not found)
36/// - **ConnectionError**: Failed to establish connection to server
37/// - **Timeout**: Request timed out
38/// - **InvalidResponse**: Server returned invalid or malformed data
39/// - **IoError**: I/O error occurred (wrapped `std::io::Error`)
40/// - **JsonError**: Failed to parse JSON response (wrapped `serde_json::Error`)
41/// - **Utf8Error**: Invalid UTF-8 in server response
42/// - **Base64Error**: Failed to decode base64 data (e.g., favicon)
43/// - **InvalidEdition**: Invalid server edition specified
44/// - **InvalidPort**: Invalid port number in address
45/// - **InvalidAddress**: Invalid address format
46#[derive(Error, Debug)]
47pub enum McError {
48 /// DNS resolution failed.
49 ///
50 /// This error occurs when the hostname cannot be resolved to an IP address,
51 /// or when an SRV record lookup fails.
52 ///
53 /// # Example
54 ///
55 /// ```no_run
56 /// # use rust_mc_status::McError;
57 /// # fn example() -> Result<(), McError> {
58 /// Err(McError::DnsError("Hostname not found".to_string()))
59 /// # }
60 /// ```
61 #[error("DNS resolution failed: {0}")]
62 DnsError(String),
63
64 /// Connection to server failed.
65 ///
66 /// This error occurs when a TCP/UDP connection cannot be established,
67 /// typically due to network issues or the server being unreachable.
68 ///
69 /// # Example
70 ///
71 /// ```no_run
72 /// # use rust_mc_status::McError;
73 /// # fn example() -> Result<(), McError> {
74 /// Err(McError::ConnectionError("Connection refused".to_string()))
75 /// # }
76 /// ```
77 #[error("Connection failed: {0}")]
78 ConnectionError(String),
79
80 /// Request timed out.
81 ///
82 /// This error occurs when the server does not respond within the configured
83 /// timeout duration. You can adjust the timeout using `McClient::with_timeout`.
84 ///
85 /// # Example
86 ///
87 /// ```no_run
88 /// # use rust_mc_status::McClient;
89 /// # use std::time::Duration;
90 /// # #[tokio::main]
91 /// # async fn main() {
92 /// let client = McClient::new().with_timeout(Duration::from_secs(2));
93 /// // If server doesn't respond within 2 seconds, Timeout error is returned
94 /// # }
95 /// ```
96 #[error("Timeout occurred")]
97 Timeout,
98
99 /// Server returned invalid or malformed response.
100 ///
101 /// This error occurs when the server response does not match the expected
102 /// protocol format, or contains invalid data.
103 ///
104 /// # Example
105 ///
106 /// ```no_run
107 /// # use rust_mc_status::McError;
108 /// # fn example() -> Result<(), McError> {
109 /// Err(McError::InvalidResponse("Response too short".to_string()))
110 /// # }
111 /// ```
112 #[error("Invalid server response: {0}")]
113 InvalidResponse(String),
114
115 /// I/O error occurred.
116 ///
117 /// This is a wrapper around `std::io::Error` for operations like reading
118 /// from or writing to network streams.
119 ///
120 /// # Example
121 ///
122 /// ```no_run
123 /// # use rust_mc_status::McError;
124 /// # use std::io;
125 /// # fn example() -> Result<(), McError> {
126 /// let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found");
127 /// Err(McError::IoError(io_error))
128 /// # }
129 /// ```
130 #[error("I/O error: {0}")]
131 IoError(#[from] std::io::Error),
132
133 /// JSON parsing error.
134 ///
135 /// This error occurs when the server response contains invalid JSON.
136 /// It's a wrapper around `serde_json::Error`.
137 ///
138 /// # Example
139 ///
140 /// ```no_run
141 /// # use rust_mc_status::McError;
142 /// # fn example() -> Result<(), McError> {
143 /// // Usually occurs when parsing Java server status JSON
144 /// # Ok(())
145 /// # }
146 /// ```
147 #[error("JSON parsing error: {0}")]
148 JsonError(#[from] serde_json::Error),
149
150 /// UTF-8 conversion error.
151 ///
152 /// This error occurs when the server response contains invalid UTF-8 sequences.
153 ///
154 /// # Example
155 ///
156 /// ```no_run
157 /// # use rust_mc_status::McError;
158 /// # fn example() -> Result<(), McError> {
159 /// // Usually occurs when reading server response
160 /// # Ok(())
161 /// # }
162 /// ```
163 #[error("UTF-8 conversion error: {0}")]
164 Utf8Error(#[from] std::string::FromUtf8Error),
165
166 /// Base64 decoding error.
167 ///
168 /// This error occurs when decoding base64-encoded data (e.g., server favicon)
169 /// fails.
170 ///
171 /// # Example
172 ///
173 /// ```no_run
174 /// # use rust_mc_status::{McClient, ServerEdition};
175 /// # #[tokio::main]
176 /// # async fn main() {
177 /// # let client = McClient::new();
178 /// # if let Ok(status) = client.ping("server.com", ServerEdition::Java).await {
179 /// # if let rust_mc_status::ServerData::Java(java) = status.data {
180 /// // Can occur when saving favicon
181 /// java.save_favicon("icon.png").unwrap();
182 /// # }
183 /// # }
184 /// # }
185 /// ```
186 #[error("Base64 decoding error: {0}")]
187 Base64Error(#[from] base64::DecodeError),
188
189 /// Invalid server edition specified.
190 ///
191 /// This error occurs when an invalid server edition is provided.
192 /// Valid editions are `Java` and `Bedrock`.
193 ///
194 /// # Example
195 ///
196 /// ```no_run
197 /// # use rust_mc_status::McError;
198 /// # use std::str::FromStr;
199 /// # use rust_mc_status::ServerEdition;
200 /// # fn example() -> Result<(), McError> {
201 /// ServerEdition::from_str("invalid")?;
202 /// # Ok(())
203 /// # }
204 /// ```
205 #[error("Invalid edition: {0}")]
206 InvalidEdition(String),
207
208 /// Invalid port number in address.
209 ///
210 /// This error occurs when the port in the address string cannot be parsed
211 /// as a valid `u16` value.
212 ///
213 /// # Example
214 ///
215 /// ```no_run
216 /// # use rust_mc_status::McClient;
217 /// # use rust_mc_status::ServerEdition;
218 /// # #[tokio::main]
219 /// # async fn main() {
220 /// let client = McClient::new();
221 /// // This will return InvalidPort error
222 /// let _ = client.ping("server.com:99999", ServerEdition::Java).await;
223 /// # }
224 /// ```
225 #[error("Invalid port: {0}")]
226 InvalidPort(String),
227
228 /// Invalid address format.
229 ///
230 /// This error occurs when the server address has an invalid format.
231 ///
232 /// # Example
233 ///
234 /// ```no_run
235 /// # use rust_mc_status::McError;
236 /// # fn example() -> Result<(), McError> {
237 /// Err(McError::InvalidAddress("Invalid format".to_string()))
238 /// # }
239 /// ```
240 #[error("Invalid address format: {0}")]
241 InvalidAddress(String),
242}