5849898283
Unit tests functional and coverage back to 100% Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
258 lines
5.6 KiB
Go
258 lines
5.6 KiB
Go
package validator
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// extractTypeInternal gets the actual underlying type of field value.
|
|
// It will dive into pointers, customTypes and return you the
|
|
// underlying value and it's kind.
|
|
func (v *validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
|
|
|
|
BEGIN:
|
|
switch current.Kind() {
|
|
case reflect.Ptr:
|
|
|
|
nullable = true
|
|
|
|
if current.IsNil() {
|
|
return current, reflect.Ptr, nullable
|
|
}
|
|
|
|
current = current.Elem()
|
|
goto BEGIN
|
|
|
|
case reflect.Interface:
|
|
|
|
nullable = true
|
|
|
|
if current.IsNil() {
|
|
return current, reflect.Interface, nullable
|
|
}
|
|
|
|
current = current.Elem()
|
|
goto BEGIN
|
|
|
|
case reflect.Invalid:
|
|
return current, reflect.Invalid, nullable
|
|
|
|
default:
|
|
|
|
if v.v.hasCustomFuncs {
|
|
|
|
if fn, ok := v.v.customFuncs[current.Type()]; ok {
|
|
current = reflect.ValueOf(fn(current))
|
|
goto BEGIN
|
|
}
|
|
}
|
|
|
|
return current, current.Kind(), nullable
|
|
}
|
|
}
|
|
|
|
// getStructFieldOKInternal traverses a struct to retrieve a specific field denoted by the provided namespace and
|
|
// returns the field, field kind and whether is was successful in retrieving the field at all.
|
|
//
|
|
// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
|
|
// could not be retrieved because it didn't exist.
|
|
func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace string) (current reflect.Value, kind reflect.Kind, found bool) {
|
|
|
|
BEGIN:
|
|
current, kind, _ = v.ExtractType(val)
|
|
|
|
if kind == reflect.Invalid {
|
|
return
|
|
}
|
|
|
|
if namespace == "" {
|
|
found = true
|
|
return
|
|
}
|
|
|
|
switch kind {
|
|
|
|
case reflect.Ptr, reflect.Interface:
|
|
return
|
|
|
|
case reflect.Struct:
|
|
|
|
typ := current.Type()
|
|
fld := namespace
|
|
var ns string
|
|
|
|
if typ != timeType {
|
|
|
|
idx := strings.Index(namespace, namespaceSeparator)
|
|
|
|
if idx != -1 {
|
|
fld = namespace[:idx]
|
|
ns = namespace[idx+1:]
|
|
} else {
|
|
ns = ""
|
|
}
|
|
|
|
bracketIdx := strings.Index(fld, leftBracket)
|
|
if bracketIdx != -1 {
|
|
fld = fld[:bracketIdx]
|
|
|
|
ns = namespace[bracketIdx:]
|
|
}
|
|
|
|
val = current.FieldByName(fld)
|
|
namespace = ns
|
|
goto BEGIN
|
|
}
|
|
|
|
case reflect.Array, reflect.Slice:
|
|
idx := strings.Index(namespace, leftBracket)
|
|
idx2 := strings.Index(namespace, rightBracket)
|
|
|
|
arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
|
|
|
|
if arrIdx >= current.Len() {
|
|
return current, kind, false
|
|
}
|
|
|
|
startIdx := idx2 + 1
|
|
|
|
if startIdx < len(namespace) {
|
|
if namespace[startIdx:startIdx+1] == namespaceSeparator {
|
|
startIdx++
|
|
}
|
|
}
|
|
|
|
val = current.Index(arrIdx)
|
|
namespace = namespace[startIdx:]
|
|
goto BEGIN
|
|
|
|
case reflect.Map:
|
|
idx := strings.Index(namespace, leftBracket) + 1
|
|
idx2 := strings.Index(namespace, rightBracket)
|
|
|
|
endIdx := idx2
|
|
|
|
if endIdx+1 < len(namespace) {
|
|
if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
|
|
endIdx++
|
|
}
|
|
}
|
|
|
|
key := namespace[idx:idx2]
|
|
|
|
switch current.Type().Key().Kind() {
|
|
case reflect.Int:
|
|
i, _ := strconv.Atoi(key)
|
|
val = current.MapIndex(reflect.ValueOf(i))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Int8:
|
|
i, _ := strconv.ParseInt(key, 10, 8)
|
|
val = current.MapIndex(reflect.ValueOf(int8(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Int16:
|
|
i, _ := strconv.ParseInt(key, 10, 16)
|
|
val = current.MapIndex(reflect.ValueOf(int16(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Int32:
|
|
i, _ := strconv.ParseInt(key, 10, 32)
|
|
val = current.MapIndex(reflect.ValueOf(int32(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Int64:
|
|
i, _ := strconv.ParseInt(key, 10, 64)
|
|
val = current.MapIndex(reflect.ValueOf(i))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Uint:
|
|
i, _ := strconv.ParseUint(key, 10, 0)
|
|
val = current.MapIndex(reflect.ValueOf(uint(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Uint8:
|
|
i, _ := strconv.ParseUint(key, 10, 8)
|
|
val = current.MapIndex(reflect.ValueOf(uint8(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Uint16:
|
|
i, _ := strconv.ParseUint(key, 10, 16)
|
|
val = current.MapIndex(reflect.ValueOf(uint16(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Uint32:
|
|
i, _ := strconv.ParseUint(key, 10, 32)
|
|
val = current.MapIndex(reflect.ValueOf(uint32(i)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Uint64:
|
|
i, _ := strconv.ParseUint(key, 10, 64)
|
|
val = current.MapIndex(reflect.ValueOf(i))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Float32:
|
|
f, _ := strconv.ParseFloat(key, 32)
|
|
val = current.MapIndex(reflect.ValueOf(float32(f)))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Float64:
|
|
f, _ := strconv.ParseFloat(key, 64)
|
|
val = current.MapIndex(reflect.ValueOf(f))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
case reflect.Bool:
|
|
b, _ := strconv.ParseBool(key)
|
|
val = current.MapIndex(reflect.ValueOf(b))
|
|
namespace = namespace[endIdx+1:]
|
|
|
|
// reflect.Type = string
|
|
default:
|
|
val = current.MapIndex(reflect.ValueOf(key))
|
|
namespace = namespace[endIdx+1:]
|
|
}
|
|
|
|
goto BEGIN
|
|
}
|
|
|
|
// if got here there was more namespace, cannot go any deeper
|
|
panic("Invalid field namespace")
|
|
}
|
|
|
|
// asInt returns the parameter as a int64
|
|
// or panics if it can't convert
|
|
func asInt(param string) int64 {
|
|
|
|
i, err := strconv.ParseInt(param, 0, 64)
|
|
panicIf(err)
|
|
|
|
return i
|
|
}
|
|
|
|
// asUint returns the parameter as a uint64
|
|
// or panics if it can't convert
|
|
func asUint(param string) uint64 {
|
|
|
|
i, err := strconv.ParseUint(param, 0, 64)
|
|
panicIf(err)
|
|
|
|
return i
|
|
}
|
|
|
|
// asFloat returns the parameter as a float64
|
|
// or panics if it can't convert
|
|
func asFloat(param string) float64 {
|
|
|
|
i, err := strconv.ParseFloat(param, 64)
|
|
panicIf(err)
|
|
|
|
return i
|
|
}
|
|
|
|
func panicIf(err error) {
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
}
|