1use std::sync::{Arc, Mutex};
2
3use lwk_wollet::{
4 asyncr,
5 clients::blocking::{self, BlockchainBackend},
6};
7
8use crate::{BlockHeader, LwkError, Network, Transaction, Txid, Update, Wollet};
9
10#[derive(uniffi::Object, Debug)]
15pub struct EsploraClient {
16 pub(crate) inner: Mutex<blocking::EsploraClient>,
17
18 pub(crate) builder: lwk_wollet::clients::EsploraClientBuilder,
20}
21
22#[derive(uniffi::Record)]
24pub struct EsploraClientBuilder {
25 base_url: String,
26 network: Arc<Network>,
27 #[uniffi(default = false)]
28 waterfalls: bool,
29 #[uniffi(default = None)]
30 concurrency: Option<u32>,
31 #[uniffi(default = None)]
32 timeout: Option<u8>,
33 #[uniffi(default = false)]
34 utxo_only: bool,
35}
36
37impl From<EsploraClientBuilder> for lwk_wollet::clients::EsploraClientBuilder {
38 fn from(builder: EsploraClientBuilder) -> Self {
39 let mut result = lwk_wollet::clients::EsploraClientBuilder::new(
40 &builder.base_url,
41 (*builder.network.as_ref()).into(),
42 );
43 if builder.waterfalls {
44 result = result.waterfalls(true);
45 }
46 if let Some(concurrency) = builder.concurrency {
47 result = result.concurrency(concurrency as usize);
48 }
49 if let Some(timeout) = builder.timeout {
50 result = result.timeout(timeout);
51 }
52 if builder.utxo_only {
53 result = result.utxo_only(true);
54 }
55 result
56 }
57}
58
59#[uniffi::export]
60impl EsploraClient {
61 #[uniffi::constructor]
63 pub fn new(url: &str, network: &Network) -> Result<Arc<Self>, LwkError> {
64 let builder = lwk_wollet::clients::EsploraClientBuilder::new(url, network.into());
65 let client = builder.clone().build_blocking()?;
66 Ok(Arc::new(Self {
67 inner: Mutex::new(client),
68 builder,
69 }))
70 }
71
72 #[uniffi::constructor]
74 pub fn new_waterfalls(url: &str, network: &Network) -> Result<Arc<Self>, LwkError> {
75 let builder =
76 lwk_wollet::clients::EsploraClientBuilder::new(url, network.into()).waterfalls(true);
77 let client = builder.clone().build_blocking()?;
78 Ok(Arc::new(Self {
79 inner: Mutex::new(client),
80 builder,
81 }))
82 }
83
84 #[uniffi::constructor]
86 pub fn from_builder(builder: EsploraClientBuilder) -> Result<Arc<Self>, LwkError> {
87 let builder = lwk_wollet::clients::EsploraClientBuilder::from(builder);
88 let client = builder.clone().build_blocking()?;
89 Ok(Arc::new(Self {
90 inner: Mutex::new(client),
91 builder,
92 }))
93 }
94
95 pub fn broadcast(&self, tx: &Transaction) -> Result<Arc<Txid>, LwkError> {
97 Ok(Arc::new(self.inner.lock()?.broadcast(tx.as_ref())?.into()))
98 }
99
100 pub fn full_scan(&self, wollet: &Wollet) -> Result<Option<Arc<Update>>, LwkError> {
111 self.full_scan_to_index(wollet, 0)
112 }
113
114 pub fn full_scan_to_index(
127 &self,
128 wollet: &Wollet,
129 index: u32,
130 ) -> Result<Option<Arc<Update>>, LwkError> {
131 let wollet = wollet.inner_wollet()?;
132 let update: Option<lwk_wollet::Update> = self
133 .inner
134 .lock()?
135 .full_scan_to_index(&wollet.state(), index)?;
136 Ok(update.map(Into::into).map(Arc::new))
137 }
138
139 pub fn tip(&self) -> Result<Arc<BlockHeader>, LwkError> {
141 let tip = self.inner.lock()?.tip()?;
142 Ok(Arc::new(tip.into()))
143 }
144}
145
146impl EsploraClient {
147 #[allow(unused)] pub(crate) fn clone_blocking_client(&self) -> Result<blocking::EsploraClient, LwkError> {
150 Ok(self.builder.clone().build_blocking()?)
151 }
152
153 #[allow(unused)] pub(crate) fn clone_async_client(&self) -> Result<asyncr::EsploraClient, LwkError> {
156 Ok(self.builder.clone().build()?)
157 }
158}