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.
73 lines
1.8 KiB
73 lines
1.8 KiB
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"
|
|
)
|
|
|
|
// 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
|
|
}
|
|
reg := regexp.MustCompile(`/{[.\w]+}`)
|
|
if reg == nil {
|
|
return pathTemplate
|
|
}
|
|
pathParams := make(map[string]struct{})
|
|
path := reg.ReplaceAllStringFunc(pathTemplate, func(in string) string {
|
|
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 {
|
|
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))
|
|
}
|
|
|