Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"bm_generate.go",
"genbm.go",
"http_descriptor.go",
],
importpath = "go-common/app/tool/protoc-gen-bm/genbm",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/tool/protoc-gen-bm/generator:go_default_library",
"//app/tool/protoc-gen-bm/util:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/google.golang.org/genproto/googleapis/api/annotations:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//protoc-gen-go/descriptor:go_default_library",
"@com_github_golang_protobuf//protoc-gen-go/plugin:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,143 @@
package genbm
import (
"fmt"
"io"
"go-common/app/tool/protoc-gen-bm/util"
)
const (
bmPkgPath = "go-common/library/net/http/blademaster"
)
// BMGenerate generate bm server code
type BMGenerate struct {
target io.Writer
packageName string
descs []*BMServerDescriptor
err error
jsonpb bool
}
// NewBMGenerate BMGenerate
func NewBMGenerate(packageName string, descs []*BMServerDescriptor, jsonpb bool) *BMGenerate {
return &BMGenerate{
packageName: packageName,
descs: descs,
jsonpb: jsonpb,
}
}
// Generate code
func (b *BMGenerate) Generate(target io.Writer) error {
b.target = target
methodsCount := 0
for _, desc := range b.descs {
methodsCount += len(desc.Methods)
}
// if not methods found, can't generate anything
if methodsCount == 0 {
return nil
}
b.generatePackageImport()
for _, desc := range b.descs {
b.generateServer(desc)
}
return b.err
}
// P print code
func (b *BMGenerate) P(args ...interface{}) {
if b.err != nil {
return
}
args = append(args, "\n")
_, b.err = fmt.Fprint(b.target, args...)
}
func (b *BMGenerate) generatePackageImport() {
b.P("// Package ", b.packageName, " Code generated by go-common/app/tool/protoc-gen-bm. DO NOT EDIT.")
b.P("package ", b.packageName)
b.P()
b.P("import (")
b.P(" \"context\"")
if b.jsonpb {
b.P(" \"bytes\"")
b.P(" \"encoding/json\"")
b.P()
b.P(" \"go-common/app/tool/protoc-gen-bm/jsonpb\"")
}
b.P()
b.P(" bm \"", bmPkgPath, "\"")
b.P(")")
b.P()
}
func (b *BMGenerate) generateServer(desc *BMServerDescriptor) {
b.generateServerInterface(desc)
b.generateServerHandler(desc)
b.generateRegisterFunc(desc)
}
func (b *BMGenerate) generateServerInterface(desc *BMServerDescriptor) {
serviceName := util.CamelCase(desc.Name)
b.P(fmt.Sprintf("// BM%sServer interface as same as gGRPC server define", serviceName))
b.P("type BM", serviceName, "Server interface {")
for _, method := range desc.Methods {
b.P(" ", util.CamelCase(method.Name), fmt.Sprintf("(context.Context, *%s) (*%s, error)", method.RequestType, method.ReplyType))
}
b.P("}")
b.P()
}
func (b *BMGenerate) generateServerHandler(desc *BMServerDescriptor) {
serviceName := util.CamelCase(desc.Name)
receiverName := fmt.Sprintf("_BMServer%s", serviceName)
b.P("// _BMServer", serviceName, "server")
b.P("type ", receiverName, " struct {")
b.P(" BM", serviceName, "Server")
b.P("}")
b.P()
for _, method := range desc.Methods {
methodName := util.CamelCase(method.Name)
funcName := fmt.Sprintf("bm%s%sHandler", serviceName, methodName)
b.P(fmt.Sprintf("func (b *%s) ", receiverName), funcName, "(c *bm.Context) {")
// bind req
b.P(fmt.Sprintf(" req := new(%s)", method.RequestType))
b.P(fmt.Sprintf(" if err := c.Bind(req); err != nil {"))
b.P(" return")
b.P(" }")
// call service
b.P(fmt.Sprintf(" reply, err := b.%s(c.Context, req)", methodName))
if b.jsonpb {
b.P(" if err != nil {")
b.P(" c.JSON(nil, err)")
b.P(" return")
b.P(" }")
b.P(" body := &bytes.Buffer{}")
b.P(" marshaler := jsonpb.Marshaler{EmitDefaults: true, OrigName: true}")
b.P(" err = marshaler.Marshal(body, reply)")
b.P(" c.JSON(json.RawMessage(body.Bytes()), err)")
} else {
b.P(" c.JSON(reply, err)")
}
b.P("}")
b.P()
}
}
func (b *BMGenerate) generateRegisterFunc(desc *BMServerDescriptor) {
serviceName := util.CamelCase(desc.Name)
receiverName := fmt.Sprintf("_BMServer%s", serviceName)
b.P(fmt.Sprintf("// Register%sBMServer register bm server", serviceName))
b.P(fmt.Sprintf("func Register%sBMServer(e *bm.Engine, s BM%sServer) {", serviceName, serviceName))
b.P(fmt.Sprintf(" bs := &%s{s}", receiverName))
for _, method := range desc.Methods {
methodName := util.CamelCase(method.Name)
funcName := fmt.Sprintf("bm%s%sHandler", serviceName, methodName)
b.P(fmt.Sprintf(" e.%s(\"%s\", bs.%s)", method.Method, method.PathPattern, funcName))
}
b.P("}")
b.P()
}

View File

