bsky_sdk/
error.rs

1//! Error types for the Bsky SDK.
2use atrium_api::xrpc::error::XrpcErrorKind;
3use atrium_api::xrpc::http::StatusCode;
4use atrium_api::xrpc::Error as XrpcError;
5use std::fmt::Debug;
6use thiserror::Error;
7
8/// Error type for this crate.
9#[derive(Error, Debug)]
10pub enum Error {
11    #[error("not logged in")]
12    NotLoggedIn,
13    #[error("invalid AT URI")]
14    InvalidAtUri,
15    #[error("xrpc response error: {0}")]
16    Xrpc(Box<GenericXrpcError>),
17    #[error("loading config error: {0}")]
18    ConfigLoad(Box<dyn std::error::Error + Send + Sync + 'static>),
19    #[error("saving config error: {0}")]
20    ConfigSave(Box<dyn std::error::Error + Send + Sync + 'static>),
21    #[error(transparent)]
22    ApiType(#[from] atrium_api::error::Error),
23    #[error(transparent)]
24    Moderation(#[from] crate::moderation::Error),
25}
26
27/// Generic error type for XRPC errors.
28#[derive(Error, Debug)]
29pub enum GenericXrpcError {
30    Response { status: StatusCode, error: Option<String> },
31    Other(String),
32}
33
34impl std::fmt::Display for GenericXrpcError {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        match self {
37            Self::Response { status, error } => {
38                write!(f, "{}", status.as_str())?;
39                let Some(error) = &error else {
40                    return Ok(());
41                };
42                if !error.is_empty() {
43                    write!(f, " {error}")?;
44                }
45            }
46            Self::Other(s) => {
47                write!(f, "{s}")?;
48            }
49        }
50        Ok(())
51    }
52}
53
54impl<E> From<XrpcError<E>> for Error
55where
56    E: Debug,
57{
58    fn from(err: XrpcError<E>) -> Self {
59        if let XrpcError::XrpcResponse(e) = err {
60            Self::Xrpc(Box::new(GenericXrpcError::Response {
61                status: e.status,
62                error: e.error.map(|e| match e {
63                    XrpcErrorKind::Custom(_) => String::from("custom error"),
64                    XrpcErrorKind::Undefined(res) => res.to_string(),
65                }),
66            }))
67        } else {
68            Self::Xrpc(Box::new(GenericXrpcError::Other(format!("{err:?}"))))
69        }
70    }
71}
72
73/// Type alias to use this crate's [`Error`](enum@crate::Error) type in a [`Result`](core::result::Result).
74pub type Result<T> = core::result::Result<T, Error>;