2022-11-10 12:15:52 +01:00

170 lines
3.6 KiB
Go

package decoders
// Decode interfaces into expected types
// with a fallback.
import (
"fmt"
"strconv"
"strings"
"time"
)
// String asserts a string, provided a default
func String(value interface{}, fallback string) string {
sval, ok := value.(string)
if !ok {
return fallback
}
return sval
}
// StringList decodes a list of strings
func StringList(data interface{}) []string {
ldata, ok := data.([]interface{})
if !ok {
return []string{}
}
list := make([]string, 0, len(ldata))
for _, e := range ldata {
s, ok := e.(string)
if ok {
list = append(list, s)
}
}
return list
}
// TrimmedCSVStringList makes a trimmed list of CSV strings
// omitting empty values.
func TrimmedCSVStringList(s string) []string {
tokens := strings.Split(s, ",")
list := []string{}
for _, t := range tokens {
if t == "" {
continue
}
list = append(list, strings.TrimSpace(t))
}
return list
}
// IntList decodes a list of integers
func IntList(data interface{}) []int {
sdata := StringList(data)
list := make([]int, 0, len(sdata))
for _, e := range sdata {
val, err := strconv.Atoi(e)
if err == nil {
list = append(list, val)
}
}
return list
}
// IntListFromStrings decodes a list of strings
// into a list of integers.
func IntListFromStrings(strs []string) []int {
list := make([]int, 0, len(strs))
for _, s := range strs {
v, err := strconv.Atoi(s)
if err != nil {
continue // skip this
}
list = append(list, v)
}
return list
}
// Int decodes an integer value
func Int(value interface{}, fallback int) int {
fval, ok := value.(float64)
if !ok {
return fallback
}
return int(fval)
}
// IntFromString decodes an integer from a string
func IntFromString(s string, fallback int) int {
val, err := strconv.Atoi(s)
if err != nil {
return fallback
}
return val
}
// Bool decodes a boolean value
func Bool(value interface{}, fallback bool) bool {
val, ok := value.(bool)
if !ok {
return fallback
}
return val
}
// Duration decodes a time.Duration
func Duration(value interface{}, fallback time.Duration) time.Duration {
val, ok := value.(time.Duration)
if !ok {
return fallback
}
return val
}
// DurationTimeframe decodes a duration: Bgpctl encodes
// this using fmt_timeframe, whiuch outputs a format similar
// to that being understood by time.ParseDuration - however
// the time unit "w" (weeks) is not supported.
// According to https://github.com/openbgpd-portable/openbgpd-openbsd/blob/master/src/usr.sbin/bgpctl/bgpctl.c#L586-L591
// we have to parse %02lluw%01ud%02uh, %01ud%02uh%02um and %02u:%02u:%02u.
// This yields three formats:
//
// 01w3d01h
// 1d02h03m
// 01:02:03
func DurationTimeframe(value interface{}, fallback time.Duration) time.Duration {
var sec, min, hour, day uint
var week uint64
sval := String(value, "")
if sval == "" {
return fallback
}
n, _ := fmt.Sscanf(sval, "%02dw%01dd%02dh", &week, &day, &hour)
if n == 3 {
return time.Duration(week)*7*24*time.Hour +
time.Duration(day)*24*time.Hour +
time.Duration(hour)*time.Hour
}
n, _ = fmt.Sscanf(sval, "%01dd%02dh%02dm", &day, &hour, &min)
if n == 3 {
return time.Duration(day)*24*time.Hour +
time.Duration(hour)*time.Hour +
time.Duration(min)*time.Minute
}
n, _ = fmt.Sscanf(sval, "%02d:%02d:%02d", &hour, &min, &sec)
if n == 3 {
return time.Duration(hour)*time.Hour +
time.Duration(min)*time.Minute +
time.Duration(sec)*time.Second
}
return fallback
}
// TimeUTC returns the time expecting an UTC timestamp
func TimeUTC(value interface{}, fallback time.Time) time.Time {
sval := String(value, "")
if sval == "" {
return fallback
}
t, err := time.Parse(time.RFC3339Nano, sval)
if err != nil {
return fallback
}
return t
}