Skip to content

Commit b727c96

Browse files
authored
Merge pull request lightningdevkit#95 from benthecarman/remaining-missing-cmds
2 parents 28845ae + a3a7481 commit b727c96

File tree

3 files changed

+122
-53
lines changed

3 files changed

+122
-53
lines changed

ldk-server/ldk-server-cli/src/main.rs

Lines changed: 84 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,18 @@ use ldk_server_client::ldk_server_protos::api::{
2424
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
2525
CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
2626
GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse,
27-
ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse,
28-
OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse,
29-
OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest,
30-
SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse,
27+
GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse,
28+
ListForwardedPaymentsRequest, ListPaymentsRequest, OnchainReceiveRequest,
29+
OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse, OpenChannelRequest,
30+
OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest, SpliceOutResponse,
31+
UpdateChannelConfigRequest, UpdateChannelConfigResponse,
3132
};
3233
use ldk_server_client::ldk_server_protos::types::{
3334
bolt11_invoice_description, Bolt11InvoiceDescription, ChannelConfig, PageToken,
3435
RouteParametersConfig,
3536
};
3637
use serde::Serialize;
37-
use types::CliListPaymentsResponse;
38+
use types::{CliListForwardedPaymentsResponse, CliListPaymentsResponse, CliPaginatedResponse};
3839

3940
mod config;
4041
mod types;
@@ -293,7 +294,22 @@ enum Commands {
293294
#[arg(help = "Page token to continue from a previous page (format: token:index)")]
294295
page_token: Option<String>,
295296
},
296-
#[command(about = "Update the config for a previously opened channel")]
297+
#[command(about = "Get details of a specific payment by its payment ID")]
298+
GetPaymentDetails {
299+
#[arg(short, long, help = "The payment ID in hex-encoded form")]
300+
payment_id: String,
301+
},
302+
#[command(about = "Retrieves list of all forwarded payments")]
303+
ListForwardedPayments {
304+
#[arg(
305+
short,
306+
long,
307+
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."
308+
)]
309+
number_of_payments: Option<u64>,
310+
#[arg(long, help = "Page token to continue from a previous page (format: token:index)")]
311+
page_token: Option<String>,
312+
},
297313
UpdateChannelConfig {
298314
#[arg(short, long, help = "The local user_channel_id of this channel")]
299315
user_channel_id: String,
@@ -584,7 +600,36 @@ async fn main() {
584600
.map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e)));
585601

586602
handle_response_result::<_, CliListPaymentsResponse>(
587-
handle_list_payments(client, number_of_payments, page_token).await,
603+
fetch_paginated(
604+
number_of_payments,
605+
page_token,
606+
|pt| client.list_payments(ListPaymentsRequest { page_token: pt }),
607+
|r| (r.payments, r.next_page_token),
608+
)
609+
.await,
610+
);
611+
},
612+
Commands::GetPaymentDetails { payment_id } => {
613+
handle_response_result::<_, GetPaymentDetailsResponse>(
614+
client.get_payment_details(GetPaymentDetailsRequest { payment_id }).await,
615+
);
616+
},
617+
Commands::ListForwardedPayments { number_of_payments, page_token } => {
618+
let page_token = page_token
619+
.map(|token_str| parse_page_token(&token_str).unwrap_or_else(|e| handle_error(e)));
620+
621+
handle_response_result::<_, CliListForwardedPaymentsResponse>(
622+
fetch_paginated(
623+
number_of_payments,
624+
page_token,
625+
|pt| {
626+
client.list_forwarded_payments(ListForwardedPaymentsRequest {
627+
page_token: pt,
628+
})
629+
},
630+
|r| (r.forwarded_payments, r.next_page_token),
631+
)
632+
.await,
588633
);
589634
},
590635
Commands::UpdateChannelConfig {
@@ -638,37 +683,40 @@ fn build_open_channel_config(
638683
})
639684
}
640685

