diff --git a/Protobuild.toml b/Protobuild.toml index a578f18..0d98363 100644 --- a/Protobuild.toml +++ b/Protobuild.toml @@ -1,6 +1,6 @@ version = "unstable" generator = "gogomgrpc" -plugins = [] +plugins = ["mgrpc"] # Control protoc include paths. Below are usually some good defaults, but feel # free to try it without them if it works for your project. @@ -24,6 +24,7 @@ plugins = [] [packages] "gogoproto/gogo.proto" = "github.com/gogo/protobuf/gogoproto" "google/protobuf/any.proto" = "github.com/gogo/protobuf/types" + "google/protobuf/empty.proto" = "github.com/gogo/protobuf/types" "google/protobuf/descriptor.proto" = "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" "google/protobuf/field_mask.proto" = "github.com/gogo/protobuf/types" "google/protobuf/timestamp.proto" = "github.com/gogo/protobuf/types" diff --git a/example/example.pb.go b/example/example.pb.go index fce398f..d6862d9 100644 --- a/example/example.pb.go +++ b/example/example.pb.go @@ -18,10 +18,13 @@ import proto "github.com/gogo/protobuf/proto" import fmt "fmt" import math "math" import _ "github.com/gogo/protobuf/types" -import _ "github.com/golang/protobuf/ptypes/empty" +import google_protobuf1 "github.com/gogo/protobuf/types" import _ "github.com/gogo/protobuf/gogoproto" import _ "github.com/gogo/protobuf/types" +import context "context" +import github_com_stevvooe_mgrpc "github.com/stevvooe/mgrpc" + import strings "strings" import reflect "reflect" @@ -180,6 +183,42 @@ func encodeVarintExample(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return offset + 1 } + +type ExampleService interface { + Method1(ctx context.Context, req *Method1Request) (*Method1Response, error) + Method2(ctx context.Context, req *Method1Request) (*google_protobuf1.Empty, error) +} + +func RegisterExampleService(srv *github_com_stevvooe_mgrpc.Server, svc ExampleService) error { + return srv.Register("mgrpc.example.v1.Example", map[string]github_com_stevvooe_mgrpc.Handler{ + "Method1": github_com_stevvooe_mgrpc.HandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) { + return svc.Method1(ctx, req.(*Method1Request)) + }), + "Method2": github_com_stevvooe_mgrpc.HandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) { + return svc.Method2(ctx, req.(*Method1Request)) + }), + }) +} + +type ExampleClient struct { + client *github_com_stevvooe_mgrpc.Client +} + +func (c *ExampleClient) Method1(ctx context.Context, req *Method1Request) (*Method1Response, error) { + resp, err := c.client.Call(ctx, "mgrpc.example.v1.Example", "Method1", req) + if err != nil { + return nil, err + } + return resp.(*Method1Response), nil +} + +func (c *ExampleClient) Method2(ctx context.Context, req *Method1Request) (*google_protobuf1.Empty, error) { + resp, err := c.client.Call(ctx, "mgrpc.example.v1.Example", "Method2", req) + if err != nil { + return nil, err + } + return resp.(*google_protobuf1.Empty), nil +} func (m *Method1Request) Size() (n int) { var l int _ = l diff --git a/generator.go b/generator.go new file mode 100644 index 0000000..37f657b --- /dev/null +++ b/generator.go @@ -0,0 +1,111 @@ +package mgrpc + +import ( + "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" + "github.com/gogo/protobuf/protoc-gen-gogo/generator" +) + +type mgrpcGenerator struct { + *generator.Generator + generator.PluginImports + + typeurlPkg generator.Single + mgrpcPkg generator.Single + contextPkg generator.Single +} + +func init() { + generator.RegisterPlugin(new(mgrpcGenerator)) +} + +func (p *mgrpcGenerator) Name() string { + return "mgrpc" +} + +func (p *mgrpcGenerator) Init(g *generator.Generator) { + p.Generator = g +} + +func (p *mgrpcGenerator) Generate(file *generator.FileDescriptor) { + p.PluginImports = generator.NewPluginImports(p.Generator) + p.contextPkg = p.NewImport("context") + p.typeurlPkg = p.NewImport("github.com/containerd/typeurl") + p.mgrpcPkg = p.NewImport("github.com/stevvooe/mgrpc") + + for _, service := range file.GetService() { + serviceName := service.GetName() + if pkg := file.GetPackage(); pkg != "" { + serviceName = pkg + "." + serviceName + } + + p.genService(serviceName, service) + } +} + +func (p *mgrpcGenerator) genService(fullName string, service *descriptor.ServiceDescriptorProto) { + serviceName := service.GetName() + "Service" + p.P() + p.P("type ", serviceName, " interface{") + p.In() + for _, method := range service.Method { + p.P(method.GetName(), + "(ctx ", p.contextPkg.Use(), ".Context, ", + "req *", p.typeName(method.GetInputType()), ") ", + "(*", p.typeName(method.GetOutputType()), ", error)") + + } + p.Out() + p.P("}") + + p.P() + // registration method + p.P("func Register", serviceName, "(srv *", p.mgrpcPkg.Use(), ".Server, svc ", serviceName, ") error {") + p.In() + p.P(`return srv.Register("`, fullName, `", map[string]`, p.mgrpcPkg.Use(), ".Handler{") + p.In() + for _, method := range service.Method { + p.P(`"`, method.GetName(), `": `, p.mgrpcPkg.Use(), `.HandlerFunc(func(ctx context.Context, req interface{}) (interface{}, error) {`) + p.In() + p.P("return svc.", method.GetName(), "(ctx, req.(*", p.typeName(method.GetInputType()), "))") + p.Out() + p.P("}),") + } + p.Out() + p.P("})") + p.Out() + p.P("}") + + clientType := service.GetName() + "Client" + p.P() + p.P("type ", clientType, " struct{") + p.In() + p.P("client *", p.mgrpcPkg.Use(), ".Client") + p.Out() + p.P("}") + for _, method := range service.Method { + p.P() + p.P("func (c *", clientType, ") ", method.GetName(), + "(ctx ", p.contextPkg.Use(), ".Context, ", + "req *", p.typeName(method.GetInputType()), ") ", + "(*", p.typeName(method.GetOutputType()), ", error) {") + p.In() + p.P("resp, err := c.client.Call(ctx, ", `"`+fullName+`", `, `"`+method.GetName()+`"`, ", req)") + p.P("if err != nil {") + p.In() + p.P("return nil, err") + p.Out() + p.P("}") + p.P("return resp.(*", p.typeName(method.GetOutputType()), "), nil") + p.Out() + p.P("}") + } +} + +func (p *mgrpcGenerator) objectNamed(name string) generator.Object { + p.Generator.RecordTypeUse(name) + return p.Generator.ObjectNamed(name) +} + +func (p *mgrpcGenerator) typeName(str string) string { + return p.Generator.TypeName(p.objectNamed(str)) +}