xmtp_proto/traits/
error.rs1use crate::api_client::AggregateStats;
2use crate::{ApiEndpoint, ProtoError};
3use thiserror::Error;
4use xmtp_common::{BoxDynError, RetryableError, retryable};
5
6#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum ApiClientError<E: std::error::Error> {
9 #[error(
10 "api client at endpoint \"{}\" has error {}. \n {:?} \n",
11 endpoint,
12 source,
13 stats
14 )]
15 ClientWithEndpointAndStats {
16 endpoint: String,
17 source: E,
18 stats: AggregateStats,
19 },
20 #[error("API Error {}, \n {:?} \n", e, stats)]
21 ErrorWithStats {
22 e: Box<dyn RetryableError>,
23 stats: AggregateStats,
24 },
25 #[error("api client at endpoint \"{}\" has error {}", endpoint, source)]
27 ClientWithEndpoint {
28 endpoint: String,
29 source: E,
31 },
32 #[error("client errored {}", source)]
33 Client { source: E },
34 #[error(transparent)]
35 Http(#[from] http::Error),
36 #[error(transparent)]
37 Body(#[from] BodyError),
38 #[error(transparent)]
39 DecodeError(#[from] prost::DecodeError),
40 #[error(transparent)]
41 Conversion(#[from] crate::ConversionError),
42 #[error(transparent)]
43 ProtoError(#[from] ProtoError),
44 #[error(transparent)]
45 InvalidUri(#[from] http::uri::InvalidUri),
46 #[error(transparent)]
47 Expired(#[from] xmtp_common::time::Expired),
48 #[error("{0}")]
49 Other(Box<dyn RetryableError>),
50 #[error("{0}")]
51 OtherUnretryable(BoxDynError),
52 #[error("Writes are disabled on this client.")]
53 WritesDisabled,
54}
55
56impl<E> ApiClientError<E>
57where
58 E: std::error::Error + 'static,
59{
60 pub fn new(endpoint: ApiEndpoint, source: E) -> Self {
61 Self::ClientWithEndpoint {
62 endpoint: endpoint.to_string(),
63 source,
64 }
65 }
66
67 pub fn endpoint(self, endpoint: String) -> Self {
69 match self {
70 Self::Client { source } => Self::ClientWithEndpoint { source, endpoint },
71 v => v,
72 }
73 }
74}
75
76impl<E: std::error::Error> ApiClientError<E> {
77 pub fn other<R: RetryableError + 'static>(e: R) -> Self {
78 ApiClientError::Other(Box::new(e))
79 }
80}
81
82impl<E> RetryableError for ApiClientError<E>
83where
84 E: RetryableError + std::error::Error + 'static,
85{
86 fn is_retryable(&self) -> bool {
87 use ApiClientError::*;
88 match self {
89 ClientWithEndpointAndStats { source, .. } => retryable!(source),
90 ErrorWithStats { e, .. } => retryable!(e),
91 Client { source } => retryable!(*source),
92 ClientWithEndpoint { source, .. } => retryable!(source),
93 Body(e) => retryable!(e),
94 Http(_) => true,
95 DecodeError(_) => false,
96 Conversion(_) => false,
97 ProtoError(_) => false,
98 InvalidUri(_) => false,
99 Expired(_) => true,
100 Other(r) => retryable!(r),
101 OtherUnretryable(_) => false,
102 WritesDisabled => false,
103 }
104 }
105}
106
107impl<E: std::error::Error> From<std::convert::Infallible> for ApiClientError<E> {
109 fn from(_v: std::convert::Infallible) -> ApiClientError<E> {
110 unreachable!("Infallible errors can never occur")
111 }
112}
113
114#[derive(Debug, Error)]
115pub enum BodyError {
116 #[error(transparent)]
117 UninitializedField(#[from] derive_builder::UninitializedFieldError),
118 #[error(transparent)]
119 Conversion(#[from] crate::ConversionError),
120}
121
122impl RetryableError for BodyError {
123 fn is_retryable(&self) -> bool {
124 false
125 }
126}