641-
async fn handle_list_payments(
642-
client: LdkServerClient, number_of_payments: Option<u64>, initial_page_token: Option<PageToken>,
643-
) -> Result<ListPaymentsResponse, LdkServerError> {
644-
if let Some(count) = number_of_payments {
645-
list_n_payments(client, count, initial_page_token).await
646-
} else {
647-
// Fetch single page
648-
client.list_payments(ListPaymentsRequest { page_token: initial_page_token }).await
649-
}
650-
}
651-
652-
async fn list_n_payments(
653-
client: LdkServerClient, target_count: u64, initial_page_token: Option<PageToken>,
654-
) -> Result<ListPaymentsResponse, LdkServerError> {
655-
let mut payments = Vec::with_capacity(target_count as usize);
656-
let mut page_token = initial_page_token;
657-
let mut next_page_token;
658-
659-
loop {
660-
let response = client.list_payments(ListPaymentsRequest { page_token }).await?;
661-
662-
payments.extend(response.payments);
663-
next_page_token = response.next_page_token;
686+
async fn fetch_paginated<T, R, Fut>(
687+
target_count: Option<u64>, initial_page_token: Option<PageToken>,
688+
fetch_page: impl Fn(Option<PageToken>) -> Fut,
689+
extract: impl Fn(R) -> (Vec<T>, Option<PageToken>),
690+
) -> Result<CliPaginatedResponse<T>, LdkServerError>
691+
where
692+
Fut: std::future::Future<Output = Result<R, LdkServerError>>,
693+
{
694+
match target_count {
695+
Some(count) => {
696+
let mut items = Vec::with_capacity(count as usize);
697+
let mut page_token = initial_page_token;
698+
let mut next_page_token;
699+
700+
loop {
701+
let response = fetch_page(page_token).await?;
702+
let (new_items, new_next_page_token) = extract(response);
703+
items.extend(new_items);
704+
next_page_token = new_next_page_token;
705+
706+
if items.len() >= count as usize || next_page_token.is_none() {
707+
break;
708+
}
709+
page_token = next_page_token;
710+
}
664711

665-
if payments.len() >= target_count as usize || next_page_token.is_none() {
666-
break;
667-
}
668-
page_token = next_page_token;
712+
Ok(CliPaginatedResponse::new(items, next_page_token))
713+
},
714+
None => {
715+
let response = fetch_page(initial_page_token).await?;
716+
let (items, next_page_token) = extract(response);
717+
Ok(CliPaginatedResponse::new(items, next_page_token))
718+
},
669719
}
670-
671-
Ok(ListPaymentsResponse { payments, next_page_token })
672720
}
673721

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

ldk-server/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/ldk-server-client/src/client.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@ use ldk_server_protos::api::{
1616
Bolt12ReceiveRequest, Bolt12ReceiveResponse, Bolt12SendRequest, Bolt12SendResponse,
1717
CloseChannelRequest, CloseChannelResponse, ForceCloseChannelRequest, ForceCloseChannelResponse,
1818
GetBalancesRequest, GetBalancesResponse, GetNodeInfoRequest, GetNodeInfoResponse,
19-
ListChannelsRequest, ListChannelsResponse, ListPaymentsRequest, ListPaymentsResponse,
20-
OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest, OnchainSendResponse,
21-
OpenChannelRequest, OpenChannelResponse, SpliceInRequest, SpliceInResponse, SpliceOutRequest,
22-
SpliceOutResponse, UpdateChannelConfigRequest, UpdateChannelConfigResponse,
19+
GetPaymentDetailsRequest, GetPaymentDetailsResponse, ListChannelsRequest, ListChannelsResponse,
20+
ListForwardedPaymentsRequest, ListForwardedPaymentsResponse, ListPaymentsRequest,
21+
ListPaymentsResponse, OnchainReceiveRequest, OnchainReceiveResponse, OnchainSendRequest,
22+
OnchainSendResponse, OpenChannelRequest, OpenChannelResponse, SpliceInRequest,
23+
SpliceInResponse, SpliceOutRequest, SpliceOutResponse, UpdateChannelConfigRequest,
24+
UpdateChannelConfigResponse,
2325
};
2426
use ldk_server_protos::endpoints::{
2527
BOLT11_RECEIVE_PATH, BOLT11_SEND_PATH, BOLT12_RECEIVE_PATH, BOLT12_SEND_PATH,
2628
CLOSE_CHANNEL_PATH, FORCE_CLOSE_CHANNEL_PATH, GET_BALANCES_PATH, GET_NODE_INFO_PATH,
27-
LIST_CHANNELS_PATH, LIST_PAYMENTS_PATH, ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH,
28-
OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH, UPDATE_CHANNEL_CONFIG_PATH,
29+
GET_PAYMENT_DETAILS_PATH, LIST_CHANNELS_PATH, LIST_FORWARDED_PAYMENTS_PATH, LIST_PAYMENTS_PATH,
30+
ONCHAIN_RECEIVE_PATH, ONCHAIN_SEND_PATH, OPEN_CHANNEL_PATH, SPLICE_IN_PATH, SPLICE_OUT_PATH,
31+
UPDATE_CHANNEL_CONFIG_PATH,
2932
};
3033
use ldk_server_protos::error::{ErrorCode, ErrorResponse};
3134
use prost::Message;
@@ -231,6 +234,24 @@ impl LdkServerClient {
231234
self.post_request(&request, &url).await
232235
}
233236

237+
/// Retrieves payment details for a given payment id.
238+
/// For API contract/usage, refer to docs for [`GetPaymentDetailsRequest`] and [`GetPaymentDetailsResponse`].
239+
pub async fn get_payment_details(
240+
&self, request: GetPaymentDetailsRequest,
241+
) -> Result<GetPaymentDetailsResponse, LdkServerError> {
242+
let url = format!("https://{}/{GET_PAYMENT_DETAILS_PATH}", self.base_url);
243+
self.post_request(&request, &url).await
244+
}
245+
246+
/// Retrieves list of all forwarded payments.
247+
/// For API contract/usage, refer to docs for [`ListForwardedPaymentsRequest`] and [`ListForwardedPaymentsResponse`].
248+
pub async fn list_forwarded_payments(
249+
&self, request: ListForwardedPaymentsRequest,
250+
) -> Result<ListForwardedPaymentsResponse, LdkServerError> {
251+
let url = format!("https://{}/{LIST_FORWARDED_PAYMENTS_PATH}", self.base_url);
252+
self.post_request(&request, &url).await
253+
}
254+
234255
async fn post_request<Rq: Message, Rs: Message + Default>(
235256
&self, request: &Rq, url: &str,
236257
) -> Result<Rs, LdkServerError> {

0 commit comments

Comments
 (0)