github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/protobuf/protoc-gen-go/grpc/grpc.go (about)

     1  // Go support for Protocol Buffers - Google's data interchange format
     2  //
     3  // Copyright 2015 The Go Authors.  All rights reserved.
     4  // https://yougam/libraries/golang/protobuf
     5  //
     6  // Redistribution and use in source and binary forms, with or without
     7  // modification, are permitted provided that the following conditions are
     8  // met:
     9  //
    10  //     * Redistributions of source code must retain the above copyright
    11  // notice, this list of conditions and the following disclaimer.
    12  //     * Redistributions in binary form must reproduce the above
    13  // copyright notice, this list of conditions and the following disclaimer
    14  // in the documentation and/or other materials provided with the
    15  // distribution.
    16  //     * Neither the name of Google Inc. nor the names of its
    17  // contributors may be used to endorse or promote products derived from
    18  // this software without specific prior written permission.
    19  //
    20  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    21  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    22  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    23  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    24  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    25  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    26  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    27  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    28  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    29  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    30  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31  
    32  // Package grpc outputs gRPC service descriptions in Go code.
    33  // It runs as a plugin for the Go protocol buffer compiler plugin.
    34  // It is linked in to protoc-gen-go.
    35  package grpc
    36  
    37  import (
    38  	"fmt"
    39  	"path"
    40  	"strconv"
    41  	"strings"
    42  
    43  	pb "github.com/insionng/yougam/libraries/golang/protobuf/protoc-gen-go/descriptor"
    44  	"github.com/insionng/yougam/libraries/golang/protobuf/protoc-gen-go/generator"
    45  )
    46  
    47  // generatedCodeVersion indicates a version of the generated code.
    48  // It is incremented whenever an incompatibility between the generated code and
    49  // the grpc package is introduced; the generated code references
    50  // a constant, grpc.SupportPackageIsVersionN (where N is generatedCodeVersion).
    51  const generatedCodeVersion = 1
    52  
    53  // Paths for packages used by code generated in this file,
    54  // relative to the import_prefix of the generator.Generator.
    55  const (
    56  	contextPkgPath = "github.com/insionng/yougam/libraries/x/net/context"
    57  	grpcPkgPath    = "google.yougam/libraries/grpc"
    58  )
    59  
    60  func init() {
    61  	generator.RegisterPlugin(new(grpc))
    62  }
    63  
    64  // grpc is an implementation of the Go protocol buffer compiler's
    65  // plugin architecture.  It generates bindings for gRPC support.
    66  type grpc struct {
    67  	gen *generator.Generator
    68  }
    69  
    70  // Name returns the name of this plugin, "grpc".
    71  func (g *grpc) Name() string {
    72  	return "grpc"
    73  }
    74  
    75  // The names for packages imported in the generated code.
    76  // They may vary from the final path component of the import path
    77  // if the name is used by other packages.
    78  var (
    79  	contextPkg string
    80  	grpcPkg    string
    81  )
    82  
    83  // Init initializes the plugin.
    84  func (g *grpc) Init(gen *generator.Generator) {
    85  	g.gen = gen
    86  	contextPkg = generator.RegisterUniquePackageName("context", nil)
    87  	grpcPkg = generator.RegisterUniquePackageName("grpc", nil)
    88  }
    89  
    90  // Given a type name defined in a .proto, return its object.
    91  // Also record that we're using it, to guarantee the associated import.
    92  func (g *grpc) objectNamed(name string) generator.Object {
    93  	g.gen.RecordTypeUse(name)
    94  	return g.gen.ObjectNamed(name)
    95  }
    96  
    97  // Given a type name defined in a .proto, return its name as we will print it.
    98  func (g *grpc) typeName(str string) string {
    99  	return g.gen.TypeName(g.objectNamed(str))
   100  }
   101  
   102  // P forwards to g.gen.P.
   103  func (g *grpc) P(args ...interface{}) { g.gen.P(args...) }
   104  
   105  // Generate generates code for the services in the given file.
   106  func (g *grpc) Generate(file *generator.FileDescriptor) {
   107  	if len(file.FileDescriptorProto.Service) == 0 {
   108  		return
   109  	}
   110  
   111  	g.P("// Reference imports to suppress errors if they are not otherwise used.")
   112  	g.P("var _ ", contextPkg, ".Context")
   113  	g.P("var _ ", grpcPkg, ".ClientConn")
   114  	g.P()
   115  
   116  	// Assert version compatibility.
   117  	g.P("// This is a compile-time assertion to ensure that this generated file")
   118  	g.P("// is compatible with the grpc package it is being compiled against.")
   119  	g.P("const _ = ", grpcPkg, ".SupportPackageIsVersion", generatedCodeVersion)
   120  	g.P()
   121  
   122  	for i, service := range file.FileDescriptorProto.Service {
   123  		g.generateService(file, service, i)
   124  	}
   125  }
   126  
   127  // GenerateImports generates the import declaration for this file.
   128  func (g *grpc) GenerateImports(file *generator.FileDescriptor) {
   129  	if len(file.FileDescriptorProto.Service) == 0 {
   130  		return
   131  	}
   132  	g.P("import (")
   133  	g.P(contextPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, contextPkgPath)))
   134  	g.P(grpcPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, grpcPkgPath)))
   135  	g.P(")")
   136  	g.P()
   137  }
   138  
   139  // reservedClientName records whether a client name is reserved on the client side.
   140  var reservedClientName = map[string]bool{
   141  // TODO: do we need any in gRPC?
   142  }
   143  
   144  func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }
   145  
   146  // generateService generates all the code for the named service.
   147  func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
   148  	path := fmt.Sprintf("6,%d", index) // 6 means service.
   149  
   150  	origServName := service.GetName()
   151  	fullServName := origServName
   152  	if pkg := file.GetPackage(); pkg != "" {
   153  		fullServName = pkg + "." + fullServName
   154  	}
   155  	servName := generator.CamelCase(origServName)
   156  
   157  	g.P()
   158  	g.P("// Client API for ", servName, " service")
   159  	g.P()
   160  
   161  	// Client interface.
   162  	g.P("type ", servName, "Client interface {")
   163  	for i, method := range service.Method {
   164  		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
   165  		g.P(g.generateClientSignature(servName, method))
   166  	}
   167  	g.P("}")
   168  	g.P()
   169  
   170  	// Client structure.
   171  	g.P("type ", unexport(servName), "Client struct {")
   172  	g.P("cc *", grpcPkg, ".ClientConn")
   173  	g.P("}")
   174  	g.P()
   175  
   176  	// NewClient factory.
   177  	g.P("func New", servName, "Client (cc *", grpcPkg, ".ClientConn) ", servName, "Client {")
   178  	g.P("return &", unexport(servName), "Client{cc}")
   179  	g.P("}")
   180  	g.P()
   181  
   182  	var methodIndex, streamIndex int
   183  	serviceDescVar := "_" + servName + "_serviceDesc"
   184  	// Client method implementations.
   185  	for _, method := range service.Method {
   186  		var descExpr string
   187  		if !method.GetServerStreaming() && !method.GetClientStreaming() {
   188  			// Unary RPC method
   189  			descExpr = fmt.Sprintf("&%s.Methods[%d]", serviceDescVar, methodIndex)
   190  			methodIndex++
   191  		} else {
   192  			// Streaming RPC method
   193  			descExpr = fmt.Sprintf("&%s.Streams[%d]", serviceDescVar, streamIndex)
   194  			streamIndex++
   195  		}
   196  		g.generateClientMethod(servName, fullServName, serviceDescVar, method, descExpr)
   197  	}
   198  
   199  	g.P("// Server API for ", servName, " service")
   200  	g.P()
   201  
   202  	// Server interface.
   203  	serverType := servName + "Server"
   204  	g.P("type ", serverType, " interface {")
   205  	for i, method := range service.Method {
   206  		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
   207  		g.P(g.generateServerSignature(servName, method))
   208  	}
   209  	g.P("}")
   210  	g.P()
   211  
   212  	// Server registration.
   213  	g.P("func Register", servName, "Server(s *", grpcPkg, ".Server, srv ", serverType, ") {")
   214  	g.P("s.RegisterService(&", serviceDescVar, `, srv)`)
   215  	g.P("}")
   216  	g.P()
   217  
   218  	// Server handler implementations.
   219  	var handlerNames []string
   220  	for _, method := range service.Method {
   221  		hname := g.generateServerMethod(servName, method)
   222  		handlerNames = append(handlerNames, hname)
   223  	}
   224  
   225  	// Service descriptor.
   226  	g.P("var ", serviceDescVar, " = ", grpcPkg, ".ServiceDesc {")
   227  	g.P("ServiceName: ", strconv.Quote(fullServName), ",")
   228  	g.P("HandlerType: (*", serverType, ")(nil),")
   229  	g.P("Methods: []", grpcPkg, ".MethodDesc{")
   230  	for i, method := range service.Method {
   231  		if method.GetServerStreaming() || method.GetClientStreaming() {
   232  			continue
   233  		}
   234  		g.P("{")
   235  		g.P("MethodName: ", strconv.Quote(method.GetName()), ",")
   236  		g.P("Handler: ", handlerNames[i], ",")
   237  		g.P("},")
   238  	}
   239  	g.P("},")
   240  	g.P("Streams: []", grpcPkg, ".StreamDesc{")
   241  	for i, method := range service.Method {
   242  		if !method.GetServerStreaming() && !method.GetClientStreaming() {
   243  			continue
   244  		}
   245  		g.P("{")
   246  		g.P("StreamName: ", strconv.Quote(method.GetName()), ",")
   247  		g.P("Handler: ", handlerNames[i], ",")
   248  		if method.GetServerStreaming() {
   249  			g.P("ServerStreams: true,")
   250  		}
   251  		if method.GetClientStreaming() {
   252  			g.P("ClientStreams: true,")
   253  		}
   254  		g.P("},")
   255  	}
   256  	g.P("},")
   257  	g.P("}")
   258  	g.P()
   259  }
   260  
   261  // generateClientSignature returns the client-side signature for a method.
   262  func (g *grpc) generateClientSignature(servName string, method *pb.MethodDescriptorProto) string {
   263  	origMethName := method.GetName()
   264  	methName := generator.CamelCase(origMethName)
   265  	if reservedClientName[methName] {
   266  		methName += "_"
   267  	}
   268  	reqArg := ", in *" + g.typeName(method.GetInputType())
   269  	if method.GetClientStreaming() {
   270  		reqArg = ""
   271  	}
   272  	respName := "*" + g.typeName(method.GetOutputType())
   273  	if method.GetServerStreaming() || method.GetClientStreaming() {
   274  		respName = servName + "_" + generator.CamelCase(origMethName) + "Client"
   275  	}
   276  	return fmt.Sprintf("%s(ctx %s.Context%s, opts ...%s.CallOption) (%s, error)", methName, contextPkg, reqArg, grpcPkg, respName)
   277  }
   278  
   279  func (g *grpc) generateClientMethod(servName, fullServName, serviceDescVar string, method *pb.MethodDescriptorProto, descExpr string) {
   280  	sname := fmt.Sprintf("/%s/%s", fullServName, method.GetName())
   281  	methName := generator.CamelCase(method.GetName())
   282  	inType := g.typeName(method.GetInputType())
   283  	outType := g.typeName(method.GetOutputType())
   284  
   285  	g.P("func (c *", unexport(servName), "Client) ", g.generateClientSignature(servName, method), "{")
   286  	if !method.GetServerStreaming() && !method.GetClientStreaming() {
   287  		g.P("out := new(", outType, ")")
   288  		// TODO: Pass descExpr to Invoke.
   289  		g.P("err := ", grpcPkg, `.Invoke(ctx, "`, sname, `", in, out, c.cc, opts...)`)
   290  		g.P("if err != nil { return nil, err }")
   291  		g.P("return out, nil")
   292  		g.P("}")
   293  		g.P()
   294  		return
   295  	}
   296  	streamType := unexport(servName) + methName + "Client"
   297  	g.P("stream, err := ", grpcPkg, ".NewClientStream(ctx, ", descExpr, `, c.cc, "`, sname, `", opts...)`)
   298  	g.P("if err != nil { return nil, err }")
   299  	g.P("x := &", streamType, "{stream}")
   300  	if !method.GetClientStreaming() {
   301  		g.P("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }")
   302  		g.P("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }")
   303  	}
   304  	g.P("return x, nil")
   305  	g.P("}")
   306  	g.P()
   307  
   308  	genSend := method.GetClientStreaming()
   309  	genRecv := method.GetServerStreaming()
   310  	genCloseAndRecv := !method.GetServerStreaming()
   311  
   312  	// Stream auxiliary types and methods.
   313  	g.P("type ", servName, "_", methName, "Client interface {")
   314  	if genSend {
   315  		g.P("Send(*", inType, ") error")
   316  	}
   317  	if genRecv {
   318  		g.P("Recv() (*", outType, ", error)")
   319  	}
   320  	if genCloseAndRecv {
   321  		g.P("CloseAndRecv() (*", outType, ", error)")
   322  	}
   323  	g.P(grpcPkg, ".ClientStream")
   324  	g.P("}")
   325  	g.P()
   326  
   327  	g.P("type ", streamType, " struct {")
   328  	g.P(grpcPkg, ".ClientStream")
   329  	g.P("}")
   330  	g.P()
   331  
   332  	if genSend {
   333  		g.P("func (x *", streamType, ") Send(m *", inType, ") error {")
   334  		g.P("return x.ClientStream.SendMsg(m)")
   335  		g.P("}")
   336  		g.P()
   337  	}
   338  	if genRecv {
   339  		g.P("func (x *", streamType, ") Recv() (*", outType, ", error) {")
   340  		g.P("m := new(", outType, ")")
   341  		g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }")
   342  		g.P("return m, nil")
   343  		g.P("}")
   344  		g.P()
   345  	}
   346  	if genCloseAndRecv {
   347  		g.P("func (x *", streamType, ") CloseAndRecv() (*", outType, ", error) {")
   348  		g.P("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }")
   349  		g.P("m := new(", outType, ")")
   350  		g.P("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }")
   351  		g.P("return m, nil")
   352  		g.P("}")
   353  		g.P()
   354  	}
   355  }
   356  
   357  // generateServerSignature returns the server-side signature for a method.
   358  func (g *grpc) generateServerSignature(servName string, method *pb.MethodDescriptorProto) string {
   359  	origMethName := method.GetName()
   360  	methName := generator.CamelCase(origMethName)
   361  	if reservedClientName[methName] {
   362  		methName += "_"
   363  	}
   364  
   365  	var reqArgs []string
   366  	ret := "error"
   367  	if !method.GetServerStreaming() && !method.GetClientStreaming() {
   368  		reqArgs = append(reqArgs, contextPkg+".Context")
   369  		ret = "(*" + g.typeName(method.GetOutputType()) + ", error)"
   370  	}
   371  	if !method.GetClientStreaming() {
   372  		reqArgs = append(reqArgs, "*"+g.typeName(method.GetInputType()))
   373  	}
   374  	if method.GetServerStreaming() || method.GetClientStreaming() {
   375  		reqArgs = append(reqArgs, servName+"_"+generator.CamelCase(origMethName)+"Server")
   376  	}
   377  
   378  	return methName + "(" + strings.Join(reqArgs, ", ") + ") " + ret
   379  }
   380  
   381  func (g *grpc) generateServerMethod(servName string, method *pb.MethodDescriptorProto) string {
   382  	methName := generator.CamelCase(method.GetName())
   383  	hname := fmt.Sprintf("_%s_%s_Handler", servName, methName)
   384  	inType := g.typeName(method.GetInputType())
   385  	outType := g.typeName(method.GetOutputType())
   386  
   387  	if !method.GetServerStreaming() && !method.GetClientStreaming() {
   388  		g.P("func ", hname, "(srv interface{}, ctx ", contextPkg, ".Context, dec func(interface{}) error) (interface{}, error) {")
   389  		g.P("in := new(", inType, ")")
   390  		g.P("if err := dec(in); err != nil { return nil, err }")
   391  		g.P("out, err := srv.(", servName, "Server).", methName, "(ctx, in)")
   392  		g.P("if err != nil { return nil, err }")
   393  		g.P("return out, nil")
   394  		g.P("}")
   395  		g.P()
   396  		return hname
   397  	}
   398  	streamType := unexport(servName) + methName + "Server"
   399  	g.P("func ", hname, "(srv interface{}, stream ", grpcPkg, ".ServerStream) error {")
   400  	if !method.GetClientStreaming() {
   401  		g.P("m := new(", inType, ")")
   402  		g.P("if err := stream.RecvMsg(m); err != nil { return err }")
   403  		g.P("return srv.(", servName, "Server).", methName, "(m, &", streamType, "{stream})")
   404  	} else {
   405  		g.P("return srv.(", servName, "Server).", methName, "(&", streamType, "{stream})")
   406  	}
   407  	g.P("}")
   408  	g.P()
   409  
   410  	genSend := method.GetServerStreaming()
   411  	genSendAndClose := !method.GetServerStreaming()
   412  	genRecv := method.GetClientStreaming()
   413  
   414  	// Stream auxiliary types and methods.
   415  	g.P("type ", servName, "_", methName, "Server interface {")
   416  	if genSend {
   417  		g.P("Send(*", outType, ") error")
   418  	}
   419  	if genSendAndClose {
   420  		g.P("SendAndClose(*", outType, ") error")
   421  	}
   422  	if genRecv {
   423  		g.P("Recv() (*", inType, ", error)")
   424  	}
   425  	g.P(grpcPkg, ".ServerStream")
   426  	g.P("}")
   427  	g.P()
   428  
   429  	g.P("type ", streamType, " struct {")
   430  	g.P(grpcPkg, ".ServerStream")
   431  	g.P("}")
   432  	g.P()
   433  
   434  	if genSend {
   435  		g.P("func (x *", streamType, ") Send(m *", outType, ") error {")
   436  		g.P("return x.ServerStream.SendMsg(m)")
   437  		g.P("}")
   438  		g.P()
   439  	}
   440  	if genSendAndClose {
   441  		g.P("func (x *", streamType, ") SendAndClose(m *", outType, ") error {")
   442  		g.P("return x.ServerStream.SendMsg(m)")
   443  		g.P("}")
   444  		g.P()
   445  	}
   446  	if genRecv {
   447  		g.P("func (x *", streamType, ") Recv() (*", inType, ", error) {")
   448  		g.P("m := new(", inType, ")")
   449  		g.P("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }")
   450  		g.P("return m, nil")
   451  		g.P("}")
   452  		g.P()
   453  	}
   454  
   455  	return hname
   456  }