diff --git a/ldk-server/src/api/list_forwarded_payments.rs b/ldk-server/src/api/list_forwarded_payments.rs new file mode 100644 index 0000000..3903f7c --- /dev/null +++ b/ldk-server/src/api/list_forwarded_payments.rs @@ -0,0 +1,47 @@ +use crate::io::{ + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, +}; +use crate::service::Context; +use bytes::Bytes; +use ldk_server_protos::api::{ListForwardedPaymentsRequest, ListForwardedPaymentsResponse}; +use ldk_server_protos::types::{ForwardedPayment, PageToken}; +use prost::Message; + +pub(crate) const LIST_FORWARDED_PAYMENTS_PATH: &str = "ListForwardedPayments"; + +pub(crate) fn handle_list_forwarded_payments_request( + context: Context, request: ListForwardedPaymentsRequest, +) -> Result { + let page_token = request.page_token.map(|p| (p.token, p.index)); + let list_response = context + .paginated_kv_store + .list( + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + page_token, + ) + .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + + let mut forwarded_payments: Vec = vec![]; + for key in list_response.keys { + let forwarded_payment_bytes = context + .paginated_kv_store + .read( + FORWARDED_PAYMENTS_PERSISTENCE_PRIMARY_NAMESPACE, + FORWARDED_PAYMENTS_PERSISTENCE_SECONDARY_NAMESPACE, + &key, + ) + .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + let forwarded_payment = ForwardedPayment::decode(Bytes::from(forwarded_payment_bytes)) + .map_err(|_| ldk_node::NodeError::ConnectionFailed)?; + forwarded_payments.push(forwarded_payment); + } + let response = ListForwardedPaymentsResponse { + forwarded_payments, + next_page_token: list_response + .next_page_token + .map(|(token, index)| PageToken { token, index }), + }; + Ok(response) +} diff --git a/ldk-server/src/api/mod.rs b/ldk-server/src/api/mod.rs index 7d0770d..c1b0fa2 100644 --- a/ldk-server/src/api/mod.rs +++ b/ldk-server/src/api/mod.rs @@ -8,6 +8,7 @@ pub(crate) mod get_balances; pub(crate) mod get_node_info; pub(crate) mod get_payment_details; pub(crate) mod list_channels; +pub(crate) mod list_forwarded_payments; pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; diff --git a/ldk-server/src/main.rs b/ldk-server/src/main.rs index 1864441..4cdd219 100644 --- a/ldk-server/src/main.rs +++ b/ldk-server/src/main.rs @@ -204,7 +204,7 @@ fn main() { match res { Ok((stream, _)) => { let io_stream = TokioIo::new(stream); - let node_service = NodeService::new(Arc::clone(&node)); + let node_service = NodeService::new(Arc::clone(&node), Arc::clone(&paginated_store) as Arc); runtime.spawn(async move { if let Err(err) = http1::Builder::new().serve_connection(io_stream, node_service).await { eprintln!("Failed to serve connection: {}", err); diff --git a/ldk-server/src/service.rs b/ldk-server/src/service.rs index 0ae5022..16ec58d 100644 --- a/ldk-server/src/service.rs +++ b/ldk-server/src/service.rs @@ -18,6 +18,9 @@ use crate::api::get_payment_details::{ handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, }; use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; +use crate::api::list_forwarded_payments::{ + handle_list_forwarded_payments_request, LIST_FORWARDED_PAYMENTS_PATH, +}; use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; @@ -25,6 +28,7 @@ use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; use crate::api::update_channel_config::{ handle_update_channel_config_request, UPDATE_CHANNEL_CONFIG_PATH, }; +use crate::io::paginated_kv_store::PaginatedKVStore; use std::future::Future; use std::pin::Pin; use std::sync::Arc; @@ -32,16 +36,20 @@ use std::sync::Arc; #[derive(Clone)] pub struct NodeService { node: Arc, + paginated_kv_store: Arc, } impl NodeService { - pub(crate) fn new(node: Arc) -> Self { - Self { node } + pub(crate) fn new( + node: Arc, paginated_kv_store: Arc, + ) -> Self { + Self { node, paginated_kv_store } } } pub(crate) struct Context { pub(crate) node: Arc, + pub(crate) paginated_kv_store: Arc, } impl Service> for NodeService { @@ -50,7 +58,10 @@ impl Service> for NodeService { type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { - let context = Context { node: Arc::clone(&self.node) }; + let context = Context { + node: Arc::clone(&self.node), + paginated_kv_store: Arc::clone(&self.paginated_kv_store), + }; // Exclude '/' from path pattern matching. match &req.uri().path()[1..] { GET_NODE_INFO => Box::pin(handle_request(context, req, handle_get_node_info_request)), @@ -85,6 +96,9 @@ impl Service> for NodeService { LIST_PAYMENTS_PATH => { Box::pin(handle_request(context, req, handle_list_payments_request)) }, + LIST_FORWARDED_PAYMENTS_PATH => { + Box::pin(handle_request(context, req, handle_list_forwarded_payments_request)) + }, path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async {