exttract protoc plugin to dedicated repo

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2020-11-13 14:59:14 +03:00
parent 4233a4b673
commit 75222e07cb
7 changed files with 0 additions and 3762 deletions

View File

@ -1,33 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
_build
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
# ignore go build and test outputs
coverage.txt
coverage.out
# ignore locally built binaries
protoc-gen-micro
dist

View File

@ -1,138 +0,0 @@
# protoc-gen-micro
This is protobuf code generation for micro. We use protoc-gen-micro to reduce boilerplate code.
## Install
```
go get github.com/micro/micro/v3/cmd/protoc-gen-micro@master
```
Also required:
- [protoc](https://github.com/google/protobuf)
- [protoc-gen-go](https://github.com/golang/protobuf)
## Usage
Define your service as `greeter.proto`
```
syntax = "proto3";
service Greeter {
rpc Hello(Request) returns (Response) {}
}
message Request {
string name = 1;
}
message Response {
string msg = 1;
}
```
Generate the code
```
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
```
Your output result should be:
```
./
greeter.proto # original protobuf file
greeter.pb.go # auto-generated by protoc-gen-go
greeter.micro.go # auto-generated by protoc-gen-micro
```
The micro generated code includes clients and handlers which reduce boiler plate code
### Server
Register the handler with your micro server
```go
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.Request, rsp *proto.Response) error {
rsp.Msg = "Hello " + req.Name
return nil
}
proto.RegisterGreeterHandler(service.Server(), &Greeter{})
```
### Client
Create a service client with your micro client
```go
client := proto.NewGreeterService("greeter", service.Client())
```
### Errors
If you see an error about `protoc-gen-micro` not being found or executable, it's likely your environment may not be configured correctly. If you've already installed `protoc`, `protoc-gen-go`, and `protoc-gen-micro` ensure you've included `$GOPATH/bin` in your `PATH`.
Alternative specify the Go plugin paths as arguments to the `protoc` command
```
protoc --plugin=protoc-gen-go=$GOPATH/bin/protoc-gen-go --plugin=protoc-gen-micro=$GOPATH/bin/protoc-gen-micro --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
```
### Endpoint
Add a micro API endpoint which routes directly to an RPC method
Usage:
1. Clone `github.com/googleapis/googleapis` to use this feature as it requires http annotations.
2. The protoc command must include `-I$GOPATH/src/github.com/googleapis/googleapis` for the annotations import.
```diff
syntax = "proto3";
import "google/api/annotations.proto";
service Greeter {
rpc Hello(Request) returns (Response) {
option (google.api.http) = { post: "/hello"; body: "*"; };
}
}
message Request {
string name = 1;
}
message Response {
string msg = 1;
}
```
The proto generates a `RegisterGreeterHandler` function with a [api.Endpoint](https://godoc.org/github.com/micro/go-micro/api#Endpoint).
```diff
func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler, opts ...server.HandlerOption) error {
type greeter interface {
Hello(ctx context.Context, in *Request, out *Response) error
}
type Greeter struct {
greeter
}
h := &greeterHandler{hdlr}
opts = append(opts, api.WithEndpoint(&api.Endpoint{
Name: "Greeter.Hello",
Path: []string{"/hello"},
Method: []string{"POST"},
Handler: "rpc",
}))
return s.Handle(s.NewHandler(&Greeter{h}, opts...))
}
```
## LICENSE
protoc-gen-micro is a liberal reuse of protoc-gen-go hence we maintain the original license

View File

@ -1,40 +0,0 @@
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2010 The Go Authors. All rights reserved.
# https://github.com/golang/protobuf
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
include $(GOROOT)/src/Make.inc
TARG=github.com/golang/protobuf/compiler/generator
GOFILES=\
generator.go\
DEPS=../descriptor ../plugin ../../proto
include $(GOROOT)/src/Make.pkg

File diff suppressed because it is too large Load Diff

View File

@ -1,135 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2013 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package generator
import (
"testing"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
)
func TestCamelCase(t *testing.T) {
tests := []struct {
in, want string
}{
{"one", "One"},
{"one_two", "OneTwo"},
{"_my_field_name_2", "XMyFieldName_2"},
{"Something_Capped", "Something_Capped"},
{"my_Name", "My_Name"},
{"OneTwo", "OneTwo"},
{"_", "X"},
{"_a_", "XA_"},
}
for _, tc := range tests {
if got := CamelCase(tc.in); got != tc.want {
t.Errorf("CamelCase(%q) = %q, want %q", tc.in, got, tc.want)
}
}
}
func TestGoPackageOption(t *testing.T) {
tests := []struct {
in string
impPath GoImportPath
pkg GoPackageName
ok bool
}{
{"", "", "", false},
{"foo", "", "foo", true},
{"github.com/golang/bar", "github.com/golang/bar", "bar", true},
{"github.com/golang/bar;baz", "github.com/golang/bar", "baz", true},
{"github.com/golang/string", "github.com/golang/string", "string", true},
}
for _, tc := range tests {
d := &FileDescriptor{
FileDescriptorProto: &descriptor.FileDescriptorProto{
Options: &descriptor.FileOptions{
GoPackage: &tc.in,
},
},
}
impPath, pkg, ok := d.goPackageOption()
if impPath != tc.impPath || pkg != tc.pkg || ok != tc.ok {
t.Errorf("go_package = %q => (%q, %q, %t), want (%q, %q, %t)", tc.in,
impPath, pkg, ok, tc.impPath, tc.pkg, tc.ok)
}
}
}
func TestPackageNames(t *testing.T) {
g := New()
g.packageNames = make(map[GoImportPath]GoPackageName)
g.usedPackageNames = make(map[GoPackageName]bool)
for _, test := range []struct {
importPath GoImportPath
want GoPackageName
}{
{"github.com/golang/foo", "foo"},
{"github.com/golang/second/package/named/foo", "foo1"},
{"github.com/golang/third/package/named/foo", "foo2"},
{"github.com/golang/conflicts/with/predeclared/ident/string", "string1"},
} {
if got := g.GoPackageName(test.importPath); got != test.want {
t.Errorf("GoPackageName(%v) = %v, want %v", test.importPath, got, test.want)
}
}
}
func TestUnescape(t *testing.T) {
tests := []struct {
in string
out string
}{
// successful cases, including all kinds of escapes
{"", ""},
{"foo bar baz frob nitz", "foo bar baz frob nitz"},
{`\000\001\002\003\004\005\006\007`, string([]byte{0, 1, 2, 3, 4, 5, 6, 7})},
{`\a\b\f\n\r\t\v\\\?\'\"`, string([]byte{'\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '?', '\'', '"'})},
{`\x10\x20\x30\x40\x50\x60\x70\x80`, string([]byte{16, 32, 48, 64, 80, 96, 112, 128})},
// variable length octal escapes
{`\0\018\222\377\3\04\005\6\07`, string([]byte{0, 1, '8', 0222, 255, 3, 4, 5, 6, 7})},
// malformed escape sequences left as is
{"foo \\g bar", "foo \\g bar"},
{"foo \\xg0 bar", "foo \\xg0 bar"},
{"\\", "\\"},
{"\\x", "\\x"},
{"\\xf", "\\xf"},
{"\\777", "\\777"}, // overflows byte
}
for _, tc := range tests {
s := unescape(tc.in)
if s != tc.out {
t.Errorf("doUnescape(%q) = %q; should have been %q", tc.in, s, tc.out)
}
}
}

View File

@ -1,99 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2010 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// protoc-gen-micro is a plugin for the Google protocol buffer compiler to generate
// Go code. Run it by building this program and putting it in your path with
// the name
// protoc-gen-micro
// That word 'micro' at the end becomes part of the option string set for the
// protocol compiler, so once the protocol compiler (protoc) is installed
// you can run
// protoc --micro_out=output_directory --go_out=output_directory input_directory/file.proto
// to generate go-micro code for the protocol defined by file.proto.
// With that input, the output will be written to
// output_directory/file.micro.go
//
// The generated code is documented in the package comment for
// the library.
//
// See the README and documentation for protocol buffers to learn more:
// https://developers.google.com/protocol-buffers/
package main
import (
"io/ioutil"
"os"
"github.com/golang/protobuf/proto"
"github.com/unistack-org/micro/v3/cmd/protoc-gen-micro/generator"
_ "github.com/unistack-org/micro/v3/cmd/protoc-gen-micro/plugin/micro"
)
func main() {
// Begin by allocating a generator. The request and response structures are stored there
// so we can do error handling easily - the response structure contains the field to
// report failure.
g := generator.New()
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
g.Error(err, "reading input")
}
if err := proto.Unmarshal(data, g.Request); err != nil {
g.Error(err, "parsing input proto")
}
if len(g.Request.FileToGenerate) == 0 {
g.Fail("no files to generate")
}
g.CommandLineParameters(g.Request.GetParameter())
// Create a wrapped version of the Descriptors and EnumDescriptors that
// point to the file that defines them.
g.WrapTypes()
g.SetPackageNames()
g.BuildTypeNameMap()
g.GenerateAllFiles()
// Send back the results.
data, err = proto.Marshal(g.Response)
if err != nil {
g.Error(err, "failed to marshal output proto")
}
_, err = os.Stdout.Write(data)
if err != nil {
g.Error(err, "failed to write output proto")
}
}

View File

@ -1,583 +0,0 @@
package micro
import (
"fmt"
"path"
"strconv"
"strings"
"github.com/golang/protobuf/proto"
pb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/unistack-org/micro/v3/cmd/protoc-gen-micro/generator"
options "google.golang.org/genproto/googleapis/api/annotations"
)
// Paths for packages used by code generated in this file,
// relative to the import_prefix of the generator.Generator.
const (
apiPkgPath = "github.com/unistack-org/micro/v3/api"
contextPkgPath = "context"
clientPkgPath = "github.com/unistack-org/micro/v3/client"
serverPkgPath = "github.com/unistack-org/micro/v3/server"
)
func init() {
generator.RegisterPlugin(new(micro))
}
// micro is an implementation of the Go protocol buffer compiler's
// plugin architecture. It generates bindings for go-micro support.
type micro struct {
gen *generator.Generator
}
// Name returns the name of this plugin, "micro".
func (g *micro) Name() string {
return "micro"
}
// The names for packages imported in the generated code.
// They may vary from the final path component of the import path
// if the name is used by other packages.
var (
apiPkg string
contextPkg string
clientPkg string
serverPkg string
pkgImports map[generator.GoPackageName]bool
)
// Init initializes the plugin.
func (g *micro) Init(gen *generator.Generator) {
g.gen = gen
apiPkg = generator.RegisterUniquePackageName("api", nil)
contextPkg = generator.RegisterUniquePackageName("context", nil)
clientPkg = generator.RegisterUniquePackageName("client", nil)
serverPkg = generator.RegisterUniquePackageName("server", nil)
}
// Given a type name defined in a .proto, return its object.
// Also record that we're using it, to guarantee the associated import.
func (g *micro) objectNamed(name string) generator.Object {
g.gen.RecordTypeUse(name)
return g.gen.ObjectNamed(name)
}
// Given a type name defined in a .proto, return its name as we will print it.
func (g *micro) typeName(str string) string {
return g.gen.TypeName(g.objectNamed(str))
}
// P forwards to g.gen.P.
func (g *micro) P(args ...interface{}) { g.gen.P(args...) }
// Generate generates code for the services in the given file.
func (g *micro) Generate(file *generator.FileDescriptor) {
if len(file.FileDescriptorProto.Service) == 0 {
return
}
g.P("// Reference imports to suppress errors if they are not otherwise used.")
g.P("var _ ", apiPkg, ".Endpoint")
g.P("var _ ", contextPkg, ".Context")
g.P("var _ ", clientPkg, ".Option")
g.P("var _ ", serverPkg, ".Option")
g.P()
for i, service := range file.FileDescriptorProto.Service {
g.generateService(file, service, i)
}
}
// GenerateImports generates the import declaration for this file.
func (g *micro) GenerateImports(file *generator.FileDescriptor, imports map[generator.GoImportPath]generator.GoPackageName) {
if len(file.FileDescriptorProto.Service) == 0 {
return
}
g.P("import (")
g.P(apiPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, apiPkgPath)))
g.P(contextPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, contextPkgPath)))
g.P(clientPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, clientPkgPath)))
g.P(serverPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, serverPkgPath)))
g.P(")")
g.P()
// We need to keep track of imported packages to make sure we don't produce
// a name collision when generating types.
pkgImports = make(map[generator.GoPackageName]bool)
for _, name := range imports {
pkgImports[name] = true
}
}
// reservedClientName records whether a client name is reserved on the client side.
var reservedClientName = map[string]bool{
// TODO: do we need any in go-micro?
}
func unexport(s string) string {
if len(s) == 0 {
return ""
}
name := strings.ToLower(s[:1]) + s[1:]
if pkgImports[generator.GoPackageName(name)] {
return name + "_"
}
return name
}
// generateService generates all the code for the named service.
func (g *micro) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
path := fmt.Sprintf("6,%d", index) // 6 means service.
origServName := service.GetName()
serviceName := strings.ToLower(service.GetName())
if pkg := file.GetPackage(); pkg != "" {
serviceName = pkg
}
servName := generator.CamelCase(origServName)
servAlias := servName + "Service"
// strip suffix
if strings.HasSuffix(servAlias, "ServiceService") {
servAlias = strings.TrimSuffix(servAlias, "Service")
}
g.P()
g.P("// Api Endpoints for ", servName, " service")
g.P()
g.P("func New", servName, "Endpoints () []*", apiPkg, ".Endpoint {")
g.P("return []*", apiPkg, ".Endpoint{")
for _, method := range service.Method {
if method.Options != nil && proto.HasExtension(method.Options, options.E_Http) {
g.P("&", apiPkg, ".Endpoint{")
g.generateEndpoint(servName, method)
g.P("},")
}
}
g.P("}")
g.P("}")
g.P()
g.P()
g.P("// Client API for ", servName, " service")
g.P()
// Client interface.
g.P("type ", servAlias, " interface {")
for i, method := range service.Method {
g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
g.P(g.generateClientSignature(servName, method))
}
g.P("}")
g.P()
// Client structure.
g.P("type ", unexport(servAlias), " struct {")
g.P("c ", clientPkg, ".Client")
g.P("name string")
g.P("}")
g.P()
// NewClient factory.
g.P("func New", servAlias, " (name string, c ", clientPkg, ".Client) ", servAlias, " {")
/*
g.P("if c == nil {")
g.P("c = ", clientPkg, ".NewClient()")
g.P("}")
g.P("if len(name) == 0 {")
g.P(`name = "`, serviceName, `"`)
g.P("}")
*/
g.P("return &", unexport(servAlias), "{")
g.P("c: c,")
g.P("name: name,")
g.P("}")
g.P("}")
g.P()
var methodIndex, streamIndex int
serviceDescVar := "_" + servName + "_serviceDesc"
// Client method implementations.
for _, method := range service.Method {
var descExpr string
if !method.GetServerStreaming() {
// Unary RPC method
descExpr = fmt.Sprintf("&%s.Methods[%d]", serviceDescVar, methodIndex)
methodIndex++
} else {
// Streaming RPC method
descExpr = fmt.Sprintf("&%s.Streams[%d]", serviceDescVar, streamIndex)
streamIndex++
}
g.generateClientMethod(serviceName, servName, serviceDescVar, method, descExpr)
}
g.P("// Server API for ", servName, " service")
g.P()
// Server interface.
serverType := servName + "Handler"
g.P("type ", serverType, " interface {")
for i, method := range service.Method {
g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
g.P(g.generateServerSignature(servName, method))
}
g.P("}")
g.P()
// Server registration.
g.P("func Register", servName, "Handler(s ", serverPkg, ".Server, hdlr ", serverType, ", opts ...", serverPkg, ".HandlerOption) error {")
g.P("type ", unexport(servName), " interface {")
// generate interface methods
for _, method := range service.Method {
methName := generator.CamelCase(method.GetName())
inType := g.typeName(method.GetInputType())
outType := g.typeName(method.GetOutputType())
if !method.GetServerStreaming() && !method.GetClientStreaming() {
g.P(methName, "(ctx ", contextPkg, ".Context, req *", inType, ", rsp *", outType, ") error")
continue
}
g.P(methName, "(ctx ", contextPkg, ".Context, stream server.Stream) error")
}
g.P("}")
g.P("type ", servName, " struct {")
g.P(unexport(servName))
g.P("}")
g.P("h := &", unexport(servName), "Handler{hdlr}")
for _, method := range service.Method {
if method.Options != nil && proto.HasExtension(method.Options, options.E_Http) {
g.P("opts = append(opts, ", apiPkg, ".WithEndpoint(&", apiPkg, ".Endpoint{")
g.generateEndpoint(servName, method)
g.P("}))")
}
}
g.P("return s.Handle(s.NewHandler(&", servName, "{h}, opts...))")
g.P("}")
g.P()
g.P("type ", unexport(servName), "Handler struct {")
g.P(serverType)
g.P("}")
// Server handler implementations.
var handlerNames []string
for _, method := range service.Method {
hname := g.generateServerMethod(servName, method)
handlerNames = append(handlerNames, hname)
}
}
// generateEndpoint creates the api endpoint
func (g *micro) generateEndpoint(servName string, method *pb.MethodDescriptorProto) {
if method.Options == nil || !proto.HasExtension(method.Options, options.E_Http) {
return
}
// http rules
r, err := proto.GetExtension(method.Options, options.E_Http)
if err != nil {
return
}
rule := r.(*options.HttpRule)
var meth string
var path string
switch {
case len(rule.GetDelete()) > 0:
meth = "DELETE"
path = rule.GetDelete()
case len(rule.GetGet()) > 0:
meth = "GET"
path = rule.GetGet()
case len(rule.GetPatch()) > 0:
meth = "PATCH"
path = rule.GetPatch()
case len(rule.GetPost()) > 0:
meth = "POST"
path = rule.GetPost()
case len(rule.GetPut()) > 0:
meth = "PUT"
path = rule.GetPut()
}
if len(meth) == 0 || len(path) == 0 {
return
}
// TODO: process additional bindings
g.P("Name:", fmt.Sprintf(`"%s.%s",`, servName, method.GetName()))
g.P("Path:", fmt.Sprintf(`[]string{"%s"},`, path))
g.P("Method:", fmt.Sprintf(`[]string{"%s"},`, meth))
if len(rule.GetGet()) == 0 {
g.P("Body:", fmt.Sprintf(`"%s",`, rule.GetBody()))
}
if method.GetServerStreaming() || method.GetClientStreaming() {
g.P("Stream: true,")
}
g.P(`Handler: "rpc",`)
}
// generateClientSignature returns the client-side signature for a method.
func (g *micro) generateClientSignature(servName string, method *pb.MethodDescriptorProto) string {
origMethName := method.GetName()
methName := generator.CamelCase(origMethName)
if reservedClientName[methName] {
methName += "_"
}
reqArg := ", req *" + g.typeName(method.GetInputType())
if method.GetClientStreaming() {
reqArg = ""
}
respName := "*" + g.typeName(method.GetOutputType())
if method.GetServerStreaming() || method.GetClientStreaming() {
respName = servName + "_" + generator.CamelCase(origMethName) + "Service"
}
return fmt.Sprintf("%s(ctx %s.Context%s, opts ...%s.CallOption) (%s, error)", methName, contextPkg, reqArg, clientPkg, respName)
}
func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, method *pb.MethodDescriptorProto, descExpr string) {
methName := generator.CamelCase(method.GetName())
reqMethod := fmt.Sprintf("%s.%s", servName, methName)
inType := g.typeName(method.GetInputType())
outType := g.typeName(method.GetOutputType())
servAlias := servName + "Service"
// strip suffix
if strings.HasSuffix(servAlias, "ServiceService") {
servAlias = strings.TrimSuffix(servAlias, "Service")
}
g.P("func (c *", unexport(servAlias), ") ", g.generateClientSignature(servName, method), "{")
if !method.GetServerStreaming() && !method.GetClientStreaming() {
g.P("rsp := &", outType, "{}")
// TODO: Pass descExpr to Invoke.
g.P(`err := c.c.Call(ctx, c.c.NewRequest(c.name, "`, reqMethod, `", req), rsp, opts...)`)
g.P("if err != nil { return nil, err }")
g.P("return rsp, nil")
g.P("}")
g.P()
return
}
streamType := unexport(servAlias) + methName
g.P(`stream, err := c.c.Stream(ctx, c.c.NewRequest(c.name, "`, reqMethod, `", &`, inType, `{}), opts...)`)
g.P("if err != nil { return nil, err }")
if !method.GetClientStreaming() {
g.P("if err := stream.Send(req); err != nil { return nil, err }")
}
g.P("return &", streamType, "{stream}, nil")
g.P("}")
g.P()
genSend := method.GetClientStreaming()
genRecv := method.GetServerStreaming()
// Stream auxiliary types and methods.
g.P("type ", servName, "_", methName, "Service interface {")
g.P("Context() context.Context")
g.P("SendMsg(interface{}) error")
g.P("RecvMsg(interface{}) error")
if genSend && !genRecv {
// client streaming, the server will send a response upon close
g.P("CloseAndRecv() (*", outType, ", error)")
}
g.P("Close() error")
if genSend {
g.P("Send(*", inType, ") error")
}
if genRecv {
g.P("Recv() (*", outType, ", error)")
}
g.P("}")
g.P()
g.P("type ", streamType, " struct {")
g.P("stream ", clientPkg, ".Stream")
g.P("}")
g.P()
if genSend && !genRecv {
// client streaming, the server will send a response upon close
g.P("func (x *", streamType, ") CloseAndRecv() (*", outType, ", error) {")
g.P("if err := x.stream.Close(); err != nil {")
g.P("return nil, err")
g.P("}")
g.P("r := new(", outType, ")")
g.P("err := x.RecvMsg(r)")
g.P("return r, err")
g.P("}")
g.P()
}
g.P("func (x *", streamType, ") Close() error {")
g.P("return x.stream.Close()")
g.P("}")
g.P()
g.P("func (x *", streamType, ") Context() context.Context {")
g.P("return x.stream.Context()")
g.P("}")
g.P()
g.P("func (x *", streamType, ") SendMsg(m interface{}) error {")
g.P("return x.stream.Send(m)")
g.P("}")
g.P()
g.P("func (x *", streamType, ") RecvMsg(m interface{}) error {")
g.P("return x.stream.Recv(m)")
g.P("}")
g.P()
if genSend {
g.P("func (x *", streamType, ") Send(m *", inType, ") error {")
g.P("return x.stream.Send(m)")
g.P("}")
g.P()
}
if genRecv {
g.P("func (x *", streamType, ") Recv() (*", outType, ", error) {")
g.P("m := &", outType, "{}")
g.P("err := x.stream.Recv(m)")
g.P("if err != nil {")
g.P("return nil, err")
g.P("}")
g.P("return m, nil")
g.P("}")
g.P()
}
}
// generateServerSignature returns the server-side signature for a method.
func (g *micro) generateServerSignature(servName string, method *pb.MethodDescriptorProto) string {
origMethName := method.GetName()
methName := generator.CamelCase(origMethName)
if reservedClientName[methName] {
methName += "_"
}
var reqArgs []string
ret := "error"
reqArgs = append(reqArgs, contextPkg+".Context")
if !method.GetClientStreaming() {
reqArgs = append(reqArgs, "*"+g.typeName(method.GetInputType()))
}
if method.GetServerStreaming() || method.GetClientStreaming() {
reqArgs = append(reqArgs, servName+"_"+generator.CamelCase(origMethName)+"Stream")
}
if !method.GetClientStreaming() && !method.GetServerStreaming() {
reqArgs = append(reqArgs, "*"+g.typeName(method.GetOutputType()))
}
return methName + "(" + strings.Join(reqArgs, ", ") + ") " + ret
}
func (g *micro) generateServerMethod(servName string, method *pb.MethodDescriptorProto) string {
methName := generator.CamelCase(method.GetName())
hname := fmt.Sprintf("_%s_%s_Handler", servName, methName)
serveType := servName + "Handler"
inType := g.typeName(method.GetInputType())
outType := g.typeName(method.GetOutputType())
if !method.GetServerStreaming() && !method.GetClientStreaming() {
g.P("func (h *", unexport(servName), "Handler) ", methName, "(ctx ", contextPkg, ".Context, req *", inType, ", rsp *", outType, ") error {")
g.P("return h.", serveType, ".", methName, "(ctx, req, rsp)")
g.P("}")
g.P()
return hname
}
streamType := unexport(servName) + methName + "Stream"
g.P("func (h *", unexport(servName), "Handler) ", methName, "(ctx ", contextPkg, ".Context, stream server.Stream) error {")
if !method.GetClientStreaming() {
g.P("m := &", inType, "{}")
g.P("if err := stream.Recv(m); err != nil { return err }")
g.P("return h.", serveType, ".", methName, "(ctx, m, &", streamType, "{stream})")
} else {
g.P("return h.", serveType, ".", methName, "(ctx, &", streamType, "{stream})")
}
g.P("}")
g.P()
genSend := method.GetServerStreaming()
genRecv := method.GetClientStreaming()
// Stream auxiliary types and methods.
g.P("type ", servName, "_", methName, "Stream interface {")
g.P("Context() context.Context")
g.P("SendMsg(interface{}) error")
g.P("RecvMsg(interface{}) error")
if !genSend {
// client streaming, the server will send a response upon close
g.P("SendAndClose(*", outType, ") error")
}
g.P("Close() error")
if genSend {
g.P("Send(*", outType, ") error")
}
if genRecv {
g.P("Recv() (*", inType, ", error)")
}
g.P("}")
g.P()
g.P("type ", streamType, " struct {")
g.P("stream ", serverPkg, ".Stream")
g.P("}")
g.P()
if !genSend {
// client streaming, the server will send a response upon close
g.P("func (x *", streamType, ") SendAndClose(in *", outType, ") error {")
g.P("if err := x.SendMsg(in); err != nil {")
g.P("return err")
g.P("}")
g.P("return x.stream.Close()")
g.P("}")
g.P()
}
// other types of rpc don't send a response when the stream closes
g.P("func (x *", streamType, ") Close() error {")
g.P("return x.stream.Close()")
g.P("}")
g.P()
g.P("func (x *", streamType, ") Context() context.Context {")
g.P("return x.stream.Context()")
g.P("}")
g.P()
g.P("func (x *", streamType, ") SendMsg(m interface{}) error {")
g.P("return x.stream.Send(m)")
g.P("}")
g.P()
g.P("func (x *", streamType, ") RecvMsg(m interface{}) error {")
g.P("return x.stream.Recv(m)")
g.P("}")
g.P()
if genSend {
g.P("func (x *", streamType, ") Send(m *", outType, ") error {")
g.P("return x.stream.Send(m)")
g.P("}")
g.P()
}
if genRecv {
g.P("func (x *", streamType, ") Recv() (*", inType, ", error) {")
g.P("m := &", inType, "{}")
g.P("if err := x.stream.Recv(m); err != nil { return nil, err }")
g.P("return m, nil")
g.P("}")
g.P()
}
return hname
}