fedimint_connectors/
http.rs1use std::sync::Arc;
2
3use fedimint_core::util::{FmtCompact as _, SafeUrl};
4use fedimint_core::{apply, async_trait_maybe_send};
5use reqwest::{Method, StatusCode};
6use serde_json::Value;
7
8use crate::error::{ConnectorError, ServerError};
9use crate::{
10 Connectivity, DynGatewayConnection, DynGuaridianConnection, IConnection, IGatewayConnection,
11 ServerResult,
12};
13
14#[derive(Clone, Debug, Default)]
15pub(crate) struct HttpConnector {
16 client: Arc<reqwest::Client>,
17}
18
19#[async_trait::async_trait]
20impl crate::Connector for HttpConnector {
21 async fn connect_guardian(
22 &self,
23 _url: &SafeUrl,
24 _api_secret: Option<&str>,
25 ) -> ServerResult<DynGuaridianConnection> {
26 Err(ServerError::InternalClientError(
27 "Unsupported transport mechanism".to_string(),
28 ))
29 }
30
31 async fn connect_gateway(&self, url: &SafeUrl) -> Result<DynGatewayConnection, ConnectorError> {
32 let http_connection = HttpConnection {
33 client: self.client.clone(),
34 base_url: url.clone(),
35 };
36
37 Ok(IGatewayConnection::into_dyn(http_connection))
38 }
39
40 fn connectivity(&self, _url: &SafeUrl) -> Connectivity {
41 Connectivity::Direct
42 }
43}
44
45#[derive(Debug)]
46pub(crate) struct HttpConnection {
47 client: Arc<reqwest::Client>,
48 base_url: SafeUrl,
49}
50
51#[apply(async_trait_maybe_send!)]
52impl IConnection for HttpConnection {
53 async fn await_disconnection(&self) {
54 std::future::pending().await
59 }
60
61 fn is_connected(&self) -> bool {
62 true
68 }
69}
70
71#[apply(async_trait_maybe_send!)]
72impl IGatewayConnection for HttpConnection {
73 async fn request(
74 &self,
75 password: Option<String>,
76 method: Method,
77 route: &str,
78 payload: Option<Value>,
79 ) -> ServerResult<Value> {
80 let url = self.base_url.join(route).expect("Invalid base url");
81 let mut builder = self.client.request(method, url.clone().to_unsafe());
82 if let Some(password) = password.clone() {
83 builder = builder.bearer_auth(password);
84 }
85 if let Some(payload) = payload {
86 builder = builder.json(&payload);
87 }
88
89 let response = builder
90 .send()
91 .await
92 .map_err(|e| ServerError::ServerError(e.fmt_compact().to_string()))?;
93
94 match response.status() {
95 StatusCode::OK => Ok(response
96 .json::<Value>()
97 .await
98 .map_err(|e| ServerError::InvalidResponse(e.fmt_compact().to_string()))?),
99 status => Err(ServerError::InvalidRequest(format!(
100 "HTTP request returned unexpected status: {status}"
101 ))),
102 }
103 }
104}