Skip to main content

xmtp_api_backend/
client.rs

1use crate::endpoints::backend;
2use arc_swap::ArcSwap;
3use std::sync::Arc;
4use xmtp_configuration::LimitsConfiguration;
5use xmtp_proto::{
6    api::{ApiClientError, Client, Query},
7    api_client::XmtpBackendClient,
8    backend_v1::*,
9};
10
11/// Sends backend requests through one transport.
12#[derive(Clone, Debug)]
13pub struct BackendClient<C> {
14    pub(crate) client: C,
15    /// The shapes this deployment accepts (CFG-064). Swapped in once, by
16    /// `build`, after the configuration is read and before any stream opens.
17    /// The compiled defaults until then, which is what every transport built
18    /// without a client keeps.
19    pub(crate) limits: Arc<ArcSwap<LimitsConfiguration>>,
20}
21impl<C> BackendClient<C> {
22    pub fn new(client: C) -> Self {
23        Self {
24            client,
25            limits: Arc::new(ArcSwap::from_pointee(LimitsConfiguration::default())),
26        }
27    }
28    pub fn inner(&self) -> &C {
29        &self.client
30    }
31    /// What this transport chunks its streams and metadata reads to.
32    pub(crate) fn limits(&self) -> arc_swap::Guard<Arc<LimitsConfiguration>> {
33        self.limits.load()
34    }
35}
36#[xmtp_common::async_trait]
37impl<C: Client> XmtpBackendClient for BackendClient<C> {
38    type Error = ApiClientError;
39    async fn publish(&self, request: PublishRequest) -> Result<PublishResponse, Self::Error> {
40        backend::Publish(request).query(&self.client).await
41    }
42    async fn query(&self, request: QueryRequest) -> Result<QueryResponse, Self::Error> {
43        backend::Query(request).query(&self.client).await
44    }
45    async fn query_newest(
46        &self,
47        request: QueryNewestRequest,
48    ) -> Result<QueryNewestResponse, Self::Error> {
49        backend::QueryNewest(request).query(&self.client).await
50    }
51    async fn get_inbox_ids(
52        &self,
53        request: GetInboxIdsRequest,
54    ) -> Result<GetInboxIdsResponse, Self::Error> {
55        backend::GetInboxIds(request).query(&self.client).await
56    }
57    async fn get_configuration(
58        &self,
59        request: GetConfigurationRequest,
60    ) -> Result<GetConfigurationResponse, Self::Error> {
61        backend::GetConfiguration(request).query(&self.client).await
62    }
63    fn backend_url(&self) -> Option<&str> {
64        Some(self.client.host())
65    }
66
67    fn has_credential_source(&self) -> bool {
68        self.client.has_credential_source()
69    }
70
71    fn set_limits(&self, limits: Arc<LimitsConfiguration>) {
72        // A zero here would panic `chunks(0)` in `streams.rs`. CFG-031 keeps
73        // zeroes off the wire; this keeps them out of a snapshot an app built
74        // in Rust and supplied through a `ConfigProvider`.
75        self.limits.store(Arc::new(limits.without_zeroes()));
76    }
77    async fn verify_smart_contract_wallet_signatures(
78        &self,
79        request: VerifySmartContractWalletSignaturesRequest,
80    ) -> Result<VerifySmartContractWalletSignaturesResponse, Self::Error> {
81        backend::VerifySmartContractWalletSignatures(request)
82            .query(&self.client)
83            .await
84    }
85    async fn register(&self, request: RegisterRequest) -> Result<RecipientState, Self::Error> {
86        backend::Register(request).query(&self.client).await
87    }
88    async fn unregister(
89        &self,
90        request: UnregisterRequest,
91    ) -> Result<UnregisterResponse, Self::Error> {
92        backend::Unregister(request).query(&self.client).await
93    }
94    async fn update_subscriptions(
95        &self,
96        request: UpdateSubscriptionsRequest,
97    ) -> Result<RecipientState, Self::Error> {
98        backend::UpdateSubscriptions(request)
99            .query(&self.client)
100            .await
101    }
102}
103
104#[xmtp_common::async_trait]
105impl<C: xmtp_proto::api::IsConnectedCheck> xmtp_proto::api::IsConnectedCheck for BackendClient<C> {
106    async fn is_connected(&self) -> bool {
107        self.client.is_connected().await
108    }
109}