lastfm_edit/error.rs
1use thiserror::Error;
2
3/// Error types for Last.fm operations.
4///
5/// This enum covers all possible errors that can occur when interacting with Last.fm,
6/// including network issues, authentication failures, parsing errors, and rate limiting.
7///
8/// # Error Handling Examples
9///
10/// ```rust,no_run
11/// use lastfm_edit::{LastFmEditClient, LastFmEditClientImpl, LastFmError};
12///
13/// #[tokio::main]
14/// async fn main() {
15/// let mut client = LastFmEditClientImpl::new(Box::new(http_client::native::NativeClient::new()));
16///
17/// match client.login("username", "password").await {
18/// Ok(()) => println!("Login successful"),
19/// Err(LastFmError::Auth(msg)) => eprintln!("Authentication failed: {}", msg),
20/// Err(LastFmError::RateLimit { retry_after }) => {
21/// eprintln!("Rate limited, retry in {} seconds", retry_after);
22/// }
23/// Err(LastFmError::Http(msg)) => eprintln!("Network error: {}", msg),
24/// Err(e) => eprintln!("Other error: {}", e),
25/// }
26/// }
27/// ```
28///
29/// # Automatic Retry
30///
31/// Some operations like [`LastFmEditClient::edit_scrobble_with_retry`](crate::LastFmEditClient::edit_scrobble_with_retry)
32/// automatically handle rate limiting errors by waiting and retrying:
33///
34/// ```rust,no_run
35/// # use lastfm_edit::{LastFmEditClient, LastFmEditClientImpl, ScrobbleEdit};
36/// # tokio_test::block_on(async {
37/// let mut client = LastFmEditClientImpl::new(Box::new(http_client::native::NativeClient::new()));
38/// // client.login(...).await?;
39///
40/// let edit = ScrobbleEdit::from_track_info("Track", "Album", "Artist", 1640995200);
41///
42/// // This will automatically retry on rate limits up to 3 times
43/// match client.edit_scrobble_with_retry(&edit, 3).await {
44/// Ok(response) => println!("Edit completed: {:?}", response),
45/// Err(e) => eprintln!("Edit failed after retries: {}", e),
46/// }
47/// # Ok::<(), Box<dyn std::error::Error>>(())
48/// # });
49/// ```
50#[derive(Error, Debug)]
51pub enum LastFmError {
52 /// HTTP/network related errors.
53 ///
54 /// This includes connection failures, timeouts, DNS errors, and other
55 /// low-level networking issues.
56 #[error("HTTP error: {0}")]
57 Http(String),
58
59 /// Authentication failures.
60 ///
61 /// This occurs when login credentials are invalid, sessions expire,
62 /// or authentication is required but not provided.
63 ///
64 /// # Common Causes
65 /// - Invalid username/password
66 /// - Expired session cookies
67 /// - Account locked or suspended
68 /// - Two-factor authentication required
69 #[error("Authentication failed: {0}")]
70 Auth(String),
71
72 /// CSRF token not found in response.
73 ///
74 /// This typically indicates that Last.fm's page structure has changed
75 /// or that the request was blocked.
76 #[error("CSRF token not found")]
77 CsrfNotFound,
78
79 /// Failed to parse Last.fm's response.
80 ///
81 /// This can happen when Last.fm changes their HTML structure or
82 /// returns unexpected data formats.
83 #[error("Failed to parse response: {0}")]
84 Parse(String),
85
86 /// Rate limiting from Last.fm.
87 ///
88 /// Last.fm has rate limits to prevent abuse. When hit, the client
89 /// should wait before making more requests.
90 ///
91 /// The `retry_after` field indicates how many seconds to wait before
92 /// the next request attempt.
93 #[error("Rate limited, retry after {retry_after} seconds")]
94 RateLimit {
95 /// Number of seconds to wait before retrying
96 retry_after: u64,
97 },
98
99 /// Scrobble edit operation failed.
100 ///
101 /// This is returned when an edit request is properly formatted and sent,
102 /// but Last.fm rejects it for business logic reasons.
103 #[error("Edit failed: {0}")]
104 EditFailed(String),
105
106 /// File system I/O errors.
107 ///
108 /// This can occur when saving debug responses or other file operations.
109 #[error("IO error: {0}")]
110 Io(#[from] std::io::Error),
111}