refactored some stuff, added healthcheck support, fixed 'include file' reload not showing in log

This commit is contained in:
yusing
2024-10-12 13:56:38 +08:00
parent 64e30f59e8
commit d47b672aa5
41 changed files with 783 additions and 421 deletions

View File

@@ -24,6 +24,10 @@ func NewMapFrom[KT comparable, VT any](m map[KT]VT) (res Map[KT, VT]) {
return
}
func NewMap[MapType Map[KT, VT], KT comparable, VT any]() Map[KT, VT] {
return NewMapOf[KT, VT]()
}
// MapFind iterates over the map and returns the first value
// that satisfies the given criteria. The iteration is stopped
// once a value is found. If no value satisfies the criteria,
@@ -161,7 +165,7 @@ func (m Map[KT, VT]) UnmarshalFromYAML(data []byte) E.NestedError {
return E.FailedWhy("unmarshal from yaml", "map is not empty")
}
tmp := make(map[KT]VT)
if err := E.From(yaml.Unmarshal(data, tmp)); err.HasError() {
if err := E.From(yaml.Unmarshal(data, tmp)); err != nil {
return err
}
for k, v := range tmp {

View File

@@ -8,6 +8,7 @@ import (
"reflect"
"strconv"
"strings"
"time"
"unicode"
"github.com/santhosh-tekuri/jsonschema"
@@ -18,7 +19,7 @@ import (
type (
SerializedObject = map[string]any
Converter interface {
ConvertFrom(value any) (any, E.NestedError)
ConvertFrom(value any) E.NestedError
}
)
@@ -264,23 +265,10 @@ func Convert(src reflect.Value, dst reflect.Value) E.NestedError {
var ok bool
// check if (*T).Convertor is implemented
if converter, ok = dst.Addr().Interface().(Converter); !ok {
// check if (T).Convertor is implemented
converter, ok = dst.Interface().(Converter)
if !ok {
return E.TypeError("conversion", srcT, dstT)
}
return E.TypeError("conversion", srcT, dstT)
}
converted, err := converter.ConvertFrom(src.Interface())
if err != nil {
return err
}
c := reflect.ValueOf(converted)
if c.Kind() == reflect.Ptr {
c = c.Elem()
}
dst.Set(c)
return nil
return converter.ConvertFrom(src.Interface())
}
func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.NestedError) {
@@ -295,6 +283,20 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.N
dst.SetString(src)
return
}
switch dst.Type() {
case reflect.TypeFor[time.Duration]():
if src == "" {
dst.Set(reflect.Zero(dst.Type()))
return
}
d, err := time.ParseDuration(src)
if err != nil {
convErr = E.Invalid("duration", src)
return
}
dst.Set(reflect.ValueOf(d))
return
}
// primitive types / simple types
switch dst.Kind() {
case reflect.Bool:

View File

@@ -4,6 +4,7 @@ import (
"reflect"
"testing"
E "github.com/yusing/go-proxy/internal/error"
. "github.com/yusing/go-proxy/internal/utils/testing"
)
@@ -102,3 +103,48 @@ func TestStringIntConvert(t *testing.T) {
ExpectNoError(t, err.Error())
ExpectEqual(t, test.u64, uint64(127))
}
type testModel struct {
Test testType
}
type testType struct {
foo int
bar string
}
func (c *testType) ConvertFrom(v any) E.NestedError {
switch v := v.(type) {
case string:
c.bar = v
return nil
case int:
c.foo = v
return nil
default:
return E.Invalid("input type", v)
}
}
func TestConvertor(t *testing.T) {
t.Run("string", func(t *testing.T) {
m := new(testModel)
ExpectNoError(t, Deserialize(map[string]any{"Test": "bar"}, m).Error())
ExpectEqual(t, m.Test.foo, 0)
ExpectEqual(t, m.Test.bar, "bar")
})
t.Run("int", func(t *testing.T) {
m := new(testModel)
ExpectNoError(t, Deserialize(map[string]any{"Test": 123}, m).Error())
ExpectEqual(t, m.Test.foo, 123)
ExpectEqual(t, m.Test.bar, "")
})
t.Run("invalid", func(t *testing.T) {
m := new(testModel)
ExpectError(t, E.ErrInvalid, Deserialize(map[string]any{"Test": 123.456}, m).Error())
})
}