xmtp_api_d14n/queries/
builder.rs1use derive_builder::UninitializedFieldError;
4use std::sync::Arc;
5use thiserror::Error;
6use xmtp_api_grpc::error::{GrpcBuilderError, GrpcError};
7use xmtp_common::{MaybeSend, MaybeSync};
8use xmtp_id::scw_verifier::VerifierError;
9use xmtp_proto::api::ApiClientError;
10use xmtp_proto::types::AppVersion;
11
12use crate::protocol::{CursorStore, FullXmtpApiArc, FullXmtpApiBox, NoCursorStore};
13use crate::{
14 AuthCallback, AuthHandle, ClientBundle, ClientBundleBuilder, ClientKind, D14nClient,
15 MultiNodeClientBuilderError, ReadWriteClientBuilderError, ReadonlyClientBuilderError, V3Client,
16};
17
18mod impls;
19
20#[derive(Clone, Default)]
23pub struct MessageBackendBuilder {
24 client_bundle: ClientBundleBuilder,
25 cursor_store: Option<Arc<dyn CursorStore>>,
26}
27
28#[derive(Error, Debug)]
29pub enum MessageBackendBuilderError {
30 #[error("V3 Host is required")]
31 MissingV3Host,
32 #[error(transparent)]
33 GrpcBuilder(#[from] GrpcBuilderError),
34 #[error(transparent)]
35 MultiNode(#[from] MultiNodeClientBuilderError),
36 #[error(transparent)]
37 Scw(#[from] VerifierError),
38 #[error("failed to build stateful local client, cursor store not replaced, type {0}")]
39 CursorStoreNotReplaced(&'static str),
40 #[error("error while building read/write api client {0},")]
41 UninitializedField(#[from] ReadWriteClientBuilderError),
42 #[error(transparent)]
43 ReadonlyBuilder(#[from] ReadonlyClientBuilderError),
44 #[error(transparent)]
45 Builder(#[from] UninitializedFieldError),
46 #[error("client kind {0} is currently unsupported")]
47 UnsupportedClient(ClientKind),
48}
49
50pub trait ToDynApi: MaybeSend + MaybeSync {
53 type Error: MaybeSend + MaybeSync;
54 fn boxed(self) -> FullXmtpApiBox<Self::Error>;
55 fn arced(self) -> FullXmtpApiArc<Self::Error>;
56}
57
58impl MessageBackendBuilder {
59 pub fn app_version(&mut self, version: impl Into<AppVersion>) -> &mut Self {
61 self.client_bundle.app_version(version);
62 self
63 }
64
65 pub fn v3_host<S: AsRef<str>>(&mut self, host: S) -> &mut Self {
71 self.client_bundle.v3_host(host.as_ref());
72 self
73 }
74
75 pub fn gateway_host<S: AsRef<str>>(&mut self, host: S) -> &mut Self {
81 self.client_bundle.gateway_host(host.as_ref());
82 self
83 }
84
85 pub fn maybe_gateway_host<S: Into<String>>(&mut self, gateway_host: Option<S>) -> &mut Self {
91 self.client_bundle.maybe_gateway_host(gateway_host);
92 self
93 }
94
95 pub fn is_secure(&mut self, is_secure: bool) -> &mut Self {
97 self.client_bundle.is_secure(is_secure);
98 self
99 }
100
101 pub fn cursor_store(&mut self, store: impl CursorStore + 'static) -> &mut Self {
102 self.cursor_store = Some(Arc::new(store) as Arc<_>);
103 self
104 }
105
106 pub fn readonly(&mut self, readonly: bool) -> &mut Self {
107 self.client_bundle.readonly(readonly);
108 self
109 }
110
111 pub fn from_bundle(
112 &mut self,
113 bundle: ClientBundle<GrpcError>,
114 ) -> Result<FullXmtpApiArc<ApiClientError<GrpcError>>, MessageBackendBuilderError> {
115 let cursor_store = self
116 .cursor_store
117 .clone()
118 .unwrap_or(Arc::new(NoCursorStore) as Arc<dyn CursorStore>);
119
120 match bundle.kind() {
121 ClientKind::D14n => Ok(D14nClient::new(bundle, cursor_store)?.arced()),
122 ClientKind::V3 => Ok(V3Client::new(bundle, cursor_store).arced()),
123 ClientKind::Hybrid => Err(MessageBackendBuilderError::UnsupportedClient(
124 ClientKind::Hybrid,
125 )),
126 }
127 }
128
129 pub fn maybe_auth_callback(&mut self, callback: Option<Arc<dyn AuthCallback>>) -> &mut Self {
130 self.client_bundle.maybe_auth_callback(callback);
131 self
132 }
133
134 pub fn maybe_auth_handle(&mut self, handle: Option<AuthHandle>) -> &mut Self {
135 self.client_bundle.maybe_auth_handle(handle);
136 self
137 }
138
139 pub fn build(
141 &mut self,
142 ) -> Result<FullXmtpApiArc<ApiClientError<GrpcError>>, MessageBackendBuilderError> {
143 let Self { client_bundle, .. } = self;
144 let bundle = client_bundle.build()?;
145 self.from_bundle(bundle)
146 }
147}