Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add in-file transport protocol specification for protoc-gen-go-dubbo #3

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ protoc -I ./ \
The `--go-dubbo_out` option specifies the output directory for the generated code,
and `--go-dubbo_opt=paths=source_relative` sets the output path to be relative to the source file.

You can also use the flags `in_file_method_protocol_spec=true` or `in_file_method_protocol_spec=true` to enable in-file transport protocol specification, then protoc-gen-go-dubbo will only generate the service/method with the option "DUBBO". For example:

```shell
protoc -I ./ \
--go-hessian2_out=./ --go-hessian2_opt=paths=source_relative \
--go-dubbo_out=./ --go-dubbo_opt=paths=source_relative,in_file_method_protocol_spec=true \
./greet.proto
```

## Example
To generate Dubbo code, you can create a `.proto` file with the following content:
```protobuf
Expand Down Expand Up @@ -63,6 +72,50 @@ service GreetService {
}
}
```

Extra options with transport protocol specification look like the follows:

```proto
//method protocol spec
service GreetingsService {
rpc Greet(GreetRequest) returns (GreetResponse) {
option (unified_idl_extend.method_protocols) = {
protocol_names: ["DUBBO"];
};
option (unified_idl_extend.method_extend) = {
method_name: "greet";
};
}
rpc Greet2(GreetRequest) returns (GreetResponse) {
option (unified_idl_extend.method_protocols) = {
protocol_names: ["TRIPLE","DUBBO"];
};
option (unified_idl_extend.method_extend) = {
method_name: "greet2";
};
}
}
```

```proto
service GreetingsService {
//service protocol spec
option (unified_idl_extend.service_protocol) = {
protocol_name: "DUBBO";
};
rpc Greet(GreetRequest) returns (GreetResponse) {
option (unified_idl_extend.method_extend) = {
method_name: "greet";
};
}
rpc Greet2(GreetRequest) returns (GreetResponse) {
option (unified_idl_extend.method_extend) = {
method_name: "greet2";
};
}
}
```

Note that you need to import the `unified_idl_extend` package to use the `method_extend` options to extend the service.
And Dubbo protocol must be used with Hessian2 serialization, so you need to use the `message_extend` options to extend
the message.
Expand Down
49 changes: 39 additions & 10 deletions generator/gen_dubbo.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,14 @@ package generator

import (
"fmt"
)

import (
"github.com/dubbogo/protoc-gen-go-dubbo/proto/unified_idl_extend"
"github.com/dubbogo/protoc-gen-go-dubbo/util"
"github.com/pkg/errors"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
)

import (
"github.com/dubbogo/protoc-gen-go-dubbo/proto/unified_idl_extend"
"github.com/dubbogo/protoc-gen-go-dubbo/util"
)

