fedimint_ln_common/
client.rs

1use std::collections::BTreeSet;
2use std::fmt::Debug;
3
4use anyhow::Context;
5use fedimint_connectors::error::ServerError;
6use fedimint_connectors::{
7    ConnectionPool, ConnectorRegistry, DynGatewayConnection, IGatewayConnection, ServerResult,
8};
9use fedimint_core::util::SafeUrl;
10use reqwest::Method;
11use serde::Serialize;
12use serde::de::DeserializeOwned;
13use tokio::sync::watch;
14
15#[derive(Clone, Debug)]
16pub struct GatewayApi {
17    password: Option<String>,
18    connection_pool: ConnectionPool<dyn IGatewayConnection>,
19}
20
21impl GatewayApi {
22    pub fn new(password: Option<String>, connectors: ConnectorRegistry) -> Self {
23        Self {
24            password,
25            connection_pool: ConnectionPool::new(connectors),
26        }
27    }
28
29    async fn get_or_create_connection(&self, url: &SafeUrl) -> ServerResult<DynGatewayConnection> {
30        self.connection_pool
31            .get_or_create_connection(url, None, |url, _api_secret, connectors| async move {
32                let conn = connectors
33                    .connect_gateway(&url)
34                    .await
35                    .map_err(ServerError::Connection)?;
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
49            .get_or_create_connection(base_url)
50            .await
51            .context("Failed to connect to gateway")
52            .map_err(ServerError::Connection)?;
53        let payload = payload.map(|p| serde_json::to_value(p).expect("Could not serialize"));
54        let res = conn
55            .request(self.password.clone(), method, route, payload)
56            .await?;
57        let response = serde_json::from_value::<T>(res).map_err(|e| {
58            ServerError::InvalidResponse(anyhow::anyhow!("Received invalid response: {e}"))
59        })?;
60        Ok(response)
61    }
62
63    /// Get receiver for changes in the active connections
64    ///
65    /// This allows real-time monitoring of connection status.
66    pub fn get_active_connection_receiver(&self) -> watch::Receiver<BTreeSet<SafeUrl>> {
67        self.connection_pool.get_active_connection_receiver()
68    }
69}