Skip to main content

poirebot_licorice/
errors.rs

1//! Structures to investogate errors from API
2
3use reqwest::{Response, StatusCode};
4use serde::Deserialize;
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8/// Encompasses all possible errors emitted by the client
9pub enum LichessError {
10    /// Error when the limit is reached
11    #[error("exceeded request limit")]
12    RateLimited(Option<usize>),
13    /// Propagated errors from the reqwest crate
14    #[error("request error: {0}")]
15    Request(#[from] reqwest::Error),
16    /// Errors for when server returns non 200 response
17    #[error("status code {0}: {1}")]
18    StatusCode(u16, String),
19    /// If the API has a designated error message for the request
20    #[error("lichess error: {0}")]
21    API(#[from] APIError),
22    /// (de)serializing and related errors
23    #[error("json parse error: {0}")]
24    ParseJSON(#[from] serde_json::Error),
25    /// Errors while reading buffers
26    #[error("input/output error: {0}")]
27    IO(#[from] std::io::Error),
28}
29
30impl LichessError {
31    pub(crate) async fn from_response(response: Response) -> Self {
32        match response.status() {
33            StatusCode::TOO_MANY_REQUESTS => Self::RateLimited(
34                response
35                    .headers()
36                    .get(reqwest::header::RETRY_AFTER)
37                    .and_then(|header| header.to_str().ok())
38                    .and_then(|duration| duration.parse().ok()),
39            ),
40            status => response
41                .json::<APIError>()
42                .await
43                .map(Into::into)
44                .unwrap_or_else(|_| status.into()),
45        }
46    }
47}
48
49impl From<StatusCode> for LichessError {
50    fn from(code: StatusCode) -> Self {
51        Self::StatusCode(
52            code.as_u16(),
53            code.canonical_reason().unwrap_or("unknown").to_string(),
54        )
55    }
56}
57
58/// Error response objects returned by the server
59#[derive(Debug, Error, Deserialize)]
60#[error("error: {error}")]
61pub struct APIError {
62    error: String,
63}