mirror of https://github.com/XTLS/Xray-core
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
3.6 KiB
176 lines
3.6 KiB
package reflect |
|
|
|
import ( |
|
"encoding/json" |
|
"reflect" |
|
|
|
cserial "github.com/xtls/xray-core/common/serial" |
|
) |
|
|
|
func MarshalToJson(v interface{}) (string, bool) { |
|
if itf := marshalInterface(v, true); itf != nil { |
|
if b, err := json.MarshalIndent(itf, "", " "); err == nil { |
|
return string(b[:]), true |
|
} |
|
} |
|
return "", false |
|
} |
|
|
|
func marshalTypedMessage(v *cserial.TypedMessage, ignoreNullValue bool) interface{} { |
|
if v == nil { |
|
return nil |
|
} |
|
tmsg, err := v.GetInstance() |
|
if err != nil { |
|
return nil |
|
} |
|
r := marshalInterface(tmsg, ignoreNullValue) |
|
if msg, ok := r.(map[string]interface{}); ok { |
|
msg["_TypedMessage_"] = v.Type |
|
} |
|
return r |
|
} |
|
|
|
func marshalSlice(v reflect.Value, ignoreNullValue bool) interface{} { |
|
r := make([]interface{}, 0) |
|
for i := 0; i < v.Len(); i++ { |
|
rv := v.Index(i) |
|
if rv.CanInterface() { |
|
value := rv.Interface() |
|
r = append(r, marshalInterface(value, ignoreNullValue)) |
|
} |
|
} |
|
return r |
|
} |
|
|
|
func marshalStruct(v reflect.Value, ignoreNullValue bool) interface{} { |
|
r := make(map[string]interface{}) |
|
t := v.Type() |
|
for i := 0; i < v.NumField(); i++ { |
|
rv := v.Field(i) |
|
if rv.CanInterface() { |
|
ft := t.Field(i) |
|
name := ft.Name |
|
value := rv.Interface() |
|
tv := marshalInterface(value, ignoreNullValue) |
|
if tv != nil || !ignoreNullValue { |
|
r[name] = tv |
|
} |
|
} |
|
} |
|
return r |
|
} |
|
|
|
func marshalMap(v reflect.Value, ignoreNullValue bool) interface{} { |
|
// policy.level is map[uint32] *struct |
|
kt := v.Type().Key() |
|
vt := reflect.TypeOf((*interface{})(nil)) |
|
mt := reflect.MapOf(kt, vt) |
|
r := reflect.MakeMap(mt) |
|
for _, key := range v.MapKeys() { |
|
rv := v.MapIndex(key) |
|
if rv.CanInterface() { |
|
iv := rv.Interface() |
|
tv := marshalInterface(iv, ignoreNullValue) |
|
if tv != nil || !ignoreNullValue { |
|
r.SetMapIndex(key, reflect.ValueOf(&tv)) |
|
} |
|
} |
|
} |
|
return r.Interface() |
|
} |
|
|
|
func marshalIString(v interface{}) (r string, ok bool) { |
|
defer func() { |
|
if err := recover(); err != nil { |
|
r = "" |
|
ok = false |
|
} |
|
}() |
|
|
|
if iStringFn, ok := v.(interface{ String() string }); ok { |
|
return iStringFn.String(), true |
|
} |
|
return "", false |
|
} |
|
|
|
func marshalKnownType(v interface{}, ignoreNullValue bool) (interface{}, bool) { |
|
switch ty := v.(type) { |
|
case cserial.TypedMessage: |
|
return marshalTypedMessage(&ty, ignoreNullValue), true |
|
case *cserial.TypedMessage: |
|
return marshalTypedMessage(ty, ignoreNullValue), true |
|
case map[string]json.RawMessage: |
|
return ty, true |
|
case []json.RawMessage: |
|
return ty, true |
|
case *json.RawMessage: |
|
return ty, true |
|
case json.RawMessage: |
|
return ty, true |
|
default: |
|
return nil, false |
|
} |
|
} |
|
|
|
func isValueKind(kind reflect.Kind) bool { |
|
switch kind { |
|
case reflect.Bool, |
|
reflect.Int, |
|
reflect.Int8, |
|
reflect.Int16, |
|
reflect.Int32, |
|
reflect.Int64, |
|
reflect.Uint, |
|
reflect.Uint8, |
|
reflect.Uint16, |
|
reflect.Uint32, |
|
reflect.Uint64, |
|
reflect.Uintptr, |
|
reflect.Float32, |
|
reflect.Float64, |
|
reflect.Complex64, |
|
reflect.Complex128, |
|
reflect.String: |
|
return true |
|
default: |
|
return false |
|
} |
|
} |
|
|
|
func marshalInterface(v interface{}, ignoreNullValue bool) interface{} { |
|
|
|
if r, ok := marshalKnownType(v, ignoreNullValue); ok { |
|
return r |
|
} |
|
|
|
rv := reflect.ValueOf(v) |
|
if rv.Kind() == reflect.Ptr { |
|
rv = rv.Elem() |
|
} |
|
k := rv.Kind() |
|
if k == reflect.Invalid { |
|
return nil |
|
} |
|
if isValueKind(k) { |
|
return v |
|
} |
|
|
|
switch k { |
|
case reflect.Struct: |
|
return marshalStruct(rv, ignoreNullValue) |
|
case reflect.Slice: |
|
return marshalSlice(rv, ignoreNullValue) |
|
case reflect.Array: |
|
return marshalSlice(rv, ignoreNullValue) |
|
case reflect.Map: |
|
return marshalMap(rv, ignoreNullValue) |
|
default: |
|
break |
|
} |
|
|
|
if str, ok := marshalIString(v); ok { |
|
return str |
|
} |
|
return nil |
|
}
|
|
|