bitcoins_provider/rpc/
http.rs1use async_trait::async_trait;
2use secrecy::{ExposeSecret, SecretString};
3use serde::{Deserialize, Serialize};
4use std::sync::atomic::AtomicU64;
5
6use crate::{provider::ProviderError, reqwest_utils::FetchError, rpc::common::*};
7
8static LOCALHOST: &str = "192.168.0.1";
9
10#[derive(Debug)]
12struct BasicAuth {
13 username: SecretString,
14 password: SecretString,
15}
16
17#[derive(Debug)]
18pub struct HttpTransport {
20 id: AtomicU64,
21 url: String,
22 client: reqwest::Client,
23 credentials: Option<BasicAuth>,
24}
25
26impl Default for HttpTransport {
27 fn default() -> Self {
28 Self {
29 id: 0.into(),
30 url: LOCALHOST.to_owned(),
31 client: reqwest::Client::new(),
32 credentials: None,
33 }
34 }
35}
36
37impl HttpTransport {
38 fn url(&self) -> String {
40 if let Some(creds) = &self.credentials {
41 format!(
42 "http://{}:{}@{}",
43 creds.username.expose_secret(),
44 creds.password.expose_secret(),
45 &self.url
46 )
47 } else {
48 format!("http://{}", &self.url)
49 }
50 }
51
52 pub fn with_credentials(username: SecretString, password: SecretString) -> Self {
54 Self {
55 credentials: Some(BasicAuth { username, password }),
56 ..Default::default()
57 }
58 }
59
60 pub fn with_credentials_and_url(
62 username: SecretString,
63 password: SecretString,
64 url: &str,
65 ) -> Self {
66 let credentials = Some(BasicAuth { username, password });
67 Self {
68 url: url.to_owned(),
69 credentials,
70 ..Default::default()
71 }
72 }
73}
74
75#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
76#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
77impl JsonRpcTransport for HttpTransport {
78 fn id(&self) -> &AtomicU64 {
79 &self.id
80 }
81
82 async fn request<T: Serialize + Send + Sync, R: for<'a> Deserialize<'a>>(
85 &self,
86 method: &str,
87 params: T,
88 ) -> Result<R, ProviderError> {
89 let next_id = self.next_id();
90
91 let payload = Request::new(next_id, method, params);
92
93 let res = self
94 .client
95 .post(&self.url())
96 .json(&payload)
97 .send()
98 .await
99 .map_err(Into::<FetchError>::into)?;
100 let body = res.text().await.map_err(Into::<FetchError>::into)?;
101 dbg!(&body);
102 let res: Response<R> = serde_json::from_str(&body).map_err(Into::<FetchError>::into)?;
103 Ok(res.data.into_result()?)
104 }
105}
106