distribution/vendor/github.com/denverdino/aliyungo/util/encoding.go
Li Yi 90bed67126 Support BYOK for OSS storage driver
Change-Id: I423ad03e63bd38aded3abfcba49079ff2fbb3b74
Signed-off-by: Li Yi <denverdino@gmail.com>
2018-12-25 08:30:40 +08:00

332 lines
8.1 KiB
Go

package util
import (
"encoding/json"
"fmt"
"log"
"net/url"
"reflect"
"strconv"
"strings"
"time"
)
// change instance=["a", "b"]
// to instance.1="a" instance.2="b"
func FlattenFn(fieldName string, field reflect.Value, values *url.Values) {
l := field.Len()
if l > 0 {
for i := 0; i < l; i++ {
str := field.Index(i).String()
values.Set(fieldName+"."+strconv.Itoa(i+1), str)
}
}
}
func Underline2Dot(name string) string {
return strings.Replace(name, "_", ".", -1)
}
//ConvertToQueryValues converts the struct to url.Values
func ConvertToQueryValues(ifc interface{}) url.Values {
values := url.Values{}
SetQueryValues(ifc, &values)
return values
}
//SetQueryValues sets the struct to existing url.Values following ECS encoding rules
func SetQueryValues(ifc interface{}, values *url.Values) {
setQueryValues(ifc, values, "")
}
func SetQueryValueByFlattenMethod(ifc interface{}, values *url.Values) {
setQueryValuesByFlattenMethod(ifc, values, "")
}
func setQueryValues(i interface{}, values *url.Values, prefix string) {
// add to support url.Values
mapValues, ok := i.(url.Values)
if ok {
for k, _ := range mapValues {
values.Set(k, mapValues.Get(k))
}
return
}
elem := reflect.ValueOf(i)
if elem.Kind() == reflect.Ptr {
elem = elem.Elem()
}
elemType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
fieldName := elemType.Field(i).Name
anonymous := elemType.Field(i).Anonymous
tag := elemType.Field(i).Tag.Get("query")
argName := elemType.Field(i).Tag.Get("ArgName")
field := elem.Field(i)
// TODO Use Tag for validation
// tag := typ.Field(i).Tag.Get("tagname")
kind := field.Kind()
isPtr := false
if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
continue
}
if kind == reflect.Ptr {
field = field.Elem()
kind = field.Kind()
isPtr = true
}
var value string
//switch field.Interface().(type) {
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i := field.Int()
if i != 0 || isPtr {
value = strconv.FormatInt(i, 10)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
i := field.Uint()
if i != 0 || isPtr {
value = strconv.FormatUint(i, 10)
}
case reflect.Float32:
value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
case reflect.Float64:
value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
case reflect.Bool:
value = strconv.FormatBool(field.Bool())
case reflect.String:
value = field.String()
case reflect.Map:
ifc := field.Interface()
m := ifc.(map[string]string)
if m != nil {
j := 0
for k, v := range m {
j++
keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
values.Set(keyName, k)
valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
values.Set(valueName, v)
}
}
case reflect.Slice:
switch field.Type().Elem().Kind() {
case reflect.Uint8:
value = string(field.Bytes())
case reflect.String:
l := field.Len()
if l > 0 {
if tag == "list" {
name := argName
if argName == "" {
name = fieldName
}
for i := 0; i < l; i++ {
valueName := fmt.Sprintf("%s.%d", name, (i + 1))
values.Set(valueName, field.Index(i).String())
}
} else {
strArray := make([]string, l)
for i := 0; i < l; i++ {
strArray[i] = field.Index(i).String()
}
bytes, err := json.Marshal(strArray)
if err == nil {
value = string(bytes)
} else {
log.Printf("Failed to convert JSON: %v", err)
}
}
}
default:
l := field.Len()
for j := 0; j < l; j++ {
prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
ifc := field.Index(j).Interface()
//log.Printf("%s : %v", prefixName, ifc)
if ifc != nil {
setQueryValues(ifc, values, prefixName)
}
}
continue
}
default:
switch field.Interface().(type) {
case ISO6801Time:
t := field.Interface().(ISO6801Time)
value = t.String()
case time.Time:
t := field.Interface().(time.Time)
value = GetISO8601TimeStamp(t)
default:
ifc := field.Interface()
if ifc != nil {
if anonymous {
SetQueryValues(ifc, values)
} else {
prefixName := fieldName + "."
setQueryValues(ifc, values, prefixName)
}
continue
}
}
}
if value != "" {
name := argName
if argName == "" {
name = fieldName
}
if prefix != "" {
name = prefix + name
}
values.Set(name, value)
}
}
}
func setQueryValuesByFlattenMethod(i interface{}, values *url.Values, prefix string) {
// add to support url.Values
mapValues, ok := i.(url.Values)
if ok {
for k, _ := range mapValues {
values.Set(k, mapValues.Get(k))
}
return
}
elem := reflect.ValueOf(i)
if elem.Kind() == reflect.Ptr {
elem = elem.Elem()
}
elemType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
fieldName := elemType.Field(i).Name
anonymous := elemType.Field(i).Anonymous
field := elem.Field(i)
// TODO Use Tag for validation
// tag := typ.Field(i).Tag.Get("tagname")
kind := field.Kind()
isPtr := false
if (kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan) && field.IsNil() {
continue
}
if kind == reflect.Ptr {
field = field.Elem()
kind = field.Kind()
isPtr = true
}
var value string
//switch field.Interface().(type) {
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i := field.Int()
if i != 0 || isPtr {
value = strconv.FormatInt(i, 10)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
i := field.Uint()
if i != 0 || isPtr {
value = strconv.FormatUint(i, 10)
}
case reflect.Float32:
value = strconv.FormatFloat(field.Float(), 'f', 4, 32)
case reflect.Float64:
value = strconv.FormatFloat(field.Float(), 'f', 4, 64)
case reflect.Bool:
value = strconv.FormatBool(field.Bool())
case reflect.String:
value = field.String()
case reflect.Map:
ifc := field.Interface()
m := ifc.(map[string]string)
if m != nil {
j := 0
for k, v := range m {
j++
keyName := fmt.Sprintf("%s.%d.Key", fieldName, j)
values.Set(keyName, k)
valueName := fmt.Sprintf("%s.%d.Value", fieldName, j)
values.Set(valueName, v)
}
}
case reflect.Slice:
if field.Type().Name() == "FlattenArray" {
FlattenFn(fieldName, field, values)
} else {
switch field.Type().Elem().Kind() {
case reflect.Uint8:
value = string(field.Bytes())
case reflect.String:
l := field.Len()
if l > 0 {
strArray := make([]string, l)
for i := 0; i < l; i++ {
strArray[i] = field.Index(i).String()
}
bytes, err := json.Marshal(strArray)
if err == nil {
value = string(bytes)
} else {
log.Printf("Failed to convert JSON: %v", err)
}
}
default:
l := field.Len()
for j := 0; j < l; j++ {
prefixName := fmt.Sprintf("%s.%d.", fieldName, (j + 1))
ifc := field.Index(j).Interface()
//log.Printf("%s : %v", prefixName, ifc)
if ifc != nil {
setQueryValuesByFlattenMethod(ifc, values, prefixName)
}
}
continue
}
}
default:
switch field.Interface().(type) {
case ISO6801Time:
t := field.Interface().(ISO6801Time)
value = t.String()
case time.Time:
t := field.Interface().(time.Time)
value = GetISO8601TimeStamp(t)
default:
ifc := field.Interface()
if ifc != nil {
if anonymous {
SetQueryValues(ifc, values)
} else {
prefixName := fieldName + "."
setQueryValuesByFlattenMethod(ifc, values, prefixName)
}
continue
}
}
}
if value != "" {
name := elemType.Field(i).Tag.Get("ArgName")
if name == "" {
name = fieldName
}
if prefix != "" {
name = prefix + name
}
// NOTE: here we will change name to underline style when the type is UnderlineString
if field.Type().Name() == "UnderlineString" {
name = Underline2Dot(name)
}
values.Set(name, value)
}
}
}