cmd/lncli: add fwdinghistory support for relative times

- introduces new parser in `cmd/lncli/arg_parse.go`
- converts start_time and end_time flags to strings
- adds default value for end_time
This commit is contained in:
Jasper Rädisch 2019-05-09 22:04:39 +02:00 committed by Olaoluwa Osuntokun
parent 03b20cabd2
commit 20b42ce261
3 changed files with 153 additions and 19 deletions

40
cmd/lncli/arg_parse.go Normal file

@ -0,0 +1,40 @@
package main
import (
"regexp"
"strconv"
"time"
)
// reTimeRange matches systemd.time-like short negative timeranges, e.g. "-200s".
var reTimeRange = regexp.MustCompile(`^-\d{1,18}[s|m|h|d|w|M|y]$`)
// secondsPer allows translating s(seconds), m(minutes), h(ours), d(ays),
// w(eeks), M(onths) and y(ears) into corresponding seconds.
var secondsPer = map[string]int64{
"s": 1,
"m": 60,
"h": 3600,
"d": 86400,
"w": 604800,
"M": 2630016, // 30.44 days
"y": 31557600, // 365.25 days
}
// parseTime parses UNIX timestamps or short timeranges inspired by sytemd (when starting with "-"),
// e.g. "-1M" for one month (30.44 days) ago.
func parseTime(s string, base time.Time) (uint64, error) {
if reTimeRange.MatchString(s) {
last := len(s) - 1
d, err := strconv.ParseInt(s[1:last], 10, 64)
if err != nil {
return uint64(0), err
}
mul := secondsPer[string(s[last])]
return uint64(base.Unix() - d*mul), nil
}
return strconv.ParseUint(s, 10, 64)
}

@ -0,0 +1,88 @@
package main
import (
"testing"
"time"
)
var now = time.Date(2017, 11, 10, 7, 8, 9, 1234, time.UTC)
var partTimeTests = []struct {
in string
expected uint64
errExpected bool
}{
{
"12345",
uint64(12345),
false,
},
{
"-0s",
uint64(now.Unix()),
false,
},
{
"-1s",
uint64(time.Date(2017, 11, 10, 7, 8, 8, 1234, time.UTC).Unix()),
false,
},
{
"-2h",
uint64(time.Date(2017, 11, 10, 5, 8, 9, 1234, time.UTC).Unix()),
false,
},
{
"-3d",
uint64(time.Date(2017, 11, 7, 7, 8, 9, 1234, time.UTC).Unix()),
false,
},
{
"-4w",
uint64(time.Date(2017, 10, 13, 7, 8, 9, 1234, time.UTC).Unix()),
false,
},
{
"-5M",
uint64(now.Unix() - 30.44*5*24*60*60),
false,
},
{
"-6y",
uint64(now.Unix() - 365.25*6*24*60*60),
false,
},
{
"-999999999999999999s",
uint64(now.Unix() - 999999999999999999),
false,
},
{
"-9999999999999999991s",
0,
true,
},
{
"-7z",
0,
true,
},
}
// Test that parsing absolute and relative times works.
func TestParseTime(t *testing.T) {
for _, test := range partTimeTests {
actual, err := parseTime(test.in, now)
if test.errExpected == (err == nil) {
t.Fatalf("unexpected error for %s:\n%v\n", test.in, err)
}
if actual != test.expected {
t.Fatalf(
"for %s actual and expected do not match:\n%d\n%d\n",
test.in,
actual,
test.expected,
)
}
}
}

@ -2708,9 +2708,12 @@ var forwardingHistoryCommand = cli.Command{
Query the HTLC switch's internal forwarding log for all completed Query the HTLC switch's internal forwarding log for all completed
payment circuits (HTLCs) over a particular time range (--start_time and payment circuits (HTLCs) over a particular time range (--start_time and
--end_time). The start and end times are meant to be expressed in --end_time). The start and end times are meant to be expressed in
seconds since the Unix epoch. If --start_time isn't provided, seconds since the Unix epoch.
then 24 hours ago is used. If --end_time isn't provided, Alternatively negative time ranges can be used, e.g. "-3d". Supports
then the current time is used. s(seconds), m(minutes), h(ours), d(ays), w(eeks), M(onths), y(ears).
Month equals 30.44 days, year equals 365.25 days.
If --start_time isn't provided, then 24 hours ago is used. If
--end_time isn't provided, then the current time is used.
The max number of events returned is 50k. The default number is 100, The max number of events returned is 50k. The default number is 100,
callers can use the --max_events param to modify this value. callers can use the --max_events param to modify this value.
@ -2720,15 +2723,15 @@ var forwardingHistoryCommand = cli.Command{
entry. Using this callers can manually paginate within a time slice. entry. Using this callers can manually paginate within a time slice.
`, `,
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.Int64Flag{ cli.StringFlag{
Name: "start_time", Name: "start_time",
Usage: "the starting time for the query, expressed in " + Usage: "the starting time for the query " +
"seconds since the unix epoch", `as unix timestamp or relative e.g. "-1w"`,
}, },
cli.Int64Flag{ cli.StringFlag{
Name: "end_time", Name: "end_time",
Usage: "the end time for the query, expressed in " + Usage: "the end time for the query " +
"seconds since the unix epoch", `as unix timestamp or relative e.g. "-1w"`,
}, },
cli.Int64Flag{ cli.Int64Flag{
Name: "index_offset", Name: "index_offset",
@ -2753,30 +2756,33 @@ func forwardingHistory(ctx *cli.Context) error {
err error err error
) )
args := ctx.Args() args := ctx.Args()
now := time.Now()
switch { switch {
case ctx.IsSet("start_time"): case ctx.IsSet("start_time"):
startTime = ctx.Uint64("start_time") startTime, err = parseTime(ctx.String("start_time"), now)
case args.Present(): case args.Present():
startTime, err = strconv.ParseUint(args.First(), 10, 64) startTime, err = parseTime(args.First(), now)
if err != nil {
return fmt.Errorf("unable to decode start_time %v", err)
}
args = args.Tail() args = args.Tail()
default: default:
now := time.Now() now := time.Now()
startTime = uint64(now.Add(-time.Hour * 24).Unix()) startTime = uint64(now.Add(-time.Hour * 24).Unix())
} }
if err != nil {
return fmt.Errorf("unable to decode start_time: %v", err)
}
switch { switch {
case ctx.IsSet("end_time"): case ctx.IsSet("end_time"):
endTime = ctx.Uint64("end_time") endTime, err = parseTime(ctx.String("end_time"), now)
case args.Present(): case args.Present():
endTime, err = strconv.ParseUint(args.First(), 10, 64) endTime, err = parseTime(args.First(), now)
if err != nil {
return fmt.Errorf("unable to decode end_time: %v", err)
}
args = args.Tail() args = args.Tail()
default:
endTime = uint64(now.Unix())
}
if err != nil {
return fmt.Errorf("unable to decode end_time: %v", err)
} }
switch { switch {