Skip to main content

fedimint_ln_common/
client.rs

1use std::collections::BTreeSet;
2use std::fmt::Debug;
3
4use fedimint_connectors::error::ServerError;
5use fedimint_connectors::{
6    ConnectionPool, ConnectorRegistry, DynGatewayConnection, IGatewayConnection, ServerResult,
7};
8use fedimint_core::util::{FmtCompact as _, SafeUrl};
9use reqwest::Method;
10use serde::Serialize;
11use serde::de::DeserializeOwned;
12use tokio::sync::watch;
13
14#[derive(Clone, Debug)]
15pub struct GatewayApi {
16    password: Option<String>,
17    connection_pool: ConnectionPool<dyn IGatewayConnection>,
18}
19
20impl GatewayApi {
21    pub fn new(password: Option<String>, connectors: ConnectorRegistry) -> Self {
22        Self {
23            password,
24            connection_pool: ConnectionPool::new(connectors),
25        }
26    }
27
28    async fn get_or_create_connection(&self, url: &SafeUrl) -> ServerResult<DynGatewayConnection> {
29        self.connection_pool
30            .get_or_create_connection(url, None, |url, _api_secret, connectors| async move {
31                let conn = connectors
32                    .connect_gateway(&url)
33                    .await
34                    // `Connection` neither prints nor exposes a source, so flatten the chain.
35                    .map_err(|err| ServerError::Connection(err.fmt_compact().to_string().into()))?;
36                Ok(conn)
37            })
38            .await
39    }
40
41    pub async fn request<P: Serialize, T: DeserializeOwned>(
42        &self,
43        base_url: &SafeUrl,
44        method: Method,
45        route: &str,
46        payload: Option<P>,
47    ) -> ServerResult<T> {
48        let conn = self.get_or_create_connection(base_url).await?;
49        let payload = payload.map(|p| serde_json::to_value(p).expect("Could not serialize"));
50        let res = conn
51            .request(self.password.clone(), method, route, payload)
52            .await?;
53        let response = serde_json::from_value::<T>(res)
54            .map_err(|e| ServerError::InvalidResponse(format!("Received invalid response: {e}")))?;
55        Ok(response)
56    }
57
58    /// Get receiver for changes in the active connections
59    ///
60    /// This allows real-time monitoring of connection status.
61    pub fn get_active_connection_receiver(&self) -> watch::Receiver<BTreeSet<SafeUrl>> {
62        self.connection_pool.get_active_connection_receiver()
63    }
64}