mirror of
https://github.com/go-kratos/kratos.git
synced 2025-11-06 08:59:18 +02:00
* test(transport): add unit test for transport coverage: 91.7% of statements * lint & fix data race * fix test * fix lint * fix lint * remove http func wrapper * remove error log when watcher context is canceled * optimize code style
76 lines
2.0 KiB
Go
76 lines
2.0 KiB
Go
package binding
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/go-kratos/kratos/v2/encoding/form"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
)
|
|
|
|
var reg = regexp.MustCompile(`/{[\\.\w]+}`)
|
|
|
|
// EncodeURL encode proto message to url path.
|
|
func EncodeURL(pathTemplate string, msg proto.Message, needQuery bool) string {
|
|
if msg == nil || (reflect.ValueOf(msg).Kind() == reflect.Ptr && reflect.ValueOf(msg).IsNil()) {
|
|
return pathTemplate
|
|
}
|
|
pathParams := make(map[string]struct{})
|
|
path := reg.ReplaceAllStringFunc(pathTemplate, func(in string) string {
|
|
// it's unreachable because the reg means that must have more than one char in {}
|
|
//if len(in) < 4 { //nolint:gomnd // ** explain the 4 number here :-) **
|
|
// return in
|
|
//}
|
|
key := in[2 : len(in)-1]
|
|
vars := strings.Split(key, ".")
|
|
value, err := getValueByField(msg.ProtoReflect(), vars)
|
|
if err != nil {
|
|
return in
|
|
}
|
|
pathParams[key] = struct{}{}
|
|
return "/" + value
|
|
})
|
|
if !needQuery {
|
|
if query := form.EncodeFieldMask(msg.ProtoReflect()); query != "" {
|
|
return path + "?" + query
|
|
}
|
|
return path
|
|
}
|
|
u, err := form.EncodeValues(msg)
|
|
if err == nil && len(u) > 0 {
|
|
for key := range pathParams {
|
|
delete(u, key)
|
|
}
|
|
query := u.Encode()
|
|
if query != "" {
|
|
path += "?" + query
|
|
}
|
|
}
|
|
return path
|
|
}
|
|
|
|
func getValueByField(v protoreflect.Message, fieldPath []string) (string, error) {
|
|
var fd protoreflect.FieldDescriptor
|
|
for i, fieldName := range fieldPath {
|
|
fields := v.Descriptor().Fields()
|
|
if fd = fields.ByJSONName(fieldName); fd == nil {
|
|
fd = fields.ByName(protoreflect.Name(fieldName))
|
|
if fd == nil {
|
|
return "", fmt.Errorf("field path not found: %q", fieldName)
|
|
}
|
|
}
|
|
if i == len(fieldPath)-1 {
|
|
break
|
|
}
|
|
if fd.Message() == nil || fd.Cardinality() == protoreflect.Repeated {
|
|
return "", fmt.Errorf("invalid path: %q is not a message", fieldName)
|
|
}
|
|
v = v.Get(fd).Message()
|
|
}
|
|
return form.EncodeField(fd, v.Get(fd))
|
|
}
|