diff --git a/mutiny-server/src/main.rs b/mutiny-server/src/main.rs index 826a77ac3..6a4a7a90e 100644 --- a/mutiny-server/src/main.rs +++ b/mutiny-server/src/main.rs @@ -74,6 +74,7 @@ async fn main() -> anyhow::Result<()> { .route("/createinvoice", post(routes::create_invoice)) .route("/payinvoice", post(routes::pay_invoice)) .route("/balance", get(routes::get_balance)) + .route("/getinfo", get(routes::get_node_info)) .fallback(fallback) .layer(Extension(state.clone())); diff --git a/mutiny-server/src/routes.rs b/mutiny-server/src/routes.rs index f27b1e3e6..23aa81adc 100644 --- a/mutiny-server/src/routes.rs +++ b/mutiny-server/src/routes.rs @@ -244,6 +244,81 @@ pub async fn get_balance( Ok(Json(json!(balance))) } +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NodeInfoResponse { + node_id: String, + channels: Vec, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Channel { + state: String, + channel_id: String, + balance_sat: u64, + inbound_liquidity_sat: u64, + capacity_sat: u64, + funding_tx_id: Option, +} + +pub async fn get_node_info( + Extension(state): Extension, +) -> Result, (StatusCode, Json)> { + let nodes = state + .mutiny_wallet + .node_manager + .list_nodes() + .await + .map_err(|e| handle_mutiny_err(e))?; + let node_pubkey: PublicKey; + if !nodes.is_empty() { + node_pubkey = nodes[0]; + } else { + return Err(( + StatusCode::INTERNAL_SERVER_ERROR, + Json(json!({"error": "unable to get node info"})), + )); + } + + let channels = state + .mutiny_wallet + .node_manager + .list_channels() + .await + .map_err(|e| handle_mutiny_err(e))?; + let channels = channels + .into_iter() + .map(|channel| { + let state = match channel.is_usable { + true => "usable", + false => "unusable", + } + .to_string(); + let funding_tx_id = match channel.outpoint { + Some(outpoint) => Some(outpoint.txid.to_string()), + None => None, + }; + + Channel { + state, + channel_id: channel.user_chan_id, + balance_sat: channel.balance, + inbound_liquidity_sat: channel.inbound, + capacity_sat: channel.size, + funding_tx_id, + } + }) + .collect(); + + let node_info = NodeInfoResponse { + node_id: node_pubkey.to_string(), + channels, + }; + + Ok(Json(json!(node_info))) +} + fn handle_mutiny_err(err: MutinyError) -> (StatusCode, Json) { let err = json!({ "error": format!("{err}"), diff --git a/mutiny-server/src/sled.rs b/mutiny-server/src/sled.rs index 07f9cdeea..ac99a4d7f 100644 --- a/mutiny-server/src/sled.rs +++ b/mutiny-server/src/sled.rs @@ -16,6 +16,7 @@ pub struct SledStorage { pub cipher: Option, db: sled::Db, delayed_keys: Arc>>, + activity_index: Arc>>, } impl SledStorage { @@ -41,6 +42,7 @@ impl SledStorage { cipher, db, delayed_keys: Arc::new(Mutex::new(HashMap::new())), + activity_index: Arc::new(RwLock::new(BTreeSet::new())), }) } } @@ -65,7 +67,7 @@ impl MutinyStorage for SledStorage { } fn activity_index(&self) -> Arc>> { - Arc::new(RwLock::new(BTreeSet::new())) + self.activity_index.clone() } fn set(&self, items: Vec<(String, impl Serialize)>) -> Result<(), MutinyError> {