cdk_http_client/transport/
mod.rs1use std::fmt::Debug;
4
5use async_trait::async_trait;
6use cashu::nuts::nut22::AuthToken;
7use serde::de::DeserializeOwned;
8use serde::Serialize;
9use url::Url;
10
11#[cfg(any(target_arch = "wasm32", feature = "bitreq", feature = "reqwest"))]
12use crate::{HttpClient, HttpClientBuilder};
13use crate::{HttpError, RawResponse};
14
15#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
21#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
22pub trait Transport: Send + Sync + Debug + Clone {
23 async fn ws_connect(
25 &self,
26 url: &str,
27 headers: &[(&str, &str)],
28 ) -> Result<(crate::ws::WsSender, crate::ws::WsReceiver), crate::ws::WsError> {
29 crate::ws::connect(url, headers).await
30 }
31
32 fn with_proxy(
38 &mut self,
39 proxy: Url,
40 host_matcher: Option<&str>,
41 accept_invalid_certs: bool,
42 ) -> Result<(), HttpError>;
43
44 async fn resolve_dns_txt(&self, _domain: &str) -> Result<Vec<String>, HttpError> {
50 Err(HttpError::Other(
51 "DNS TXT resolution is not enabled for this transport".to_owned(),
52 ))
53 }
54
55 async fn http_get<R>(&self, url: Url, auth: Option<AuthToken>) -> Result<R, HttpError>
57 where
58 R: DeserializeOwned;
59
60 async fn http_get_raw(
62 &self,
63 url: Url,
64 auth: Option<AuthToken>,
65 ) -> Result<RawResponse, HttpError>;
66
67 async fn http_post<P, R>(
69 &self,
70 url: Url,
71 auth_token: Option<AuthToken>,
72 payload: &P,
73 ) -> Result<R, HttpError>
74 where
75 P: Serialize + Send + Sync,
76 R: DeserializeOwned;
77
78 async fn http_post_form_raw<P>(
80 &self,
81 url: Url,
82 auth_token: Option<AuthToken>,
83 payload: &P,
84 ) -> Result<RawResponse, HttpError>
85 where
86 P: Serialize + Send + Sync;
87}
88
89#[cfg(any(target_arch = "wasm32", feature = "bitreq", feature = "reqwest"))]
91#[derive(Debug, Clone)]
92pub struct Async {
93 inner: HttpClient,
94}
95
96#[cfg(any(target_arch = "wasm32", feature = "bitreq", feature = "reqwest"))]
97impl Default for Async {
98 fn default() -> Self {
99 Self {
100 inner: HttpClient::builder()
101 .no_redirects()
102 .build()
103 .expect("default no-redirect client"),
104 }
105 }
106}
107
108#[cfg(any(target_arch = "wasm32", feature = "bitreq", feature = "reqwest"))]
109#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
110#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
111impl Transport for Async {
112 fn with_proxy(
113 &mut self,
114 proxy: Url,
115 host_matcher: Option<&str>,
116 accept_invalid_certs: bool,
117 ) -> Result<(), HttpError> {
118 let builder = HttpClientBuilder::default()
119 .no_redirects()
120 .danger_accept_invalid_certs(accept_invalid_certs);
121
122 let builder = match host_matcher {
123 Some(pattern) => builder.proxy_with_matcher(proxy, pattern)?,
124 None => builder.proxy(proxy),
125 };
126
127 self.inner = builder.build()?;
128 Ok(())
129 }
130
131 #[cfg(all(feature = "bip353", not(target_arch = "wasm32")))]
132 async fn resolve_dns_txt(&self, domain: &str) -> Result<Vec<String>, HttpError> {
133 crate::dns::resolve_dns_txt(domain).await
134 }
135
136 async fn http_get<R>(&self, url: Url, auth: Option<AuthToken>) -> Result<R, HttpError>
137 where
138 R: DeserializeOwned,
139 {
140 self.http_get_raw(url, auth).await?.json_or_status_error()
141 }
142
143 async fn http_get_raw(
144 &self,
145 url: Url,
146 auth: Option<AuthToken>,
147 ) -> Result<RawResponse, HttpError> {
148 let url_str = url.to_string();
149 let mut request = self.inner.get(&url_str);
150
151 if let Some(auth) = auth {
152 request = request.header(auth.header_key(), auth.to_string());
153 }
154
155 request.send().await
156 }
157
158 async fn http_post<P, R>(
159 &self,
160 url: Url,
161 auth_token: Option<AuthToken>,
162 payload: &P,
163 ) -> Result<R, HttpError>
164 where
165 P: Serialize + Send + Sync,
166 R: DeserializeOwned,
167 {
168 let url_str = url.to_string();
169 let mut request = self.inner.post(&url_str).json(payload);
170
171 if let Some(auth) = auth_token {
172 request = request.header(auth.header_key(), auth.to_string());
173 }
174
175 request.send_json::<R>().await
176 }
177
178 async fn http_post_form_raw<P>(
179 &self,
180 url: Url,
181 auth_token: Option<AuthToken>,
182 payload: &P,
183 ) -> Result<RawResponse, HttpError>
184 where
185 P: Serialize + Send + Sync,
186 {
187 let url_str = url.to_string();
188 let mut request = self.inner.post(&url_str).form(payload);
189
190 if let Some(auth) = auth_token {
191 request = request.header(auth.header_key(), auth.to_string());
192 }
193
194 request.send().await
195 }
196}
197
198#[cfg(all(
199 feature = "bitreq",
200 not(feature = "reqwest"),
201 not(target_arch = "wasm32")
202))]
203pub type BitreqTransport = Async;
205
206#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))]
207pub type ReqwestTransport = Async;
209
210#[cfg(all(feature = "tor", not(target_arch = "wasm32")))]
211mod tor_transport;
212
213#[cfg(all(feature = "tor", not(target_arch = "wasm32")))]
214pub use self::tor_transport::TorAsync;