From ced2dafbcde6fea458476c13d2d067dbf61d6838 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Mon, 9 May 2022 17:16:20 +0200 Subject: [PATCH] Make settings decoding more robust (numbers & strings) --- system/service/settings.go | 2 +- system/types/kv_decoder.go | 30 +++++++++++++++++++++++------- system/types/kv_decoder_test.go | 18 ++++++++++++------ 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/system/service/settings.go b/system/service/settings.go index 0b0a20146..3646a8b5e 100644 --- a/system/service/settings.go +++ b/system/service/settings.go @@ -161,7 +161,7 @@ func (svc *settings) updateCurrent(ctx context.Context, vv types.SettingValueSet // update current settings with new values if err = vv.KV().Decode(svc.current); err != nil { - return + return fmt.Errorf("could not decode settings: %v", err) } // push message over update chan so that we can notify all settings listeners diff --git a/system/types/kv_decoder.go b/system/types/kv_decoder.go index ba89ecc1d..3b0284470 100644 --- a/system/types/kv_decoder.go +++ b/system/types/kv_decoder.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "reflect" "strconv" "strings" @@ -102,7 +103,7 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) { if decode, ok := decodeMethod.Interface().(func(SettingsKV, string) error); !ok { panic("invalid DecodeKV() function signature") } else if err = decode(kv, key); err != nil { - return errors.Wrapf(err, "cannot decode settings for %q", key) + return fmt.Errorf("cannot decode settings for %q: %w", key, err) } else { continue } @@ -114,7 +115,7 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) { // It calls DecodeKV recursively if structField.Kind() == reflect.Struct { if err = DecodeKV(kv.Filter(key), structValue, key); err != nil { - return + return err } continue @@ -132,7 +133,7 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) { mapValue := reflect.New(structField.Type().Elem()) err = val.Unmarshal(mapValue.Interface()) if err != nil { - return errors.Wrapf(err, "cannot decode settings for %q", key) + return fmt.Errorf("cannot decode JSON into map for key %q: %w", key, err) } structField.SetMapIndex(reflect.ValueOf(k), mapValue.Elem()) @@ -156,15 +157,30 @@ func DecodeKV(kv SettingsKV, dst interface{}, pp ...string) (err error) { if val.Unmarshal(structField.Addr().Interface()) != nil { // Try to get numbers encoded as strings... var tmp interface{} - if val.Unmarshal(&tmp) != nil { - return err + if err = val.Unmarshal(&tmp); err != nil { + return fmt.Errorf("could not decode JSON for key %q: %w", key, err) } - switch cnv := tmp.(type) { - case string: + var cnv, is = tmp.(string) + if !is { + // give up + continue + } + + switch structFType.Type.Kind() { + case reflect.Int, reflect.Int32, reflect.Int64: + if num, err := strconv.ParseInt(cnv, 10, 64); err == nil { + structField.SetInt(num) + } + case reflect.Uint, reflect.Uint32, reflect.Uint64: if num, err := strconv.ParseUint(cnv, 10, 64); err == nil { structField.SetUint(num) } + case reflect.Float32, reflect.Float64: + if num, err := strconv.ParseFloat(cnv, 64); err == nil { + structField.SetFloat(num) + } + } } } diff --git a/system/types/kv_decoder_test.go b/system/types/kv_decoder_test.go index 17acbe870..6d14b5b3a 100644 --- a/system/types/kv_decoder_test.go +++ b/system/types/kv_decoder_test.go @@ -21,9 +21,11 @@ func TestDecode(t *testing.T) { withHandler struct{} dst struct { - S string `kv:"s"` - B bool `kv:"b"` - N int `kv:"n"` + S string `kv:"s"` + B bool `kv:"b"` + N int `kv:"n"` + NAS int `kv:"numAsString"` + Pi float32 `kv:"pi"` NoKV string @@ -53,6 +55,8 @@ func TestDecode(t *testing.T) { "s": types.JSONText(`"string"`), "b": types.JSONText("true"), "n": types.JSONText("42"), + "numAsString": types.JSONText(`"84"`), + "pi": types.JSONText(`"3.14"`), "sub.s": types.JSONText(`"string"`), "sub.b": types.JSONText("true"), "sub.bar": nil, @@ -73,9 +77,11 @@ func TestDecode(t *testing.T) { } eq = dst{ - S: "string", - B: true, - N: 42, + S: "string", + B: true, + N: 42, + NAS: 84, + Pi: 3.14, NoKV: "NO-SettingsKV-!", Ptr: &ptr,