var (
ErrStreamMethod = errors.New("dubbo doesn't support stream method")
ErrMoreExtendArgsRespFieldNum = errors.New("extend args for response message should only has 1 field")
Expand Down Expand Up @@ -66,7 +61,7 @@ type Method struct {
ReturnType string
}

func ProcessProtoFile(g *protogen.GeneratedFile, file *protogen.File) (*Dubbogo, error) {
func ProcessProtoFile(g *protogen.GeneratedFile, file *protogen.File, methodProtocolSpecFlag, serviceProtocolSpecFlag bool) (*Dubbogo, error) {
desc := file.Proto
dubboGo := &Dubbogo{
File: file,
Expand All @@ -76,7 +71,15 @@ func ProcessProtoFile(g *protogen.GeneratedFile, file *protogen.File) (*Dubbogo,
}

for _, service := range file.Services {
serviceProtocolOpt, ok := proto.GetExtension(service.Desc.Options(), unified_idl_extend.E_ServiceProtocol).(*unified_idl_extend.ServiceProtocolTypeOption)
if serviceProtocolSpecFlag && ok {
if serviceProtocolOpt.GetProtocolName() != unified_idl_extend.ProtocolType_DUBBO.String() || serviceProtocolOpt == nil {
// skip the service which is not dubbo protocol or does not have a service option
continue
}
}
serviceMethods := make([]*Method, 0)
skipMethodFlag := false
for _, method := range service.Methods {
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
return nil, ErrStreamMethod
Expand All @@ -87,7 +90,25 @@ func ProcessProtoFile(g *protogen.GeneratedFile, file *protogen.File) (*Dubbogo,
ReturnType: g.QualifiedGoIdent(method.Output.GoIdent),
}

methodProtocolOpt, ok := proto.GetExtension(method.Desc.Options(), unified_idl_extend.E_MethodProtocols).(*unified_idl_extend.MethodProtocolTypeOption)
if methodProtocolSpecFlag && ok {
flagDubboProtocol := false
for _, protoName := range methodProtocolOpt.GetProtocolNames() {
if protoName == unified_idl_extend.ProtocolType_DUBBO.String() {
flagDubboProtocol = true
break
}
}
if !flagDubboProtocol || methodProtocolOpt == nil {
// skip the method which is not dubbo protocol or does not have a method option
skipMethodFlag = true
continue
}
}
skipMethodFlag = false

methodOpt, ok := proto.GetExtension(method.Desc.Options(), unified_idl_extend.E_MethodExtend).(*unified_idl_extend.Hessian2MethodOptions)

invokeName := util.ToLower(method.GoName)
if ok && methodOpt != nil {
invokeName = methodOpt.MethodName
Expand Down Expand Up @@ -116,8 +137,12 @@ func ProcessProtoFile(g *protogen.GeneratedFile, file *protogen.File) (*Dubbogo,
goType, _ := util.FieldGoType(g, method.Output.Fields[0])
m.ReturnType = goType
}

serviceMethods = append(serviceMethods, m)
if !skipMethodFlag {
serviceMethods = append(serviceMethods, m)
}
}
if len(serviceMethods) == 0 {
continue
}

serviceOpt, ok := proto.GetExtension(service.Desc.Options(), unified_idl_extend.E_ServiceExtend).(*unified_idl_extend.Hessian2ServiceOptions)
Expand All @@ -132,5 +157,9 @@ func ProcessProtoFile(g *protogen.GeneratedFile, file *protogen.File) (*Dubbogo,
})
}

if len(dubboGo.Services) == 0 {
return nil, fmt.Errorf("no service found in %s", dubboGo.Source)
}

return dubboGo, nil
}
26 changes: 16 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@
package main

import (
"flag"
"fmt"
"os"
)

import (
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/types/pluginpb"
)

import (
"github.com/dubbogo/protoc-gen-go-dubbo/generator"
"github.com/dubbogo/protoc-gen-go-dubbo/internal/version"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/types/pluginpb"
)

const (
usage = "Flags:\n -h, --help\tPrint this help and exit.\n --version\tPrint the version and exit."
)

func main() {

var flags flag.FlagSet
methodProtocolSpecFlag := flags.Bool("in_file_method_protocol_spec", false, "enable the in-file method transport protocol option")
serviceProtocolSpecFlag := flags.Bool("in_file_service_protocol_spec", false, "enable the in-file service transport protocol option")
if len(os.Args) == 2 && os.Args[1] == "--version" {
fmt.Fprintln(os.Stdout, version.Version)
os.Exit(0)
Expand All @@ -50,14 +50,20 @@ func main() {
os.Exit(1)
}

protogen.Options{}.Run(func(gen *protogen.Plugin) error {
flags.Init("protoc-gen-go-dubbo", flag.ContinueOnError)

protogen.Options{
ParamFunc: flags.Set,
}.Run(func(gen *protogen.Plugin) error {
gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
for _, file := range gen.Files {
if file.Generate {
filename := file.GeneratedFilenamePrefix + ".dubbo.go"
g := gen.NewGeneratedFile(filename, file.GoImportPath)

dubboGo, err := generator.ProcessProtoFile(g, file)
if *methodProtocolSpecFlag && *serviceProtocolSpecFlag {
return fmt.Errorf("in_file_method_protocol_spec and in_file_service_protocol_spec can't be true at the same time")
}
dubboGo, err := generator.ProcessProtoFile(g, file, *methodProtocolSpecFlag, *serviceProtocolSpecFlag)
if err != nil {
return err
}
Expand Down
Loading