Skip to content

Commit b43402f

Browse files
committed
Add ListForwardedPayments to client and CLI
1 parent 7ea45b7 commit b43402f

File tree

3 files changed

+96
-49
lines changed

3 files changed

+96
-49
lines changed

ldk-server-cli/src/main.rs

Lines changed: 69 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ use ldk_server_client::ldk_server_protos::api::{
1919
CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
2020
GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse,
2121
GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse,
22-
ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse,
23-
OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse,
24-
SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse,
22+
ListForwardedPaymentsRequest, ListPaymentsRequest, OnchainReceiveRequest,
23+
OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest,
24+
OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse,
2525
UpdateChannelConfigRequest, UpdateChannelConfigResponse,
2626
};
2727
use ldk_server_client::ldk_server_protos::types::{
2828
bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken,
2929
RouteParametersConfig,
3030
};
3131
use serde::Serialize;
32-
use types::CliListPaymentsResponse;
32+
use types::{CliListForwardedPaymentsResponse, CliListPaymentsResponse, CliPaginatedResponse};
3333

3434
mod types;
3535

@@ -204,6 +204,16 @@ enum Commands {
204204
#[arg(short, long, help = "The payment ID in hex-encoded form")]
205205
payment_id: String,
206206
},
207+
ListForwardedPayments {
208+
#[arg(short, long)]
209+
#[arg(
210+
help = "Fetch at least this many forwarded payments by iterating through multiple pages. Returns combined results with the last page token. If not provided, returns only a single page."
211+
)]
212+
number_of_payments: Option<u64>,
213+
#[arg(long)]
214+
#[arg(help = "Page token to continue from a previous page (format: token:index)")]
215+
page_token: Option<String>,
216+
},
207217
UpdateChannelConfig {
208218
#[arg(short, long)]
209219
user_channel_id: String,
@@ -454,7 +464,13 @@ async fn main() {
454464
.map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e)));
455465

456466
handle_response_result::<_, CliListPaymentsResponse>(
457-
handle_list_payments(client, number_of_payments, page_token).await,
467+
fetch_paginated(
468+
number_of_payments,
469+
page_token,
470+
|pt| client.list_payments(ListPaymentsRequest { page_token: pt }),
471+
|r| (r.payments, r.next_page_token),
472+
)
473+
.await,
458474
);
459475
},
460476
Commands::UpdateChannelConfig {
@@ -488,6 +504,24 @@ async fn main() {
488504
client.get_payment_details(GetPaymentDetailsRequest { payment_id }).await,
489505
);
490506
},
507+
Commands::ListForwardedPayments { number_of_payments, page_token } => {
508+
let page_token = page_token
509+
.map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e)));
510+
511+
handle_response_result::<_, CliListForwardedPaymentsResponse>(
512+
fetch_paginated(
513+
number_of_payments,
514+
page_token,
515+
|pt| {
516+
client.list_forwarded_payments(ListForwardedPaymentsRequest {
517+
page_token: pt,
518+
})
519+
},
520+
|r| (r.forwarded_payments, r.next_page_token),
521+
)
522+
.await,
523+
);
524+
},
491525
}
492526
}
493527

@@ -513,37 +547,40 @@ fn build_open_channel_config(
513547
})
514548
}
515549