@@ -0,0 +1,131 @@
package genbm
import (
"bytes"
"go/format"
"os"
"path/filepath"
"strings"
"github.com/golang/glog"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
"go-common/app/tool/protoc-gen-bm/generator"
)
// New blademaster server code generator
func New(jsonpb bool) generator.Generator {
return &genbm{jsonpb: jsonpb}
}
type genbm struct {
jsonpb bool
}
func (g *genbm) Generate(req *plugin.CodeGeneratorRequest) ([]*plugin.CodeGeneratorResponse_File, error) {
var resp []*plugin.CodeGeneratorResponse_File
files := req.GetProtoFile()
for _, file := range files {
respFile, ok, err := g.generateFile(file)
if err != nil {
return resp, err
}
if ok {
resp = append(resp, respFile)
}
}
return resp, nil
}
func (g *genbm) generateFile(file *descriptor.FileDescriptorProto) (*plugin.CodeGeneratorResponse_File, bool, error) {
glog.V(1).Infof("process proto file %s", file.GetName())
services := file.GetService()
if len(services) == 0 {
glog.V(5).Infof("proto file %s not included service descriptor", file.GetName())
return nil, false, nil
}
var descs []*BMServerDescriptor
for _, service := range services {
server, err := ParseBMServer(service)
if err != nil {
return nil, false, err
}
descs = append(descs, server)
}
buf := new(bytes.Buffer)
goPackageName := GetGoPackageName(file)
gen := NewBMGenerate(goPackageName, descs, g.jsonpb)
if err := gen.Generate(buf); err != nil {
return nil, false, err
}
// format code
data, err := format.Source(buf.Bytes())
if err != nil {
return nil, false, err
}
content := string(data)
// no content
if len(content) == 0 {
return nil, false, nil
}
target := TargetFilePath(file)
glog.V(1).Infof("generate code to %s", target)
return &plugin.CodeGeneratorResponse_File{
Content: &content,
Name: &target,
}, true, nil
}
// TargetFilePath find target file path
func TargetFilePath(file *descriptor.FileDescriptorProto) string {
fpath := file.GetName()
protoDir := filepath.Dir(fpath)
noExt := filepath.Base(fpath)
for i := len(noExt) - 1; i >= 0 && !os.IsPathSeparator(noExt[i]); i-- {
if noExt[i] == '.' {
noExt = noExt[:i]
}
}
target := noExt + ".pb.bm.go"
options := file.GetOptions()
if options != nil {
goPackage := options.GetGoPackage()
if goPackage != "" {
goPackage = strings.Split(goPackage, ";")[0]
if strings.Contains(goPackage, "/") {
return filepath.Join(goPackage, target)
}
}
}
return filepath.Join(protoDir, target)
}
// GetGoPackageName last element from proto package name or go_package option
func GetGoPackageName(file *descriptor.FileDescriptorProto) string {
var goPackageName string
protoPackage := file.GetPackage()
goPackageName = splitLastElem(protoPackage, ".")
options := file.GetOptions()
if options == nil {
return goPackageName
}
if goPackage := options.GetGoPackage(); goPackage != "" {
if strings.Contains(goPackage, ";") {
goPackageName = splitLastElem(goPackage, ";")
} else {
goPackageName = splitLastElem(goPackage, "/")
}
}
return goPackageName
}
func splitLastElem(s string, seq string) string {
seqs := strings.Split(s, seq)
return seqs[len(seqs)-1]
}

View File

@@ -0,0 +1,107 @@
package genbm
import (
"fmt"
"net/http"
"github.com/golang/glog"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
"google.golang.org/genproto/googleapis/api/annotations"
)
// BMServerDescriptor descriptor for BM server
type BMServerDescriptor struct {
Name string
ProtoService *descriptor.ServiceDescriptorProto
Methods []*BMMethodDescriptor
}
// BMMethodDescriptor descriptor for BM http method
type BMMethodDescriptor struct {
Name string
Method string
PathPattern string
RequestType string
ReplyType string
ProtoMethod *descriptor.MethodDescriptorProto
HTTPRule *annotations.HttpRule
}
// ParseBMServer parse BMServerDescriptor form service descriptor proto
func ParseBMServer(service *descriptor.ServiceDescriptorProto) (*BMServerDescriptor, error) {
glog.V(1).Infof("parse bmserver from service %s", service.GetName())
serverDesc := &BMServerDescriptor{
Name: service.GetName(),
ProtoService: service,
}
for _, method := range service.GetMethod() {
if !HasHTTPRuleOptions(method) {
glog.V(5).Infof("method %s not include http rule, skipped", method.GetName())
continue
}
bmMethod, err := ParseBMMethod(method)
if err != nil {
return nil, err
}
serverDesc.Methods = append(serverDesc.Methods, bmMethod)
}
return serverDesc, nil
}
// ParseBMMethod parse BMMethodDescriptor form method descriptor proto
func ParseBMMethod(method *descriptor.MethodDescriptorProto) (*BMMethodDescriptor, error) {
glog.V(1).Infof("parse bmmethod from method %s", method.GetName())
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)
}
if len(rule.AdditionalBindings) != 0 {
glog.Warningf("unsupport additional binding, additional binding will be ignored")
}
// TODO: support use type from other package
requestType := splitLastElem(method.GetInputType(), ".")
replyType := splitLastElem(method.GetOutputType(), ".")
bmMethod := &BMMethodDescriptor{
Name: method.GetName(),
Method: httpMethod,
PathPattern: pathPattern,
RequestType: requestType,
ReplyType: replyType,
ProtoMethod: method,
HTTPRule: rule,
}
glog.V(5).Infof("bmMethod %s: %s %s, Request:%s Reply: %s", bmMethod.Name, bmMethod.Method, bmMethod.PathPattern, bmMethod.RequestType, bmMethod.ReplyType)
return bmMethod, nil
}
// HasHTTPRuleOptions check method has httprule extension
func HasHTTPRuleOptions(method *descriptor.MethodDescriptorProto) bool {
options := method.GetOptions()
if options == nil {
return false
}
return proto.HasExtension(options, annotations.E_Http)
}