1#![warn(clippy::unwrap_used)]
2
3pub mod configuration;
4pub mod identity;
5pub mod mls;
6mod notification;
7pub mod scw_verifier;
8#[cfg(any(test, feature = "test-utils"))]
9pub mod test_utils;
10
11use std::sync::Arc;
12
13use xmtp_common::{ErrorCode, ExponentialBackoff, Retry, RetryableError, retryable};
14pub use xmtp_proto::api_client::XmtpApi;
15
16pub use identity::*;
17pub use mls::*;
18pub mod chunk;
19pub use chunk::PublishUnit;
20
21pub type Result<T> = std::result::Result<T, ApiError>;
22
23pub mod strategies {
24 use super::*;
25 pub fn exponential_cooldown() -> Retry<ExponentialBackoff> {
26 xmtp_common::Retry::builder().build()
27 }
28}
29
30pub fn dyn_err(e: impl RetryableError + 'static) -> ApiError {
37 fn find(error: &(dyn std::any::Any + 'static)) -> Option<xmtp_proto::api::AuthError> {
38 if let Some(xmtp_proto::api::ApiClientError::Auth(auth)) = error.downcast_ref() {
39 return Some(*auth);
40 }
41 if let Some(auth) = error.downcast_ref::<xmtp_proto::api::AuthError>() {
42 return Some(*auth);
43 }
44 if let Some(boxed) = error.downcast_ref::<Box<xmtp_proto::api::ApiClientError>>() {
48 return find(&**boxed);
49 }
50 if let Some(boxed) = error.downcast_ref::<Box<xmtp_proto::api::AuthError>>() {
51 return Some(**boxed);
52 }
53 None
54 }
55 if let Some(auth) = find(&e) {
56 return ApiError::Auth(auth);
57 }
58 ApiError::Api(xmtp_proto::api::NetworkError::new(e))
59}
60
61#[derive(Debug, thiserror::Error, ErrorCode)]
62pub enum ApiError {
63 #[error(transparent)]
64 #[error_code(inherit)]
65 Auth(#[from] xmtp_proto::api::AuthError),
66 #[error("api client error {0}")]
70 Api(#[source] xmtp_proto::api::NetworkError),
71 #[error("identity history changed")]
73 IdentityUpdateConflict,
74 #[error("envelope exceeds the byte limit")]
76 EnvelopeTooLarge,
77 #[error("atomic publish unit exceeds a request limit")]
79 UnitTooLarge,
80 #[error("one envelope response exceeds a backend limit")]
82 ResponseTooLarge,
83 #[error("invalid backend request: {0}")]
85 InvalidRequest(&'static str),
86 #[error("invalid backend response: {0}")]
88 InvalidResponse(&'static str),
89 #[error(transparent)]
91 InvalidEnvelope(#[from] xmtp_mls_validation::ValidationError),
92 #[error(transparent)]
94 Envelope(#[from] xmtp_api_backend::envelope::EnvelopeError),
95 #[error(transparent)]
99 ProtoConversion(#[from] xmtp_proto::ConversionError),
100}
101
102impl RetryableError for ApiError {
103 fn is_retryable(&self) -> bool {
104 match self {
105 Self::Auth(e) => retryable!(e),
106 Self::Api(e) => retryable!(e),
107 _ => false,
108 }
109 }
110}
111
112#[derive(Clone, Debug)]
113pub struct ApiClientWrapper<ApiClient> {
114 pub api_client: ApiClient,
116 pub(crate) retry_strategy: Arc<Retry<ExponentialBackoff>>,
117 pub(crate) inbox_id: Option<String>,
118 pub(crate) configuration: Arc<xmtp_configuration::ServerConfiguration>,
123}
124
125impl<ApiClient> ApiClientWrapper<ApiClient> {
126 pub fn new(api_client: ApiClient, retry_strategy: Retry<ExponentialBackoff>) -> Self {
127 Self {
128 api_client,
129 retry_strategy: retry_strategy.into(),
130 inbox_id: None,
131 configuration: Arc::default(),
132 }
133 }
134
135 pub fn map<F, NewApiClient>(self, f: F) -> ApiClientWrapper<NewApiClient>
136 where
137 F: FnOnce(ApiClient) -> NewApiClient,
138 {
139 ApiClientWrapper {
140 api_client: f(self.api_client),
141 retry_strategy: self.retry_strategy,
142 inbox_id: self.inbox_id,
143 configuration: self.configuration,
144 }
145 }
146
147 pub fn set_configuration(
150 &mut self,
151 configuration: Arc<xmtp_configuration::ServerConfiguration>,
152 ) {
153 self.configuration = configuration;
154 }
155
156 pub fn configuration(&self) -> &xmtp_configuration::ServerConfiguration {
158 &self.configuration
159 }
160
161 pub fn limits(&self) -> &xmtp_configuration::LimitsConfiguration {
163 &self.configuration.limits
164 }
165
166 pub fn attach_inbox_id(&mut self, inbox_id: Option<String>) {
169 self.inbox_id = inbox_id;
170 }
171}
172
173xmtp_common::if_native! {
174 #[cfg(test)]
175 #[ctor::ctor(unsafe)]
176 fn _setup() {
177 xmtp_common::logger()
178 }
179}
180
181#[cfg(test)]
182mod tests;