From 6eabacc9bc8e71d09834cce051ec9115ba36b1e1 Mon Sep 17 00:00:00 2001 From: Kazuyoshi Kato Date: Fri, 20 Aug 2021 15:50:53 -0700 Subject: [PATCH] Add protoc-gen-go-ttrpc Google's new protobuf code generator only supports protobuf serialization/deserialization and let other code generators handle RPC-related aspects. This new code generator follows the change and can be used with the new protobuf code generator. Signed-off-by: Kazuyoshi Kato --- cmd/protoc-gen-go-ttrpc/generator.go | 125 +++++++++++++++++++++++++++ cmd/protoc-gen-go-ttrpc/main.go | 35 ++++++++ go.mod | 1 + go.sum | 9 +- 4 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 cmd/protoc-gen-go-ttrpc/generator.go create mode 100644 cmd/protoc-gen-go-ttrpc/main.go diff --git a/cmd/protoc-gen-go-ttrpc/generator.go b/cmd/protoc-gen-go-ttrpc/generator.go new file mode 100644 index 000000000..0886beb6e --- /dev/null +++ b/cmd/protoc-gen-go-ttrpc/generator.go @@ -0,0 +1,125 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "strings" + + "google.golang.org/protobuf/compiler/protogen" +) + +// generator is a Go code generator that uses ttrpc.Server and ttrpc.Client. +// Unlike the original gogo version, this doesn't generate serializers for message types and +// let protoc-gen-go handle them. +type generator struct { + out *protogen.GeneratedFile + + ident struct { + context string + server string + client string + method string + } +} + +func newGenerator(out *protogen.GeneratedFile) *generator { + gen := generator{out: out} + gen.ident.context = out.QualifiedGoIdent(protogen.GoIdent{ + GoImportPath: "context", + GoName: "Context", + }) + gen.ident.server = out.QualifiedGoIdent(protogen.GoIdent{ + GoImportPath: "github.com/containerd/ttrpc", + GoName: "Server", + }) + gen.ident.client = out.QualifiedGoIdent(protogen.GoIdent{ + GoImportPath: "github.com/containerd/ttrpc", + GoName: "Client", + }) + gen.ident.method = out.QualifiedGoIdent(protogen.GoIdent{ + GoImportPath: "github.com/containerd/ttrpc", + GoName: "Method", + }) + return &gen +} + +func generate(plugin *protogen.Plugin, input *protogen.File) error { + file := plugin.NewGeneratedFile(input.GeneratedFilenamePrefix+"_ttrpc.pb.go", input.GoImportPath) + file.P("// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT.") + file.P("// source: ", input.Desc.Path()) + file.P("package ", input.GoPackageName) + + gen := newGenerator(file) + for _, service := range input.Services { + gen.genService(service) + } + return nil +} + +func (gen *generator) genService(service *protogen.Service) { + fullName := service.Desc.FullName() + p := gen.out + + serviceName := service.GoName + "Service" + p.P("type ", serviceName, " interface{") + for _, method := range service.Methods { + p.P(method.GoName, + "(ctx ", gen.ident.context, ",", + "req *", method.Input.GoIdent, ")", + "(*", method.Output.GoIdent, ", error)") + } + p.P("}") + + // registration method + p.P("func Register", serviceName, "(srv *", gen.ident.server, ", svc ", serviceName, "){") + p.P(`srv.Register("`, fullName, `", map[string]`, gen.ident.method, "{") + for _, method := range service.Methods { + p.P(`"`, method.GoName, `": func(ctx `, gen.ident.context, ", unmarshal func(interface{}) error)(interface{}, error){") + p.P("var req ", method.Input.GoIdent) + p.P("if err := unmarshal(&req); err != nil {") + p.P("return nil, err") + p.P("}") + p.P("return svc.", method.GoName, "(ctx, &req)") + p.P("},") + } + p.P("})") + p.P("}") + + clientType := service.GoName + "Client" + clientStructType := strings.ToLower(clientType[:1]) + clientType[1:] + p.P("type ", clientStructType, " struct{") + p.P("client *", gen.ident.client) + p.P("}") + p.P("func New", clientType, "(client *", gen.ident.client, ")", serviceName, "{") + p.P("return &", clientStructType, "{") + p.P("client:client,") + p.P("}") + p.P("}") + + for _, method := range service.Methods { + p.P("func (c *", clientStructType, ")", method.GoName, "(", + "ctx ", gen.ident.context, ",", + "req *", method.Input.GoIdent, ")", + "(*", method.Output.GoIdent, ", error){") + p.P("var resp ", method.Output.GoIdent) + p.P(`if err := c.client.Call(ctx, "`, fullName, `", "`, method.Desc.Name(), `", req, &resp); err != nil {`) + p.P("return nil, err") + p.P("}") + p.P("return &resp, nil") + p.P("}") + } +} diff --git a/cmd/protoc-gen-go-ttrpc/main.go b/cmd/protoc-gen-go-ttrpc/main.go new file mode 100644 index 000000000..faa2005d2 --- /dev/null +++ b/cmd/protoc-gen-go-ttrpc/main.go @@ -0,0 +1,35 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "google.golang.org/protobuf/compiler/protogen" +) + +func main() { + protogen.Options{}.Run(func(gen *protogen.Plugin) error { + for _, f := range gen.Files { + if !f.Generate { + continue + } + if err := generate(gen, f); err != nil { + return err + } + } + return nil + }) +} diff --git a/go.mod b/go.mod index 6fbeb5bc9..efc00860c 100644 --- a/go.mod +++ b/go.mod @@ -9,4 +9,5 @@ require ( golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 google.golang.org/grpc v1.27.1 + google.golang.org/protobuf v1.27.1 ) diff --git a/go.sum b/go.sum index 7f808eee3..cb91432e3 100644 --- a/go.sum +++ b/go.sum @@ -13,11 +13,13 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -90,5 +92,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=