diff --git a/wavesrv/pkg/telemetry/telemetry.go b/wavesrv/pkg/telemetry/telemetry.go index 865d949aa..a8418aa06 100644 --- a/wavesrv/pkg/telemetry/telemetry.go +++ b/wavesrv/pkg/telemetry/telemetry.go @@ -6,7 +6,10 @@ package telemetry import ( "context" "database/sql/driver" + "fmt" "log" + "regexp" + "strconv" "time" "github.com/wavetermdev/waveterm/wavesrv/pkg/dbutil" @@ -81,6 +84,99 @@ func GetCurDayStr() string { return dayStr } +func GetRelDayStr(relDays int) string { + now := time.Now() + dayStr := now.AddDate(0, 0, relDays).Format("2006-01-02") + return dayStr +} + +// accepts a custom format string to return a daystr +// can be either a prefix, a delta, or a prefix w/ a delta +// if no prefix is given, "today" is assumed +// examples: today-2d, bow, bom+1m-1d (that's end of the month), 2024-04-01+1w +// +// prefixes: +// +// yyyy-mm-dd +// today +// yesterday +// bom (beginning of month) +// bow (beginning of week -- sunday) +// +// deltas: +// +// +[n]d, -[n]d (e.g. +1d, -5d) +// +[n]w, -[n]w (e.g. +2w) +// +[n]m, -[n]m (e.g. -1m) +// deltas can be combined e.g. +1w-2d +func GetCustomDayStr(format string) (string, error) { + m := customDayStrRe.FindStringSubmatch(format) + if m == nil { + return "", fmt.Errorf("invalid daystr format") + } + prefix, deltas := m[1], m[2] + if prefix == "" { + prefix = "today" + } + var rtnTime time.Time + now := time.Now() + switch prefix { + case "today": + rtnTime = now + case "yesterday": + rtnTime = now.AddDate(0, 0, -1) + case "bom": + rtnTime = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) + case "bow": + weekday := now.Weekday() + if weekday == time.Sunday { + rtnTime = now + } else { + rtnTime = now.AddDate(0, 0, -int(weekday)) + } + default: + m = daystrRe.FindStringSubmatch(prefix) + if m == nil { + return "", fmt.Errorf("invalid prefix format") + } + year, month, day := m[1], m[2], m[3] + yearInt, monthInt, dayInt := atoiNoErr(year), atoiNoErr(month), atoiNoErr(day) + if yearInt == 0 || monthInt == 0 || dayInt == 0 { + return "", fmt.Errorf("invalid prefix format") + } + rtnTime = time.Date(yearInt, time.Month(monthInt), dayInt, 0, 0, 0, 0, now.Location()) + } + for _, delta := range regexp.MustCompile(`[+-]\d+[dwm]`).FindAllString(deltas, -1) { + deltaVal, err := strconv.Atoi(delta[1 : len(delta)-1]) + if err != nil { + return "", fmt.Errorf("invalid delta format") + } + if delta[0] == '-' { + deltaVal = -deltaVal + } + switch delta[len(delta)-1] { + case 'd': + rtnTime = rtnTime.AddDate(0, 0, deltaVal) + case 'w': + rtnTime = rtnTime.AddDate(0, 0, deltaVal*7) + case 'm': + rtnTime = rtnTime.AddDate(0, deltaVal, 0) + } + } + return rtnTime.Format("2006-01-02"), nil +} + +func atoiNoErr(str string) int { + val, err := strconv.Atoi(str) + if err != nil { + return 0 + } + return val +} + +var customDayStrRe = regexp.MustCompile(`^((?:\d{4}-\d{2}-\d{2})|today|yesterday|bom|bow)?((?:[+-]\d+[dwm])*)$`) +var daystrRe = regexp.MustCompile(`^(\d{4})-(\d{2})-(\d{2})$`) + func UpdateCurrentActivity(ctx context.Context, update ActivityUpdate) error { now := time.Now() dayStr := GetCurDayStr() diff --git a/wavesrv/pkg/telemetry/telemetry_test.go b/wavesrv/pkg/telemetry/telemetry_test.go new file mode 100644 index 000000000..875f834e5 --- /dev/null +++ b/wavesrv/pkg/telemetry/telemetry_test.go @@ -0,0 +1,41 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +package telemetry + +import ( + "testing" + "time" +) + +func testCustomDaystr(t *testing.T, customDayStr string, expectedDayStr string, shouldErr bool) { + rtn, err := GetCustomDayStr(customDayStr) + if err != nil { + if !shouldErr { + t.Errorf("unexpected error: %v", err) + } + } else { + if rtn != expectedDayStr { + t.Errorf("for %q expected %q, got %q", customDayStr, expectedDayStr, rtn) + } + } +} + +func TestDaystrCustom(t *testing.T) { + now := time.Now() + bom := now.AddDate(0, 0, -now.Day()+1) + testCustomDaystr(t, "today", GetCurDayStr(), false) + testCustomDaystr(t, "yesterday", GetRelDayStr(-1), false) + testCustomDaystr(t, "bom", bom.Format("2006-01-02"), false) + bow := now.AddDate(0, 0, -int(now.Weekday())) + testCustomDaystr(t, "bow", bow.Format("2006-01-02"), false) + testCustomDaystr(t, "today-1d", GetRelDayStr(-1), false) + testCustomDaystr(t, "today+1d", GetRelDayStr(1), false) + testCustomDaystr(t, "today-1w", GetRelDayStr(-7), false) + day1 := bom.AddDate(0, 1, -1) + testCustomDaystr(t, "bom+1m-1d", day1.Format("2006-01-02"), false) + testCustomDaystr(t, "foo", "", true) + testCustomDaystr(t, "2000-1-1", "", true) + testCustomDaystr(t, "2024-01-01+1w", "2024-01-08", false) + testCustomDaystr(t, "2024-01-01+1m+1w-1d", "2024-02-07", false) +}