Skip to content

Commit eca9e7a

Browse files
committed
looprpc: add simple pagination to the ListSwaps command
This commit adds the ability to set a max_swaps and an index_offset flag to the ListSwaps command. These new fields are applied AFTER the initial filtering step. The response also now passes additional information about the index count and total swaps filtered.
1 parent bfe7991 commit eca9e7a

File tree

5 files changed

+1011
-866
lines changed

5 files changed

+1011
-866
lines changed

cmd/loop/swaps.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ var listSwapsCommand = cli.Command{
3535
labelFlag,
3636
channelFlag,
3737
lastHopFlag,
38+
cli.Uint64Flag{
39+
Name: "max_swaps",
40+
Usage: "Max number of swaps to return after filtering",
41+
},
42+
cli.Int64Flag{
43+
Name: "start_time_ns",
44+
Usage: "Unix timestamp to start listing swaps from (default: 0, meaning no start time filter)",
45+
},
3846
},
3947
}
4048

@@ -99,9 +107,19 @@ func listSwaps(ctx *cli.Context) error {
99107
filter.Label = ctx.String(labelFlag.Name)
100108
}
101109

110+
// Parse start timestamp if set.
111+
if ctx.IsSet("start_time_ns") {
112+
startTimestamp, err := strconv.ParseInt(ctx.String("start_time_ns"), 10, 64)
113+
if err != nil {
114+
return fmt.Errorf("error parsing start timestamp: %v", err)
115+
}
116+
filter.StartTimestampNs = startTimestamp
117+
}
118+
102119
resp, err := client.ListSwaps(
103120
context.Background(), &looprpc.ListSwapsRequest{
104121
ListSwapFilter: filter,
122+
MaxSwaps: ctx.Uint64("max_swaps"),
105123
},
106124
)
107125
if err != nil {

loopd/swapclient_server.go

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"reflect"
10+
"slices"
1011
"sort"
1112
"strings"
1213
"sync"
@@ -563,31 +564,67 @@ func (s *swapClientServer) ListSwaps(ctx context.Context,
563564
req *looprpc.ListSwapsRequest) (*looprpc.ListSwapsResponse, error) {
564565

565566
var (
566-
rpcSwaps = []*looprpc.SwapStatus{}
567-
idx = 0
567+
rpcSwaps = []*looprpc.SwapStatus{}
568+
maxSwaps = int(req.MaxSwaps)
569+
nextStartTime = int64(0)
570+
canPage = false
568571
)
569572

570573
s.swapsLock.Lock()
571574
defer s.swapsLock.Unlock()
572575

576+
// Convert the swaps map into a slice which can be ordered.
577+
var swapList []loop.SwapInfo
578+
for _, swp := range s.swaps {
579+
swapList = append(swapList, swp)
580+
}
581+
582+
// Sort all swaps by a consistent field, InitiationTime.
583+
slices.SortFunc(swapList, func(a, b loop.SwapInfo) int {
584+
// For descending order (newest first)
585+
if a.InitiationTime.UnixNano() > b.InitiationTime.UnixNano() {
586+
return 1
587+
}
588+
if a.InitiationTime.UnixNano() < b.InitiationTime.UnixNano() {
589+
return -1
590+
}
591+
return 0
592+
})
573593
// We can just use the server's in-memory cache as that contains the
574594
// most up-to-date state including temporary failures which aren't
575595
// persisted to disk. The swaps field is a map, that's why we need an
576596
// additional index.
577-
for _, swp := range s.swaps {
597+
for _, swp := range swapList {
578598
// Filter the swap based on the provided filter.
579599
if !filterSwap(&swp, req.ListSwapFilter) {
580600
continue
581601
}
582602

583-
rpcSwap, err := s.marshallSwap(ctx, &swp)
584-
if err != nil {
585-
return nil, err
603+
// Check if this swap is within our pagination window.
604+
// If maxSwaps is 0, we return all swaps.
605+
// Otherwise, check if we've reached our limit.
606+
if maxSwaps == 0 || len(rpcSwaps) < maxSwaps {
607+
rpcSwap, err := s.marshallSwap(ctx, &swp)
608+
if err != nil {
609+
return nil, err
610+
}
611+
rpcSwaps = append(rpcSwaps, rpcSwap)
612+
} else {
613+
// Indicate that paging is enabled, and exit the loop.
614+
canPage = true
615+
break
586616
}
587-
rpcSwaps = append(rpcSwaps, rpcSwap)
588-
idx++
589617
}
590-
return &looprpc.ListSwapsResponse{Swaps: rpcSwaps}, nil
618+
619+
if canPage {
620+
nextStartTime = rpcSwaps[len(rpcSwaps)-1].InitiationTime + 1
621+
}
622+
623+
response := looprpc.ListSwapsResponse{
624+
Swaps: rpcSwaps,
625+
NextStartTime: nextStartTime,
626+
}
627+
return &response, nil
591628
}
592629

593630
// filterSwap filters the given swap based on the provided filter.
@@ -617,6 +654,11 @@ func filterSwap(swapInfo *loop.SwapInfo, filter *looprpc.ListSwapsFilter) bool {
617654
return false
618655
}
619656

657+
// If timestamp filters are set, only return swaps within the specified time range.
658+
if filter.StartTimestampNs > 0 && swapInfo.InitiationTime.UnixNano() < filter.StartTimestampNs {
659+
return false
660+
}
661+
620662
// If the swap is of type loop out and the outgoing channel filter is
621663
// set, we only return swaps that match the filter.
622664
if swapInfo.SwapType == swap.TypeOut && filter.OutgoingChanSet != nil {

0 commit comments

Comments
 (0)