├── .gitignore ├── .goreleaser.yaml ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── main.go ├── rpcx.go └── testdata └── rpcx ├── gen.sh ├── gen_gofast.sh ├── helloworld.pb.go ├── helloworld.proto └── helloworld.rpcx.pb.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | dist/ 18 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | # This is an example .goreleaser.yml file with some sensible defaults. 2 | # Make sure to check the documentation at https://goreleaser.com 3 | before: 4 | hooks: 5 | # You may remove this if you don't use go modules. 6 | - go mod tidy 7 | # you may remove this if you don't need go generate 8 | - go generate ./... 9 | builds: 10 | - env: 11 | - CGO_ENABLED=0 12 | goos: 13 | - linux 14 | - windows 15 | - darwin 16 | archives: 17 | - replacements: 18 | darwin: Darwin 19 | linux: Linux 20 | windows: Windows 21 | 386: i386 22 | amd64: x86_64 23 | checksum: 24 | name_template: 'checksums.txt' 25 | snapshot: 26 | name_template: "{{ incpatch .Version }}-next" 27 | changelog: 28 | sort: asc 29 | filters: 30 | exclude: 31 | - '^docs:' 32 | - '^test:' 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, rpcx.io 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder 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 "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 安装 3 | 4 | - 首先我们需要 `protoc` 编译器: [protobuf](https://github.com/protocolbuffers/protobuf)。一般平台上都有编译好的二进制程序,直接下载加载PATH路径里即可。或者你也可以源代码安装。 5 | 6 | `protoc`负责将proto文件编译成不同编程语言的代码,一般通过插件的方式实现。 7 | 8 | - 安装golang官方protoc-gen-go插件或gogo protoc-gen-gofast插件,任选其一即可。 9 | 10 | ```sh 11 | go install github.com/golang/protobuf/protoc-gen-go@latest // 支持标准库 12 | go install github.com/gogo/protobuf/protoc-gen-gofast@latest // 支持gogo gofast 13 | 14 | go install github.com/rpcxio/protoc-gen-go@latest // 本插件 15 | ``` 16 | 17 | - 编译rpcx插件: 18 | 19 | ```sh 20 | go install github.com/rpcxio/protoc-gen-rpcx@latest 21 | ``` 22 | 23 | 如果你到达了这一步,恭喜你,插件安装成功了,按照下面的命令你就可以将proto中定义的service编译成rpcx的服务和客户端代码了: 24 | 25 | protobuf官方库(如果未设置GOPATH,请去掉`-I${GOPATH}/src`或者设置GOPAH): 26 | ```sh 27 | protoc -I. -I${GOPATH}/src \ 28 | --go_out=. \ 29 | --rpcx_out=. --rpcx_opt=paths=source_relative helloworld.proto 30 | ``` 31 | 32 | gogo库(如果未设置GOPATH,请去掉`-I${GOPATH}/src`或者设置GOPAH): 33 | ```sh 34 | protoc -I. -I${GOPATH}/src \ 35 | --gofast_out=. --gofast_opt=paths=source_relative \ 36 | --rpcx_out=. --rpcx_opt=paths=source_relative *.proto 37 | ``` 38 | 39 | ## 例子 40 | 41 | - proto文件 42 | 43 | 最简单的一个打招呼的rpc服务。 44 | 45 | ```proto 46 | syntax = "proto3"; 47 | 48 | option go_package = "github.com/rpcxio/protoc-gen-rpcx/testdata/rpcx/helloworld"; 49 | 50 | package helloworld; 51 | 52 | // The greeting service definition. 53 | service Greeter { 54 | // Sends a greeting 55 | rpc SayHello (HelloRequest) returns (HelloReply) {} 56 | } 57 | 58 | // The request message containing the user's name. 59 | message HelloRequest { 60 | string name = 1; 61 | } 62 | 63 | // The response message containing the greetings 64 | message HelloReply { 65 | string message = 1; 66 | } 67 | ``` 68 | 69 | - 使用protoc编译器编译出Go代码 70 | 71 | ```sh 72 | protoc -I. -I${GOPATH}/src \ 73 | --gofast_out=. --gofast_opt=paths=source_relative \ 74 | --rpcx_out=. --rpcx_opt=paths=source_relative helloworld.proto 75 | ``` 76 | 77 | 上述命令生成了 `helloworld.pb.go` 与 `helloworld.rpcx.pb.go` 两个文件。 `helloworld.pb.go` 文件是由protoc-gen-gofast插件生成的, 78 | 当然你也可以选择官方的protoc-gen-go插件来生成。 `helloworld.rpcx.pb.go` 是由protoc-gen-rpcx插件生成的,它包含服务端的一个骨架, 以及客户端的代码。 79 | 80 | - 服务端代码 81 | 82 | 服务端的代码只是一个骨架,很显然你要实现你的逻辑。比如这个打招呼的例子, 客户端传入一个名称,你可以返回一个`hello `的字符串。 83 | 84 | 它还提供了一个简单启动服务的方法,你可以在此基础上实现服务端的代码,注册很多的服务,配置注册中心和其它插件等等。 85 | 86 | ```go 87 | package main 88 | 89 | import ( 90 | context "context" 91 | "fmt" 92 | 93 | helloworld "github.com/rpcxio/protoc-gen-rpcx/testdata/rpcx" 94 | server "github.com/smallnest/rpcx/server" 95 | ) 96 | 97 | func main() { 98 | s := server.NewServer() 99 | s.RegisterName("Greeter", new(GreeterImpl), "") 100 | err := s.Serve("tcp", ":8972") 101 | if err != nil { 102 | panic(err) 103 | } 104 | } 105 | 106 | type GreeterImpl struct{} 107 | 108 | // SayHello is server rpc method as defined 109 | func (s *GreeterImpl) SayHello(ctx context.Context, args *helloworld.HelloRequest, reply *helloworld.HelloReply) (err error) { 110 | *reply = helloworld.HelloReply{ 111 | Message: fmt.Sprintf("hello %s!", args.Name), 112 | } 113 | return nil 114 | } 115 | ``` 116 | 117 | - 客户端代码 118 | 119 | 客户端生成的代码更友好,它包装了`XClient`对象,提供了符合人工美学的方法调用格式(请求参数作为方法参数,返回结果作为方法的返回值)。并且提供了客户端的配置方式。 120 | 121 | 你也可以扩展客户端的配置,提供注册中心、路由算法,失败模式、重试、熔断等服务治理的设置。  122 | 123 | 124 | ```go 125 | package main 126 | 127 | import ( 128 | "context" 129 | "fmt" 130 | 131 | helloworld "github.com/rpcxio/protoc-gen-rpcx/testdata/rpcx" 132 | ) 133 | 134 | func main() { 135 | xclient := helloworld.NewXClientForGreeter("127.0.0.1:8972") 136 | client := helloworld.NewGreeterClient(xclient) 137 | 138 | args := &helloworld.HelloRequest{ 139 | Name: "rpcx", 140 | } 141 | 142 | reply, err := client.SayHello(context.Background(), args) 143 | if err != nil { 144 | panic(err) 145 | } 146 | 147 | fmt.Println("reply: ", reply.Message) 148 | } 149 | 150 | ``` -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rpcxio/protoc-gen-rpcx 2 | 3 | go 1.18 4 | 5 | require google.golang.org/protobuf v1.28.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 2 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 3 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 4 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 5 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 6 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 7 | google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= 8 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 9 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | 7 | "google.golang.org/protobuf/compiler/protogen" 8 | "google.golang.org/protobuf/types/pluginpb" 9 | ) 10 | 11 | const version = "0.3.0" 12 | 13 | func main() { 14 | showVersion := flag.Bool("version", false, "print the version and exit") 15 | flag.Parse() 16 | if *showVersion { 17 | fmt.Printf("protoc-gen-rpcx %v\n", version) 18 | return 19 | } 20 | 21 | protogen.Options{ 22 | ParamFunc: flag.CommandLine.Set, 23 | }.Run(func(gen *protogen.Plugin) error { 24 | gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) 25 | for _, f := range gen.Files { 26 | if !f.Generate { 27 | continue 28 | } 29 | generateFile(gen, f) 30 | } 31 | return nil 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /rpcx.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "google.golang.org/protobuf/compiler/protogen" 8 | ) 9 | 10 | const ( 11 | contextPackage = protogen.GoImportPath("context") 12 | rpcxServerPackage = protogen.GoImportPath("github.com/smallnest/rpcx/server") 13 | rpcxClientPackage = protogen.GoImportPath("github.com/smallnest/rpcx/client") 14 | rpcxProtocolPackage = protogen.GoImportPath("github.com/smallnest/rpcx/protocol") 15 | ) 16 | 17 | // generateFile generates a _grpc.pb.go file containing gRPC service definitions. 18 | func generateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile { 19 | if len(file.Services) == 0 { 20 | return nil 21 | } 22 | filename := file.GeneratedFilenamePrefix + ".rpcx.pb.go" 23 | g := gen.NewGeneratedFile(filename, file.GoImportPath) 24 | g.P("// Code generated by protoc-gen-rpcx. DO NOT EDIT.") 25 | g.P("// versions:") 26 | g.P("// - protoc-gen-rpcx v", version) 27 | g.P("// - protoc ", protocVersion(gen)) 28 | if file.Proto.GetOptions().GetDeprecated() { 29 | g.P("// ", file.Desc.Path(), " is a deprecated file.") 30 | } else { 31 | g.P("// source: ", file.Desc.Path()) 32 | } 33 | g.P() 34 | g.P("package ", file.GoPackageName) 35 | g.P() 36 | generateFileContent(gen, file, g) 37 | return g 38 | } 39 | 40 | func protocVersion(gen *protogen.Plugin) string { 41 | v := gen.Request.GetCompilerVersion() 42 | if v == nil { 43 | return "(unknown)" 44 | } 45 | var suffix string 46 | if s := v.GetSuffix(); s != "" { 47 | suffix = "-" + s 48 | } 49 | return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(), v.GetPatch(), suffix) 50 | } 51 | 52 | // generateFileContent generates the gRPC service definitions, excluding the package statement. 53 | func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile) { 54 | if len(file.Services) == 0 { 55 | return 56 | } 57 | 58 | g.P("// Reference imports to suppress errors if they are not otherwise used.") 59 | g.P("var _ = ", contextPackage.Ident("TODO")) 60 | // g.P("var _ = ", rpcxServerPackage.Ident("NewServer")) 61 | g.P("var _ = ", rpcxClientPackage.Ident("NewClient")) 62 | g.P("var _ = ", rpcxProtocolPackage.Ident("NewMessage")) 63 | g.P() 64 | 65 | for _, service := range file.Services { 66 | genService(gen, file, g, service) 67 | } 68 | } 69 | 70 | func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service) { 71 | serviceName := upperFirstLatter(service.GoName) 72 | 73 | g.P("//================== interface skeleton ===================") 74 | g.P(fmt.Sprintf(`type %sAble interface {`, serviceName)) 75 | g.P(fmt.Sprintf(`// %sAble can be used for interface verification.`, serviceName)) 76 | g.P() 77 | for _, method := range service.Methods { 78 | generateAbleCode(g, method) 79 | } 80 | g.P(fmt.Sprintf(`}`)) 81 | 82 | // g.P() 83 | // g.P("//================== server skeleton ===================") 84 | // g.P(fmt.Sprintf(`type %[1]sImpl struct {} 85 | 86 | // // ServeFor%[1]s starts a server only registers one service. 87 | // // You can register more services and only start one server. 88 | // // It blocks until the application exits. 89 | // func ServeFor%[1]s(addr string) error{ 90 | // s := server.NewServer() 91 | // s.RegisterName("%[1]s", new(%[1]sImpl), "") 92 | // return s.Serve("tcp", addr) 93 | // } 94 | // `, serviceName)) 95 | // g.P() 96 | // for _, method := range service.Methods { 97 | // generateServerCode(g, service, method) 98 | // } 99 | 100 | g.P() 101 | g.P("//================== client stub ===================") 102 | g.P(fmt.Sprintf(`// %[1]s is a client wrapped XClient. 103 | type %[1]sClient struct{ 104 | xclient client.XClient 105 | } 106 | 107 | // New%[1]sClient wraps a XClient as %[1]sClient. 108 | // You can pass a shared XClient object created by NewXClientFor%[1]s. 109 | func New%[1]sClient(xclient client.XClient) *%[1]sClient { 110 | return &%[1]sClient{xclient: xclient} 111 | } 112 | 113 | // NewXClientFor%[1]s creates a XClient. 114 | // You can configure this client with more options such as etcd registry, serialize type, select algorithm and fail mode. 115 | func NewXClientFor%[1]s(addr string) (client.XClient, error) { 116 | d, err := client.NewPeer2PeerDiscovery("tcp@"+addr, "") 117 | if err != nil { 118 | return nil, err 119 | } 120 | 121 | opt := client.DefaultOption 122 | opt.SerializeType = protocol.ProtoBuffer 123 | 124 | xclient := client.NewXClient("%[1]s", client.Failtry, client.RoundRobin, d, opt) 125 | 126 | return xclient,nil 127 | } 128 | `, serviceName)) 129 | for _, method := range service.Methods { 130 | generateClientCode(g, service, method) 131 | } 132 | 133 | // one client 134 | g.P() 135 | g.P("//================== oneclient stub ===================") 136 | g.P(fmt.Sprintf(`// %[1]sOneClient is a client wrapped oneClient. 137 | type %[1]sOneClient struct{ 138 | serviceName string 139 | oneclient *client.OneClient 140 | } 141 | 142 | // New%[1]sOneClient wraps a OneClient as %[1]sOneClient. 143 | // You can pass a shared OneClient object created by NewOneClientFor%[1]s. 144 | func New%[1]sOneClient(oneclient *client.OneClient) *%[1]sOneClient { 145 | return &%[1]sOneClient{ 146 | serviceName: "%[1]s", 147 | oneclient: oneclient, 148 | } 149 | } 150 | 151 | // ====================================================== 152 | `, serviceName)) 153 | for _, method := range service.Methods { 154 | generateOneClientCode(g, service, method) 155 | } 156 | } 157 | 158 | func generateServerCode(g *protogen.GeneratedFile, service *protogen.Service, method *protogen.Method) { 159 | methodName := upperFirstLatter(method.GoName) 160 | serviceName := upperFirstLatter(service.GoName) 161 | inType := g.QualifiedGoIdent(method.Input.GoIdent) 162 | outType := g.QualifiedGoIdent(method.Output.GoIdent) 163 | g.P(fmt.Sprintf(`// %s is server rpc method as defined 164 | func (s *%sImpl) %s(ctx context.Context, args *%s, reply *%s) (err error){ 165 | // TODO: add business logics 166 | 167 | // TODO: setting return values 168 | *reply = %s{} 169 | 170 | return nil 171 | } 172 | `, methodName, serviceName, methodName, inType, outType, outType)) 173 | } 174 | 175 | func generateAbleCode(g *protogen.GeneratedFile, method *protogen.Method) { 176 | methodName := upperFirstLatter(method.GoName) 177 | inType := g.QualifiedGoIdent(method.Input.GoIdent) 178 | outType := g.QualifiedGoIdent(method.Output.GoIdent) 179 | g.P(fmt.Sprintf(`// %[1]s is server rpc method as defined 180 | %[1]s(ctx context.Context, args *%[2]s, reply *%[3]s) (err error) 181 | `, methodName, inType, outType)) 182 | } 183 | 184 | func generateClientCode(g *protogen.GeneratedFile, service *protogen.Service, method *protogen.Method) { 185 | methodName := upperFirstLatter(method.GoName) 186 | serviceName := upperFirstLatter(service.GoName) 187 | inType := g.QualifiedGoIdent(method.Input.GoIdent) 188 | outType := g.QualifiedGoIdent(method.Output.GoIdent) 189 | g.P(fmt.Sprintf(`// %s is client rpc method as defined 190 | func (c *%sClient) %s(ctx context.Context, args *%s)(reply *%s, err error){ 191 | reply = &%s{} 192 | err = c.xclient.Call(ctx,"%s",args, reply) 193 | return reply, err 194 | } 195 | `, methodName, serviceName, methodName, inType, outType, outType, method.GoName)) 196 | } 197 | 198 | func generateOneClientCode(g *protogen.GeneratedFile, service *protogen.Service, method *protogen.Method) { 199 | methodName := upperFirstLatter(method.GoName) 200 | serviceName := upperFirstLatter(service.GoName) 201 | inType := g.QualifiedGoIdent(method.Input.GoIdent) 202 | outType := g.QualifiedGoIdent(method.Output.GoIdent) 203 | g.P(fmt.Sprintf(`// %s is client rpc method as defined 204 | func (c *%sOneClient) %s(ctx context.Context, args *%s)(reply *%s, err error){ 205 | reply = &%s{} 206 | err = c.oneclient.Call(ctx,c.serviceName,"%s",args, reply) 207 | return reply, err 208 | } 209 | `, methodName, serviceName, methodName, inType, outType, outType, method.GoName)) 210 | } 211 | 212 | // upperFirstLatter make the fisrt charater of given string upper class 213 | func upperFirstLatter(s string) string { 214 | if len(s) == 0 { 215 | return "" 216 | } 217 | if len(s) == 1 { 218 | return strings.ToUpper(string(s[0])) 219 | } 220 | return strings.ToUpper(string(s[0])) + s[1:] 221 | } 222 | -------------------------------------------------------------------------------- /testdata/rpcx/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | protoc -I. \ 4 | --go_out=. --go_opt=paths=source_relative \ 5 | --rpcx_out=. --rpcx_opt=paths=source_relative helloworld.proto 6 | -------------------------------------------------------------------------------- /testdata/rpcx/gen_gofast.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | protoc -I. -I${GOPATH}/src \ 4 | --gofast_out=. --gofast_opt=paths=source_relative \ 5 | --rpcx_out=. --rpcx_opt=paths=source_relative helloworld.proto 6 | -------------------------------------------------------------------------------- /testdata/rpcx/helloworld.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.28.1 4 | // protoc v3.21.5 5 | // source: helloworld.proto 6 | 7 | package helloworld 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | // The request message containing the user's name. 24 | type HelloRequest struct { 25 | state protoimpl.MessageState 26 | sizeCache protoimpl.SizeCache 27 | unknownFields protoimpl.UnknownFields 28 | 29 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 30 | } 31 | 32 | func (x *HelloRequest) Reset() { 33 | *x = HelloRequest{} 34 | if protoimpl.UnsafeEnabled { 35 | mi := &file_helloworld_proto_msgTypes[0] 36 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 37 | ms.StoreMessageInfo(mi) 38 | } 39 | } 40 | 41 | func (x *HelloRequest) String() string { 42 | return protoimpl.X.MessageStringOf(x) 43 | } 44 | 45 | func (*HelloRequest) ProtoMessage() {} 46 | 47 | func (x *HelloRequest) ProtoReflect() protoreflect.Message { 48 | mi := &file_helloworld_proto_msgTypes[0] 49 | if protoimpl.UnsafeEnabled && x != nil { 50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 51 | if ms.LoadMessageInfo() == nil { 52 | ms.StoreMessageInfo(mi) 53 | } 54 | return ms 55 | } 56 | return mi.MessageOf(x) 57 | } 58 | 59 | // Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead. 60 | func (*HelloRequest) Descriptor() ([]byte, []int) { 61 | return file_helloworld_proto_rawDescGZIP(), []int{0} 62 | } 63 | 64 | func (x *HelloRequest) GetName() string { 65 | if x != nil { 66 | return x.Name 67 | } 68 | return "" 69 | } 70 | 71 | // The response message containing the greetings 72 | type HelloReply struct { 73 | state protoimpl.MessageState 74 | sizeCache protoimpl.SizeCache 75 | unknownFields protoimpl.UnknownFields 76 | 77 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 78 | } 79 | 80 | func (x *HelloReply) Reset() { 81 | *x = HelloReply{} 82 | if protoimpl.UnsafeEnabled { 83 | mi := &file_helloworld_proto_msgTypes[1] 84 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 85 | ms.StoreMessageInfo(mi) 86 | } 87 | } 88 | 89 | func (x *HelloReply) String() string { 90 | return protoimpl.X.MessageStringOf(x) 91 | } 92 | 93 | func (*HelloReply) ProtoMessage() {} 94 | 95 | func (x *HelloReply) ProtoReflect() protoreflect.Message { 96 | mi := &file_helloworld_proto_msgTypes[1] 97 | if protoimpl.UnsafeEnabled && x != nil { 98 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 99 | if ms.LoadMessageInfo() == nil { 100 | ms.StoreMessageInfo(mi) 101 | } 102 | return ms 103 | } 104 | return mi.MessageOf(x) 105 | } 106 | 107 | // Deprecated: Use HelloReply.ProtoReflect.Descriptor instead. 108 | func (*HelloReply) Descriptor() ([]byte, []int) { 109 | return file_helloworld_proto_rawDescGZIP(), []int{1} 110 | } 111 | 112 | func (x *HelloReply) GetMessage() string { 113 | if x != nil { 114 | return x.Message 115 | } 116 | return "" 117 | } 118 | 119 | var File_helloworld_proto protoreflect.FileDescriptor 120 | 121 | var file_helloworld_proto_rawDesc = []byte{ 122 | 0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, 123 | 0x74, 0x6f, 0x12, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x22, 0x22, 124 | 0x0a, 0x0c, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 125 | 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 126 | 0x6d, 0x65, 0x22, 0x26, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 127 | 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 128 | 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x49, 0x0a, 0x07, 0x47, 0x72, 129 | 0x65, 0x65, 0x74, 0x65, 0x72, 0x12, 0x3e, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 130 | 0x6f, 0x12, 0x18, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 131 | 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, 132 | 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 133 | 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x3c, 0x5a, 0x3a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 134 | 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x70, 0x63, 0x78, 0x69, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 135 | 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x72, 0x70, 0x63, 0x78, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 136 | 0x61, 0x74, 0x61, 0x2f, 0x72, 0x70, 0x63, 0x78, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 137 | 0x72, 0x6c, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 138 | } 139 | 140 | var ( 141 | file_helloworld_proto_rawDescOnce sync.Once 142 | file_helloworld_proto_rawDescData = file_helloworld_proto_rawDesc 143 | ) 144 | 145 | func file_helloworld_proto_rawDescGZIP() []byte { 146 | file_helloworld_proto_rawDescOnce.Do(func() { 147 | file_helloworld_proto_rawDescData = protoimpl.X.CompressGZIP(file_helloworld_proto_rawDescData) 148 | }) 149 | return file_helloworld_proto_rawDescData 150 | } 151 | 152 | var file_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 153 | var file_helloworld_proto_goTypes = []interface{}{ 154 | (*HelloRequest)(nil), // 0: helloworld.HelloRequest 155 | (*HelloReply)(nil), // 1: helloworld.HelloReply 156 | } 157 | var file_helloworld_proto_depIdxs = []int32{ 158 | 0, // 0: helloworld.Greeter.SayHello:input_type -> helloworld.HelloRequest 159 | 1, // 1: helloworld.Greeter.SayHello:output_type -> helloworld.HelloReply 160 | 1, // [1:2] is the sub-list for method output_type 161 | 0, // [0:1] is the sub-list for method input_type 162 | 0, // [0:0] is the sub-list for extension type_name 163 | 0, // [0:0] is the sub-list for extension extendee 164 | 0, // [0:0] is the sub-list for field type_name 165 | } 166 | 167 | func init() { file_helloworld_proto_init() } 168 | func file_helloworld_proto_init() { 169 | if File_helloworld_proto != nil { 170 | return 171 | } 172 | if !protoimpl.UnsafeEnabled { 173 | file_helloworld_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 174 | switch v := v.(*HelloRequest); i { 175 | case 0: 176 | return &v.state 177 | case 1: 178 | return &v.sizeCache 179 | case 2: 180 | return &v.unknownFields 181 | default: 182 | return nil 183 | } 184 | } 185 | file_helloworld_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 186 | switch v := v.(*HelloReply); i { 187 | case 0: 188 | return &v.state 189 | case 1: 190 | return &v.sizeCache 191 | case 2: 192 | return &v.unknownFields 193 | default: 194 | return nil 195 | } 196 | } 197 | } 198 | type x struct{} 199 | out := protoimpl.TypeBuilder{ 200 | File: protoimpl.DescBuilder{ 201 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 202 | RawDescriptor: file_helloworld_proto_rawDesc, 203 | NumEnums: 0, 204 | NumMessages: 2, 205 | NumExtensions: 0, 206 | NumServices: 1, 207 | }, 208 | GoTypes: file_helloworld_proto_goTypes, 209 | DependencyIndexes: file_helloworld_proto_depIdxs, 210 | MessageInfos: file_helloworld_proto_msgTypes, 211 | }.Build() 212 | File_helloworld_proto = out.File 213 | file_helloworld_proto_rawDesc = nil 214 | file_helloworld_proto_goTypes = nil 215 | file_helloworld_proto_depIdxs = nil 216 | } 217 | -------------------------------------------------------------------------------- /testdata/rpcx/helloworld.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "github.com/rpcxio/protoc-gen-rpcx/testdata/rpcx/helloworld"; 4 | 5 | package helloworld; 6 | 7 | // The greeting service definition. 8 | service Greeter { 9 | // Sends a greeting 10 | rpc SayHello (HelloRequest) returns (HelloReply) {} 11 | } 12 | 13 | // The request message containing the user's name. 14 | message HelloRequest { 15 | string name = 1; 16 | } 17 | 18 | // The response message containing the greetings 19 | message HelloReply { 20 | string message = 1; 21 | } -------------------------------------------------------------------------------- /testdata/rpcx/helloworld.rpcx.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-rpcx. DO NOT EDIT. 2 | // versions: 3 | // - protoc-gen-rpcx v0.3.0 4 | // - protoc v3.21.5 5 | // source: helloworld.proto 6 | 7 | package helloworld 8 | 9 | import ( 10 | context "context" 11 | client "github.com/smallnest/rpcx/client" 12 | protocol "github.com/smallnest/rpcx/protocol" 13 | server "github.com/smallnest/rpcx/server" 14 | ) 15 | 16 | // Reference imports to suppress errors if they are not otherwise used. 17 | var _ = context.TODO 18 | var _ = server.NewServer 19 | var _ = client.NewClient 20 | var _ = protocol.NewMessage 21 | 22 | // ================== interface skeleton =================== 23 | type GreeterAble interface { 24 | // GreeterAble can be used for interface verification. 25 | 26 | // SayHello is server rpc method as defined 27 | SayHello(ctx context.Context, args *HelloRequest, reply *HelloReply) (err error) 28 | } 29 | 30 | // ================== server skeleton =================== 31 | type GreeterImpl struct{} 32 | 33 | // ServeForGreeter starts a server only registers one service. 34 | // You can register more services and only start one server. 35 | // It blocks until the application exits. 36 | func ServeForGreeter(addr string) error { 37 | s := server.NewServer() 38 | s.RegisterName("Greeter", new(GreeterImpl), "") 39 | return s.Serve("tcp", addr) 40 | } 41 | 42 | // SayHello is server rpc method as defined 43 | func (s *GreeterImpl) SayHello(ctx context.Context, args *HelloRequest, reply *HelloReply) (err error) { 44 | // TODO: add business logics 45 | 46 | // TODO: setting return values 47 | *reply = HelloReply{} 48 | 49 | return nil 50 | } 51 | 52 | //================== client stub =================== 53 | // Greeter is a client wrapped XClient. 54 | type GreeterClient struct { 55 | xclient client.XClient 56 | } 57 | 58 | // NewGreeterClient wraps a XClient as GreeterClient. 59 | // You can pass a shared XClient object created by NewXClientForGreeter. 60 | func NewGreeterClient(xclient client.XClient) *GreeterClient { 61 | return &GreeterClient{xclient: xclient} 62 | } 63 | 64 | // NewXClientForGreeter creates a XClient. 65 | // You can configure this client with more options such as etcd registry, serialize type, select algorithm and fail mode. 66 | func NewXClientForGreeter(addr string) (client.XClient, error) { 67 | d, err := client.NewPeer2PeerDiscovery("tcp@"+addr, "") 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | opt := client.DefaultOption 73 | opt.SerializeType = protocol.ProtoBuffer 74 | 75 | xclient := client.NewXClient("Greeter", client.Failtry, client.RoundRobin, d, opt) 76 | 77 | return xclient, nil 78 | } 79 | 80 | // SayHello is client rpc method as defined 81 | func (c *GreeterClient) SayHello(ctx context.Context, args *HelloRequest) (reply *HelloReply, err error) { 82 | reply = &HelloReply{} 83 | err = c.xclient.Call(ctx, "SayHello", args, reply) 84 | return reply, err 85 | } 86 | 87 | //================== oneclient stub =================== 88 | // GreeterOneClient is a client wrapped oneClient. 89 | type GreeterOneClient struct { 90 | serviceName string 91 | oneclient *client.OneClient 92 | } 93 | 94 | // NewGreeterOneClient wraps a OneClient as GreeterOneClient. 95 | // You can pass a shared OneClient object created by NewOneClientForGreeter. 96 | func NewGreeterOneClient(oneclient *client.OneClient) *GreeterOneClient { 97 | return &GreeterOneClient{ 98 | serviceName: "Greeter", 99 | oneclient: oneclient, 100 | } 101 | } 102 | 103 | // ====================================================== 104 | 105 | // SayHello is client rpc method as defined 106 | func (c *GreeterOneClient) SayHello(ctx context.Context, args *HelloRequest) (reply *HelloReply, err error) { 107 | reply = &HelloReply{} 108 | err = c.oneclient.Call(ctx, c.serviceName, "SayHello", args, reply) 109 | return reply, err 110 | } 111 | --------------------------------------------------------------------------------