From 59afe398a3125b1b5fa07b8347afa5000bf6b558 Mon Sep 17 00:00:00 2001 From: Robin Date: Thu, 20 Jul 2023 08:07:43 +0200 Subject: [PATCH] fix: Parse number Durations in config correctly (fix #221) This error edge case was introduced by #218. --- pkg/edition/java/lite/config/config.go | 4 +-- pkg/util/configutil/duration.go | 40 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 pkg/util/configutil/duration.go diff --git a/pkg/edition/java/lite/config/config.go b/pkg/edition/java/lite/config/config.go index 148dfaaf..1bc289b0 100644 --- a/pkg/edition/java/lite/config/config.go +++ b/pkg/edition/java/lite/config/config.go @@ -30,7 +30,7 @@ type ( Route struct { Host configutil.SingleOrMulti[string] `json:"host" yaml:"host"` Backend configutil.SingleOrMulti[string] `json:"backend" yaml:"backend"` - CachePingTTL time.Duration `json:"cachePingTTL,omitempty" yaml:"cachePingTTL,omitempty"` // 0 = default, < 0 = disabled + CachePingTTL configutil.Duration `json:"cachePingTTL,omitempty" yaml:"cachePingTTL,omitempty"` // 0 = default, < 0 = disabled Fallback *Status `json:"fallback,omitempty" yaml:"fallback,omitempty"` // nil = disabled ProxyProtocol bool `json:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty"` RealIP bool `json:"realIP,omitempty" yaml:"realIP,omitempty"` @@ -73,7 +73,7 @@ func (r *Route) GetCachePingTTL() time.Duration { if r.CachePingTTL == 0 { return defaultTTL } - return r.CachePingTTL + return time.Duration(r.CachePingTTL) } // CachePingEnabled returns true if the route has a ping cache enabled. diff --git a/pkg/util/configutil/duration.go b/pkg/util/configutil/duration.go new file mode 100644 index 00000000..272a9f9c --- /dev/null +++ b/pkg/util/configutil/duration.go @@ -0,0 +1,40 @@ +package configutil + +import ( + "encoding/json" + "fmt" + "time" +) + +// Duration is a configuration duration. +// It is a wrapper around time.Duration that implements the json.Marshaler and json.Unmarshaler interfaces. +// +// - string is parsed using time.ParseDuration. +// - int64 and float64 are interpreted as seconds. +type Duration time.Duration + +func (d *Duration) MarshalJSON() ([]byte, error) { + return json.Marshal(time.Duration(*d).String()) +} + +func (d *Duration) UnmarshalJSON(data []byte) error { + var a any + if err := json.Unmarshal(data, &a); err != nil { + return err + } + switch v := a.(type) { + case string: + dur, err := time.ParseDuration(v) + if err != nil { + return err + } + *d = Duration(dur) + case float64: + *d = Duration(time.Duration(v) * time.Second) + case int64: + *d = Duration(time.Duration(v) * time.Second) + default: + return fmt.Errorf("invalid duration type %T: %v", v, v) + } + return nil +}