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::{LastFmClient, LastFmError};
12///
13/// #[tokio::main]
14/// async fn main() {
15///     let mut client = LastFmClient::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 [`LastFmClient::edit_scrobble_with_retry`](crate::LastFmClient::edit_scrobble_with_retry)
32/// automatically handle rate limiting errors by waiting and retrying:
33///
34/// ```rust,no_run
35/// # use lastfm_edit::{LastFmClient, ScrobbleEdit};
36/// # tokio_test::block_on(async {
37/// let mut client = LastFmClient::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}