Skip to main content

fedimint_server_core/
dashboard_ui.rs

1use std::collections::BTreeMap;
2use std::sync::Arc;
3use std::time::Duration;
4
5use async_trait::async_trait;
6use fedimint_core::admin_client::GuardianConfigBackup;
7use fedimint_core::bitcoin::Network;
8use fedimint_core::core::ModuleKind;
9use fedimint_core::module::ApiAuth;
10use fedimint_core::module::audit::AuditSummary;
11use fedimint_core::net::auth::GuardianAuthToken;
12use fedimint_core::session_outcome::SessionStatusV2;
13use fedimint_core::util::SafeUrl;
14use fedimint_core::{Feerate, PeerId};
15use serde::{Deserialize, Serialize};
16
17use crate::{DynServerModule, ServerModule};
18
19pub type DynDashboardApi = Arc<dyn IDashboardApi + Send + Sync + 'static>;
20
21/// Type of the connection to a peer. Mirrors iroh::endpoint::ConnectionType.
22#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum ConnectionType {
25    /// Direct UDP connectivity
26    Direct,
27    /// Going through an Iroh relay
28    Relay,
29    /// Both relay and direct paths available
30    Mixed,
31}
32
33/// P2P connection status for a peer. None indicates disconnected.
34#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
35pub struct P2PConnectionStatus {
36    /// The type of connection (Direct, Relay, Mixed), None if unknown
37    pub conn_type: Option<ConnectionType>,
38    /// Round-trip time (only available for iroh connections)
39    pub rtt: Option<Duration>,
40}
41
42/// Interface for guardian dashboard API in a running federation
43#[async_trait]
44pub trait IDashboardApi {
45    /// Password protecting the dashboard UI login form. `None` means the UI
46    /// is served without a login form.
47    fn auth_ui(&self) -> Option<ApiAuth>;
48
49    /// Get the guardian ID
50    async fn guardian_id(&self) -> PeerId;
51
52    /// Get a map of peer IDs to guardian names
53    async fn guardian_names(&self) -> BTreeMap<PeerId, String>;
54
55    /// Get the federation name
56    async fn federation_name(&self) -> String;
57
58    /// Get the current active session count
59    async fn session_count(&self) -> u64;
60
61    /// Get items in a given session
62    async fn get_session_status(&self, session_idx: u64) -> SessionStatusV2;
63
64    /// The time it took to order our last proposal in the current session
65    async fn consensus_ord_latency(&self) -> Option<Duration>;
66
67    /// Returns a map of peer ID to connection status (None = disconnected)
68    async fn p2p_connection_status(&self) -> BTreeMap<PeerId, Option<P2PConnectionStatus>>;
69
70    /// Get the federation invite code to share with users
71    async fn federation_invite_code(&self) -> String;
72
73    /// Get the federation audit summary
74    async fn federation_audit(&self) -> AuditSummary;
75
76    /// Get the url of the bitcoin rpc
77    async fn bitcoin_rpc_url(&self) -> SafeUrl;
78
79    /// Get the status of the bitcoin backend
80    async fn bitcoin_rpc_status(&self) -> Option<ServerBitcoinRpcStatus>;
81
82    /// Download a backup of the guardian's configuration
83    async fn download_guardian_config_backup(
84        &self,
85        guardian_auth: &GuardianAuthToken,
86    ) -> GuardianConfigBackup;
87
88    /// Get reference to a server module instance by module kind
89    fn get_module_by_kind(&self, kind: ModuleKind) -> Option<&DynServerModule>;
90
91    /// Get the fedimintd version
92    async fn fedimintd_version(&self) -> String;
93
94    /// Get the git hash of the fedimintd binary, or `None` if it is not
95    /// available (e.g. it was built outside a git checkout).
96    async fn fedimintd_version_hash(&self) -> Option<String>;
97
98    /// Create a trait object
99    fn into_dyn(self) -> DynDashboardApi
100    where
101        Self: Sized + Send + Sync + 'static,
102    {
103        Arc::new(self)
104    }
105}
106
107/// Extension trait for IDashboardApi providing type-safe module access
108pub trait DashboardApiModuleExt {
109    /// Get a typed reference to a server module instance by kind
110    fn get_module<M: ServerModule + 'static>(&self) -> Option<&M>;
111}
112
113impl DashboardApiModuleExt for DynDashboardApi {
114    fn get_module<M: ServerModule + 'static>(&self) -> Option<&M> {
115        self.get_module_by_kind(M::module_kind())?
116            .as_any()
117            .downcast_ref::<M>()
118    }
119}
120
121#[derive(Debug, Clone)]
122pub struct ServerBitcoinRpcStatus {
123    pub network: Network,
124    pub block_count: u64,
125    pub fee_rate: Feerate,
126    pub sync_progress: Option<f64>,
127}