package generator import ( "fmt" "net/http" "strings" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/genproto/googleapis/api/annotations" "github.com/go-kratos/kratos/tool/protobuf/pkg/tag" "github.com/go-kratos/kratos/tool/protobuf/pkg/typemap" ) // HTTPInfo http info for method type HTTPInfo struct { HttpMethod string Path string LegacyPath string NewPath string IsLegacyPath bool Title string Description string // is http path added in the google.api.http option ? HasExplicitHTTPPath bool } type googleMethodOptionInfo struct { Method string PathPattern string HTTPRule *annotations.HttpRule } // GetHTTPInfo http info of method func GetHTTPInfo( file *descriptor.FileDescriptorProto, service *descriptor.ServiceDescriptorProto, method *descriptor.MethodDescriptorProto, reg *typemap.Registry) *HTTPInfo { var ( title string desc string httpMethod string newPath string explicitHTTPPath bool ) comment, _ := reg.MethodComments(file, service, method) tags := tag.GetTagsInComment(comment.Leading) cleanComments := tag.GetCommentWithoutTag(comment.Leading) if len(cleanComments) > 0 { title = strings.Trim(cleanComments[0], "\n\r ") if len(cleanComments) > 1 { descLines := cleanComments[1:] desc = strings.Trim(strings.Join(descLines, "\n"), "\r\n ") } else { desc = "" } } else { title = "" } googleOptionInfo, err := ParseBMMethod(method) if err == nil { httpMethod = strings.ToUpper(googleOptionInfo.Method) p := googleOptionInfo.PathPattern if p != "" { explicitHTTPPath = true newPath = p goto END } } if httpMethod == "" { // resolve http method httpMethod = tag.GetTagValue("method", tags) if httpMethod == "" { httpMethod = "GET" } else { httpMethod = strings.ToUpper(httpMethod) } } newPath = "/" + file.GetPackage() + "." + service.GetName() + "/" + method.GetName() END: var p = newPath param := &HTTPInfo{HttpMethod: httpMethod, Path: p, NewPath: newPath, IsLegacyPath: false, Title: title, Description: desc, HasExplicitHTTPPath: explicitHTTPPath, } if title == "" { param.Title = param.Path } return param } func (t *Base) GetHttpInfoCached(file *descriptor.FileDescriptorProto, service *descriptor.ServiceDescriptorProto, method *descriptor.MethodDescriptorProto) *HTTPInfo { key := file.GetPackage() + service.GetName() + method.GetName() httpInfo, ok := t.httpInfoCache[key] if !ok { httpInfo = GetHTTPInfo(file, service, method, t.Reg) t.httpInfoCache[key] = httpInfo } return httpInfo } // ParseBMMethod parse BMMethodDescriptor form method descriptor proto func ParseBMMethod(method *descriptor.MethodDescriptorProto) (*googleMethodOptionInfo, error) { ext, err := proto.GetExtension(method.GetOptions(), annotations.E_Http) if err != nil { return nil, fmt.Errorf("get extension error: %s", err) } rule := ext.(*annotations.HttpRule) var httpMethod string var pathPattern string switch pattern := rule.Pattern.(type) { case *annotations.HttpRule_Get: pathPattern = pattern.Get httpMethod = http.MethodGet case *annotations.HttpRule_Put: pathPattern = pattern.Put httpMethod = http.MethodPut case *annotations.HttpRule_Post: pathPattern = pattern.Post httpMethod = http.MethodPost case *annotations.HttpRule_Patch: pathPattern = pattern.Patch httpMethod = http.MethodPatch case *annotations.HttpRule_Delete: pathPattern = pattern.Delete httpMethod = http.MethodDelete default: return nil, fmt.Errorf("unsupport http pattern %s", rule.Pattern) } bmMethod := &googleMethodOptionInfo{ Method: httpMethod, PathPattern: pathPattern, HTTPRule: rule, } return bmMethod, nil }