@@ -15,11 +15,14 @@ use ldk_server_client::ldk_server_protos::api::{
1515 SpliceOutResponse , UpdateChannelConfigRequest , UpdateChannelConfigResponse ,
1616} ;
1717use ldk_server_client:: ldk_server_protos:: types:: {
18- bolt11_invoice_description, Bolt11InvoiceDescription , ChannelConfig , PageToken , Payment ,
18+ bolt11_invoice_description, Bolt11InvoiceDescription , ChannelConfig , PageToken ,
1919 RouteParametersConfig ,
2020} ;
2121use serde:: Serialize ;
2222
23+ mod types;
24+ use types:: CliListPaymentsResponse ;
25+
2326// Having these default values as constants in the Proto file and
2427// importing/reusing them here might be better, but Proto3 removed
2528// the ability to set default values.
@@ -169,9 +172,12 @@ enum Commands {
169172 ListPayments {
170173 #[ arg( short, long) ]
171174 #[ arg(
172- help = "Minimum number of payments to return. If not provided, only the first page of the paginated list is returned ."
175+ help = "Fetch at least this many payments by iterating through multiple pages. Returns combined results with the last page token. If not provided, returns only a single page ."
173176 ) ]
174177 number_of_payments : Option < u64 > ,
178+ #[ arg( long) ]
179+ #[ arg( help = "Page token to continue from a previous page (format: token:index)" ) ]
180+ page_token : Option < String > ,
175181 } ,
176182 UpdateChannelConfig {
177183 #[ arg( short, long) ]
@@ -407,12 +413,15 @@ async fn main() {
407413 client. list_channels ( ListChannelsRequest { } ) . await ,
408414 ) ;
409415 } ,
410- Commands :: ListPayments { number_of_payments } => {
411- handle_response_result :: < _ , ListPaymentsResponse > (
412- list_n_payments ( client, number_of_payments)
413- . await
414- // todo: handle pagination properly
415- . map ( |payments| ListPaymentsResponse { payments, next_page_token : None } ) ,
416+ Commands :: ListPayments { number_of_payments, page_token } => {
417+ let page_token = if let Some ( token_str) = page_token {
418+ Some ( parse_page_token ( & token_str) . unwrap_or_else ( |e| handle_error ( e) ) )
419+ } else {
420+ None
421+ } ;
422+
423+ handle_response_result :: < _ , CliListPaymentsResponse > (
424+ handle_list_payments ( client, number_of_payments, page_token) . await ,
416425 ) ;
417426 } ,
418427 Commands :: UpdateChannelConfig {
@@ -466,24 +475,37 @@ fn build_open_channel_config(
466475 } )
467476}
468477
478+ async fn handle_list_payments (
479+ client : LdkServerClient , number_of_payments : Option < u64 > , initial_page_token : Option < PageToken > ,
480+ ) -> Result < ListPaymentsResponse , LdkServerError > {
481+ if let Some ( count) = number_of_payments {
482+ list_n_payments ( client, count, initial_page_token) . await
483+ } else {
484+ // Fetch single page
485+ client. list_payments ( ListPaymentsRequest { page_token : initial_page_token } ) . await
486+ }
487+ }
488+
469489async fn list_n_payments (
470- client : LdkServerClient , number_of_payments : Option < u64 > ,
471- ) -> Result < Vec < Payment > , LdkServerError > {
472- let mut payments = Vec :: new ( ) ;
473- let mut page_token: Option < PageToken > = None ;
474- // If no count is specified, just list the first page.
475- let target_count = number_of_payments. unwrap_or ( 0 ) ;
490+ client : LdkServerClient , target_count : u64 , initial_page_token : Option < PageToken > ,
491+ ) -> Result < ListPaymentsResponse , LdkServerError > {
492+ let mut payments = Vec :: with_capacity ( target_count as usize ) ;
493+ let mut page_token = initial_page_token;
494+ let mut next_page_token;
476495
477496 loop {
478497 let response = client. list_payments ( ListPaymentsRequest { page_token } ) . await ?;
479498
480499 payments. extend ( response. payments ) ;
481- if payments. len ( ) >= target_count as usize || response. next_page_token . is_none ( ) {
500+ next_page_token = response. next_page_token ;
501+
502+ if payments. len ( ) >= target_count as usize || next_page_token. is_none ( ) {
482503 break ;
483504 }
484- page_token = response . next_page_token ;
505+ page_token = next_page_token;
485506 }
486- Ok ( payments)
507+
508+ Ok ( ListPaymentsResponse { payments, next_page_token } )
487509}
488510
489511fn handle_response_result < Rs , Js > ( response : Result < Rs , LdkServerError > )
@@ -508,6 +530,20 @@ where
508530 }
509531}
510532
533+ fn parse_page_token ( token_str : & str ) -> Result < PageToken , LdkServerError > {
534+ let parts: Vec < & str > = token_str. split ( ':' ) . collect ( ) ;
535+ if parts. len ( ) != 2 {
536+ return Err ( LdkServerError :: new (
537+ InternalError ,
538+ "Page token must be in format 'token:index'" . to_string ( ) ,
539+ ) ) ;
540+ }
541+ let index = parts[ 1 ]
542+ . parse :: < i64 > ( )
543+ . map_err ( |_| LdkServerError :: new ( InternalError , "Invalid page token index" . to_string ( ) ) ) ?;
544+ Ok ( PageToken { token : parts[ 0 ] . to_string ( ) , index } )
545+ }
546+
511547fn handle_error ( e : LdkServerError ) -> ! {
512548 let error_type = match e. error_code {
513549 InvalidRequestError => "Invalid Request" ,
0 commit comments