516-
async fn handle_list_payments(
517-
client: LdkServerClient, number_of_payments: Option<u64>, initial_page_token: Option<PageToken>,
518-
) -> Result<ListPaymentsResponse, LdkServerError> {
519-
if let Some(count) = number_of_payments {
520-
list_n_payments(client, count, initial_page_token).await
521-
} else {
522-
// Fetch single page
523-
client.list_payments(ListPaymentsRequest { page_token: initial_page_token }).await
524-
}
525-
}
526-
527-
async fn list_n_payments(
528-
client: LdkServerClient, target_count: u64, initial_page_token: Option<PageToken>,
529-
) -> Result<ListPaymentsResponse, LdkServerError> {
530-
let mut payments = Vec::with_capacity(target_count as usize);
531-
let mut page_token = initial_page_token;
532-
let mut next_page_token;
550+
async fn fetch_paginated<T, R, Fut>(
551+
target_count: Option<u64>, initial_page_token: Option<PageToken>,
552+
fetch_page: impl Fn(Option<PageToken>) -> Fut,
553+
extract: impl Fn(R) -> (Vec<T>, Option<PageToken>),
554+
) -> Result<CliPaginatedResponse<T>, LdkServerError>
555+
where
556+
Fut: std::future::Future<Output = Result<R, LdkServerError>>,
557+
{
558+
match target_count {
559+
Some(count) => {
560+
let mut items = Vec::with_capacity(count as usize);
561+
let mut page_token = initial_page_token;
562+
let mut next_page_token;
533563

534-
loop {
535-
let response = client.list_payments(ListPaymentsRequest { page_token }).await?;
564+
loop {
565+
let response = fetch_page(page_token).await?;
566+
let (new_items, new_next_page_token) = extract(response);
567+
items.extend(new_items);
568+
next_page_token = new_next_page_token;
536569

537-
payments.extend(response.payments);
538-
next_page_token = response.next_page_token;
570+
if items.len() >= count as usize || next_page_token.is_none() {
571+
break;
572+
}
573+
page_token = next_page_token;
574+
}
539575

540-
if payments.len() >= target_count as usize || next_page_token.is_none() {
541-
break;
542-
}
543-
page_token = next_page_token;
576+
Ok(CliPaginatedResponse::new(items, next_page_token))
577+
},
578+
None => {
579+
let response = fetch_page(initial_page_token).await?;
580+
let (items, next_page_token) = extract(response);
581+
Ok(CliPaginatedResponse::new(items, next_page_token))
582+
},
544583
}
545-
546-
Ok(ListPaymentsResponse { payments, next_page_token })
547584
}
548585

549586
fn handle_response_result<Rs, Js>(response: Result<Rs, LdkServerError>)

ldk-server-cli/src/types.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,29 @@
1313
//! of API responses for CLI output. These wrappers ensure that the CLI's output
1414
//! format matches what users expect and what the CLI can parse back as input.
1515
16-
use ldk_server_client::ldk_server_protos::api::ListPaymentsResponse;
17-
use ldk_server_client::ldk_server_protos::types::{PageToken, Payment};
16+
use ldk_server_client::ldk_server_protos::types::{ForwardedPayment, PageToken, Payment};
1817
use serde::Serialize;
1918

20-
/// CLI-specific wrapper for ListPaymentsResponse that formats the page token
19+
/// CLI-specific wrapper for paginated responses that formats the page token
2120
/// as "token:idx" instead of a JSON object.
2221
#[derive(Debug, Clone, Serialize)]
23-
pub struct CliListPaymentsResponse {
24-
/// List of payments.
25-
pub payments: Vec<Payment>,
22+
pub struct CliPaginatedResponse<T> {
23+
/// List of items.
24+
pub list: Vec<T>,
2625
/// Next page token formatted as "token:idx", or None if no more pages.
2726
#[serde(skip_serializing_if = "Option::is_none")]
2827
pub next_page_token: Option<String>,
2928
}
3029

31-
impl From<ListPaymentsResponse> for CliListPaymentsResponse {
32-
fn from(response: ListPaymentsResponse) -> Self {
33-
let next_page_token = response.next_page_token.map(format_page_token);
34-
35-
CliListPaymentsResponse { payments: response.payments, next_page_token }
30+
impl<T> CliPaginatedResponse<T> {
31+
pub fn new(list: Vec<T>, next_page_token: Option<PageToken>) -> Self {
32+
Self { list, next_page_token: next_page_token.map(format_page_token) }
3633
}
3734
}
3835

36+
pub type CliListPaymentsResponse = CliPaginatedResponse<Payment>;
37+
pub type CliListForwardedPaymentsResponse = CliPaginatedResponse<ForwardedPayment>;
38+
3939
fn format_page_token(token: PageToken) -> String {
4040
format!("{}:{}", token.token, token.index)
4141
}

ldk-server-client/src/client.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@ use ldk_server_protos::api::{
2121
CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
2222
GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse,
2323
GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse,
24-
ListPaymentsRequest, ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse,
25-
OnchainSendRequest, OnchainSendResponse, OpenChannelRequest, OpenChannelResponse,
26-
SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse,
27-
UpdateChannelConfigRequest, UpdateChannelConfigResponse,
24+
ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, ListPaymentsRequest,
25+
ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest,
26+
OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, SpliceInRequest,
27+
SpliceInResponse, SpliceOutRequest, SpliceOutResponse, UpdateChannelConfigRequest,
28+
UpdateChannelConfigResponse,
2829
};
2930
use ldk_server_protos::endpoints::{
3031
BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH,
3132
CLOSE_CHANNEL_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH,
32-
GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH,
33-
ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH,
33+
GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH,
34+
ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH,
3435
UPDATE_CHANNEL_CONFIG_PATH,
3536
};
3637
use ldk_server_protos::error::{ErrorCode, ErrorResponse};
@@ -241,6 +242,15 @@ impl LdkServerClient {
241242
self.post_request(&request, &url).await
242243
}
243244

245+
/// Retrieves list of all forwarded payments.
246+
/// For API contract/usage, refer to docs for [`ListForwardedPaymentsRequest`] and [`ListForwardedPaymentsResponse`].
247+
pub async fn list_forwarded_payments(
248+
&self, request: ListForwardedPaymentsRequest,
249+
) -> Result<ListForwardedPaymentsResponse, LdkServerError> {
250+
let url = format!("https://{}/{LIST_FORWARDED_PAYMENTS_PATH}", self.base_url);
251+
self.post_request(&request, &url).await
252+
}
253+
244254
async fn post_request<Rq: Message, Rs: Message + Default>(
245255
&self, request: &Rq, url: &str,
246256
) -> Result<Rs, LdkServerError> {

0 commit comments

Comments
 (0)