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 http_client = http_client::native::NativeClient::new();
16///
17///     match LastFmEditClientImpl::login_with_credentials(Box::new(http_client), "username", "password").await {
18///         Ok(client) => 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_single`](crate::LastFmEditClient::edit_scrobble_single)
32/// automatically handle rate limiting errors by waiting and retrying:
33///
34/// ```rust,no_run
35/// # use lastfm_edit::{LastFmEditClient, LastFmEditClientImpl, LastFmEditSession, ScrobbleEdit};
36/// # tokio_test::block_on(async {
37/// # let test_session = LastFmEditSession::new("test".to_string(), vec!["sessionid=.test123".to_string()], Some("csrf".to_string()), "https://www.last.fm".to_string());
38/// let mut client = LastFmEditClientImpl::from_session(Box::new(http_client::native::NativeClient::new()), test_session);
39///
40/// let edit = ScrobbleEdit::from_track_info("Track", "Album", "Artist", 1640995200);
41///
42/// // Standard edit operation
43/// match client.edit_scrobble(&edit).await {
44///     Ok(response) => println!("Edit completed: {:?}", response),
45///     Err(e) => eprintln!("Edit failed: {}", 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}