@@ -24,10 +24,13 @@ use ldk_server_client::ldk_server_protos::api::{
2424 SpliceOutResponse , UpdateChannelConfigRequest , UpdateChannelConfigResponse ,
2525} ;
2626use ldk_server_client:: ldk_server_protos:: types:: {
27- bolt11_invoice_description, Bolt11InvoiceDescription , ChannelConfig , PageToken , Payment ,
27+ bolt11_invoice_description, Bolt11InvoiceDescription , ChannelConfig , PageToken ,
2828 RouteParametersConfig ,
2929} ;
3030use serde:: Serialize ;
31+ use types:: CliListPaymentsResponse ;
32+
33+ mod types;
3134
3235// Having these default values as constants in the Proto file and
3336// importing/reusing them here might be better, but Proto3 removed
@@ -178,9 +181,12 @@ enum Commands {
178181 ListPayments {
179182 #[ arg( short, long) ]
180183 #[ arg(
181- help = "Minimum number of payments to return. If not provided, only the first page of the paginated list is returned ."
184+ 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 ."
182185 ) ]
183186 number_of_payments : Option < u64 > ,
187+ #[ arg( long) ]
188+ #[ arg( help = "Page token to continue from a previous page (format: token:index)" ) ]
189+ page_token : Option < String > ,
184190 } ,
185191 UpdateChannelConfig {
186192 #[ arg( short, long) ]
@@ -416,12 +422,15 @@ async fn main() {
416422 client. list_channels ( ListChannelsRequest { } ) . await ,
417423 ) ;
418424 } ,
419- Commands :: ListPayments { number_of_payments } => {
420- handle_response_result :: < _ , ListPaymentsResponse > (
421- list_n_payments ( client, number_of_payments)
422- . await
423- // todo: handle pagination properly
424- . map ( |payments| ListPaymentsResponse { payments, next_page_token : None } ) ,
425+ Commands :: ListPayments { number_of_payments, page_token } => {
426+ let page_token = if let Some ( token_str) = page_token {
427+ Some ( parse_page_token ( & token_str) . unwrap_or_else ( |e| handle_error ( e) ) )
428+ } else {
429+ None
430+ } ;
431+
432+ handle_response_result :: < _ , CliListPaymentsResponse > (
433+ handle_list_payments ( client, number_of_payments, page_token) . await ,
425434 ) ;
426435 } ,
427436 Commands :: UpdateChannelConfig {
@@ -475,24 +484,37 @@ fn build_open_channel_config(
475484 } )
476485}
477486
487+ async fn handle_list_payments (
488+ client : LdkServerClient , number_of_payments : Option < u64 > , initial_page_token : Option < PageToken > ,
489+ ) -> Result < ListPaymentsResponse , LdkServerError > {
490+ if let Some ( count) = number_of_payments {
491+ list_n_payments ( client, count, initial_page_token) . await
492+ } else {
493+ // Fetch single page
494+ client. list_payments ( ListPaymentsRequest { page_token : initial_page_token } ) . await
495+ }
496+ }
497+
478498async fn list_n_payments (
479- client : LdkServerClient , number_of_payments : Option < u64 > ,
480- ) -> Result < Vec < Payment > , LdkServerError > {
481- let mut payments = Vec :: new ( ) ;
482- let mut page_token: Option < PageToken > = None ;
483- // If no count is specified, just list the first page.
484- let target_count = number_of_payments. unwrap_or ( 0 ) ;
499+ client : LdkServerClient , target_count : u64 , initial_page_token : Option < PageToken > ,
500+ ) -> Result < ListPaymentsResponse , LdkServerError > {
501+ let mut payments = Vec :: with_capacity ( target_count as usize ) ;
502+ let mut page_token = initial_page_token;
503+ let mut next_page_token;
485504
486505 loop {
487506 let response = client. list_payments ( ListPaymentsRequest { page_token } ) . await ?;
488507
489508 payments. extend ( response. payments ) ;
490- if payments. len ( ) >= target_count as usize || response. next_page_token . is_none ( ) {
509+ next_page_token = response. next_page_token ;
510+
511+ if payments. len ( ) >= target_count as usize || next_page_token. is_none ( ) {
491512 break ;
492513 }
493- page_token = response . next_page_token ;
514+ page_token = next_page_token;
494515 }
495- Ok ( payments)
516+
517+ Ok ( ListPaymentsResponse { payments, next_page_token } )
496518}
497519
498520fn handle_response_result < Rs , Js > ( response : Result < Rs , LdkServerError > )
@@ -517,6 +539,20 @@ where
517539 }
518540}
519541
542+ fn parse_page_token ( token_str : & str ) -> Result < PageToken , LdkServerError > {
543+ let parts: Vec < & str > = token_str. split ( ':' ) . collect ( ) ;
544+ if parts. len ( ) != 2 {
545+ return Err ( LdkServerError :: new (
546+ InternalError ,
547+ "Page token must be in format 'token:index'" . to_string ( ) ,
548+ ) ) ;
549+ }
550+ let index = parts[ 1 ]
551+ . parse :: < i64 > ( )
552+ . map_err ( |_| LdkServerError :: new ( InternalError , "Invalid page token index" . to_string ( ) ) ) ?;
553+ Ok ( PageToken { token : parts[ 0 ] . to_string ( ) , index } )
554+ }
555+
520556fn handle_error ( e : LdkServerError ) -> ! {
521557 let error_type = match e. error_code {
522558 InvalidRequestError => "Invalid Request" ,
0 commit comments