├── _config.yml
├── .gitignore
├── .travis.yml
├── .github
└── workflows
│ └── main.yml
├── compress.go
├── go.mod
├── doc.go
├── utility.go
├── utility_test.go
├── docs
├── httprpc.md
├── quickstart_server.md
├── quickstart_client.md
└── Demo.md
├── header_test.go
├── request.pb_test.go
├── log.go
├── example
├── haclient_example_test.go
├── client_example_test.go
├── pb_example_test.go
└── server_example_test.go
├── codec_test.go
├── README.md
├── benchmark_test.go
├── header.go
├── status_test.go
├── haclient_test.go
├── echoservice_test.go
├── go.sum
├── httpserver_test.go
├── datamessage_test.go
├── server_test.go
├── status.go
├── connection.go
├── connectionpool.go
├── rpcpackage_test.go
├── httpserver.go
├── haclient.go
├── codec.go
├── pb_status.go
├── LICENSE
├── client.go
├── client_test.go
├── rpcpackage.go
└── pb_data.go
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .settings/org.eclipse.core.resources.prefs
3 | .idea
4 | .vscode/launch.json
5 | .gitignore
6 | .vscode/settings.json
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | go_import_path: github.com/jhunters/timewheel
3 |
4 | sudo: false
5 |
6 | go:
7 | - 1.13
8 |
9 | before_install:
10 | - go get -v honnef.co/go/tools/...
11 | - go get -v github.com/kisielk/errcheck
12 |
13 | script:
14 | - make test
15 | - make race
16 | # - make errcheck
17 |
18 | after_success:
19 | - bash <(curl -s https://codecov.io/bash)
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ v1.4.x ]
6 | pull_request:
7 | branches: [ v1.4.x ]
8 |
9 | jobs:
10 |
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v2
18 | with:
19 | go-version: 1.18
20 |
21 | - name: Build
22 | run: go build -v ./...
23 |
24 | - name: Test
25 | run: go test -timeout 120s -v ./... -coverprofile=coverage.txt -covermode=atomic
26 |
27 | - name: CoverageUpload
28 | run: bash <(curl -s https://codecov.io/bash)
29 |
--------------------------------------------------------------------------------
/compress.go:
--------------------------------------------------------------------------------
1 | package baidurpc
2 |
3 | import (
4 | "bytes"
5 | "compress/gzip"
6 | "io/ioutil"
7 | )
8 |
9 | // GZIP do gzip action by gzip package
10 | func GZIP(b []byte) ([]byte, error) {
11 | buf := new(bytes.Buffer)
12 | w := gzip.NewWriter(buf)
13 | defer w.Close()
14 |
15 | _, err := w.Write(b)
16 | w.Flush()
17 |
18 | if err != nil {
19 | return nil, err
20 | }
21 |
22 | return buf.Bytes(), nil
23 | }
24 |
25 | // GUNZIP do unzip action by gzip package
26 | func GUNZIP(b []byte) ([]byte, error) {
27 | buf := new(bytes.Buffer)
28 | buf.Write(b)
29 | r, err := gzip.NewReader(buf)
30 | if err != nil {
31 | return nil, err
32 | }
33 | defer r.Close()
34 | undatas, _ := ioutil.ReadAll(r)
35 |
36 | return undatas, nil
37 | }
38 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/baidu-golang/pbrpc
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/golang/snappy v0.0.4
7 | github.com/jhunters/goassist v1.0.9
8 | github.com/jhunters/timewheel v1.1.0
9 | github.com/jolestar/go-commons-pool/v2 v2.1.1
10 | github.com/smartystreets/goconvey v1.7.2
11 | google.golang.org/protobuf v1.26.0
12 | )
13 |
14 | require (
15 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
16 | github.com/jtolds/gls v4.20.0+incompatible // indirect
17 | github.com/smartystreets/assertions v1.2.0 // indirect
18 | )
19 |
20 | require (
21 | github.com/jhunters/link v0.0.0-20221207123848-6322292415b2
22 | github.com/stretchr/testify v1.6.1 // indirect
23 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
24 | )
25 |
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
--------------------------------------------------------------------------------
/utility.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "time"
20 | )
21 |
22 | var NANO_IN_SECONDS = 1000000000.0
23 |
24 | // get time took in seconds
25 | func TimetookInSeconds(currentNano int64) float64 {
26 | c := time.Now().UnixNano()
27 |
28 | return float64(c-currentNano) / NANO_IN_SECONDS
29 | }
30 |
--------------------------------------------------------------------------------
/utility_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc_test
17 |
18 | import (
19 | "testing"
20 | "time"
21 |
22 | baidurpc "github.com/baidu-golang/pbrpc"
23 | )
24 |
25 | func TestTimetookInSeconds(t *testing.T) {
26 |
27 | now := time.Now().UnixNano()
28 |
29 | time.Sleep(time.Second)
30 |
31 | cost := baidurpc.TimetookInSeconds(now)
32 |
33 | if cost < 1 {
34 | t.Error("time took is not acceptable.")
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/docs/httprpc.md:
--------------------------------------------------------------------------------
1 |
6 |
baidurpc
7 |
8 |
9 | baidurpc是一种基于TCP协议的二进制高性能RPC通信协议实现。它以Protobuf作为基本的数据交换格式。
10 | 本版本基于golang实现.完全兼容jprotobuf-rpc-socket: https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
11 |
12 |
13 |
14 |
15 | ### 同步发布http rpc服务
16 | 要同步发布http rpc 服务,部署非常简单,直接调用 EnableHttp 方法即可。会与rpc复用同一端口。
17 |
18 | ```go
19 | rpcServer.EnableHttp()
20 | ```
21 |
22 | ```go
23 | serverMeta := baidurpc.ServerMeta{}
24 | serverMeta.Host = nil
25 | serverMeta.Port = Int(*port)
26 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
27 |
28 | echoService := new(EchoService)
29 |
30 | rpcServer.Register(echoService)
31 | // 开启http rpc服务
32 | rpcServer.EnableHttp()
33 | // 启动RPC服务
34 | err := rpcServer.Start()
35 |
36 | if err != nil {
37 | baidurpc.Error(err)
38 | }
39 | ```
40 |
41 | ### 相关事项说明
42 | 1. 发布http rpc 服务, 需要struct 增加json tag字段说明
43 | ```go
44 | type DataMessage struct {
45 | Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
46 | }
47 | ```
48 | 2. http 协议统一使用POST方法进行发布。 url path 协同 http://host:port/rpc/service_name/method_name
49 | 3. http请求内容
50 | header 定义 "Content-Type" "application/json;charset=utf-8"
51 | POST body直接为json结构
52 | 4. http返回内容, json结果.
53 |
54 | errno错误码: 0表示成功,其它则为错误
55 | message: 错误信息,errno非0时,会设置
56 | data:返回内容
57 |
58 | ```json
59 | {
60 | "errno" : 0,
61 | "message" : "",
62 | "data" : {}
63 | }
64 | ```
--------------------------------------------------------------------------------
/header_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-04-26 18:18:59
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | package baidurpc_test
22 |
23 | import (
24 | "testing"
25 |
26 | baidurpc "github.com/baidu-golang/pbrpc"
27 |
28 | . "github.com/smartystreets/goconvey/convey"
29 | )
30 |
31 | // TestRpcDataWriteReader test head read and write
32 | func TestRpcDataWriteReader(t *testing.T) {
33 |
34 | Convey("TestRpcDataWriteReader", t, func() {
35 |
36 | h := baidurpc.Header{}
37 | h.SetMagicCode([]byte("PRPB"))
38 | h.SetMessageSize(12300)
39 | h.SetMetaSize(59487)
40 |
41 | bs, _ := h.Write()
42 | So(len(bs), ShouldEqual, baidurpc.SIZE)
43 |
44 | h2 := baidurpc.Header{}
45 | h2.Read(bs)
46 | So(string(h.GetMagicCode()), ShouldEqual, string(h2.GetMagicCode()))
47 | So(h.GetMessageSize(), ShouldEqual, 12300)
48 | So(h.GetMetaSize(), ShouldEqual, 59487)
49 | })
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/docs/quickstart_server.md:
--------------------------------------------------------------------------------
1 |
6 | baidurpc
7 |
8 |
9 | baidurpc是一种基于TCP协议的二进制高性能RPC通信协议实现。它以Protobuf作为基本的数据交换格式。
10 | 本版本基于golang实现.完全兼容jprotobuf-rpc-socket: https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
11 |
12 |
13 |
14 | ### Installing
15 |
16 | To start using pbrpc, install Go and run `go get`:
17 |
18 | ```sh
19 | $ go get github.com/baidu-golang/pbrpc
20 | ```
21 |
22 | ### 定义protobuf 对象
23 | ```property
24 | message DataMessae {
25 | string name = 1;
26 | }
27 | ```
28 | 用protoc工具 生成 pb go 定义文件
29 | protoc --go_out=. datamessage.proto
30 |
31 |
32 | ### 开发RPC服务端
33 | 要发布一个RPC服务,需要先定义一个对象以及方法,用于发布服务。 与传统的golang基础库的rpc发布非常一致。
34 |
35 | 1. 以下定义了 EchoService对象 并 增加 Echo 方法
36 | ```go
37 | type EchoService struct {
38 | }
39 |
40 | func (rpc *EchoService) Echo(c context.Context, in *DataMessage) (*DataMessage, context.Context) {
41 | var ret = "hello "
42 | if len(*in.Name) == 0 {
43 | ret = ret + "veryone"
44 | } else {
45 | ret = ret + *in.Name
46 | }
47 | dm := DataMessage{}
48 | dm.Name = proto.String(ret)
49 | return &dm, baidurpc.BindAttachement(context.Background(), []byte("hello")) // return with attachement
50 | }
51 | ```
52 |
53 | 2. 指定发布端口,把EchoService发布成RPC服务
54 |
55 | ```go
56 | serverMeta := baidurpc.ServerMeta{}
57 | serverMeta.Host = nil
58 | serverMeta.Port = Int(*port)
59 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
60 |
61 | echoService := new(EchoService)
62 |
63 | rpcServer.Register(echoService)
64 |
65 | // 启动RPC服务
66 | err := rpcServer.Start()
67 |
68 | if err != nil {
69 | baidurpc.Error(err)
70 | }
71 | ```
72 |
73 | [查看代码](https://github.com/baidu-golang/pbrpc/blob/master/example/server_example_test.go)
--------------------------------------------------------------------------------
/docs/quickstart_client.md:
--------------------------------------------------------------------------------
1 |
6 | baidurpc
7 |
8 |
9 | baidurpc是一种基于TCP协议的二进制高性能RPC通信协议实现。它以Protobuf作为基本的数据交换格式。
10 | 本版本基于golang实现.完全兼容jprotobuf-rpc-socket: https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
11 |
12 |
13 |
14 | ### Installing
15 |
16 | To start using pbrpc, install Go and run `go get`:
17 |
18 | ```sh
19 | $ go get github.com/baidu-golang/pbrpc
20 | ```
21 |
22 | ### 定义protobuf 对象
23 | ```property
24 | message DataMessae {
25 | string name = 1;
26 | }
27 | ```
28 | 用protoc工具 生成 pb go 定义文件
29 | protoc --go_out=. datamessage.proto
30 |
31 |
32 | ### 开发RPC客户端
33 | 客户端开发,使用RpcClient进行调用。
34 |
35 | ```go
36 | host := "localhost"
37 | port := 1031
38 | // 创建链接
39 | url := baidurpc.URL{}
40 | url.SetHost(&host).SetPort(&port)
41 |
42 | timeout := time.Second * 500
43 | // create client by simple connection
44 | connection, err := baidurpc.NewTCPConnection(url, &timeout)
45 |
46 | if err != nil {
47 | fmt.Println(err)
48 | return
49 | }
50 | defer connection.Close()
51 |
52 | // 创建client
53 | rpcClient, err := baidurpc.NewRpcCient(connection)
54 | if err != nil {
55 | fmt.Println(err)
56 | return
57 | }
58 | defer rpcClient.Close()
59 | // 调用RPC
60 | serviceName := "echoService"
61 | methodName := "echo"
62 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
63 |
64 | message := "say hello from xiemalin中文测试"
65 | dm := DataMessage{&message}
66 |
67 | rpcInvocation.SetParameterIn(&dm)
68 | parameterOut := DataMessage{}
69 |
70 | _, err := rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
71 | if err != nil {
72 | fmt.Println(err)
73 | }
74 |
75 | fmt.Println(*parameterOut.Name)
76 | ```
77 |
78 | [查看代码](https://github.com/baidu-golang/pbrpc/blob/master/example/client_example_test.go)
--------------------------------------------------------------------------------
/request.pb_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-07-24 16:54:14
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | package baidurpc_test
22 |
23 | import (
24 | "testing"
25 |
26 | baidurpc "github.com/baidu-golang/pbrpc"
27 | "google.golang.org/protobuf/proto"
28 |
29 | . "github.com/smartystreets/goconvey/convey"
30 | )
31 |
32 | // TestPropertySetAndGet
33 | func TestPropertySetAndGet(t *testing.T) {
34 | Convey("TestPropertySetAndGet", t, func() {
35 | var serviceName string = "ThisAServiceName"
36 | var methodName string = "ThisAMethodName"
37 | var logId int64 = 1
38 |
39 | request := baidurpc.Request{
40 | ServiceName: serviceName,
41 | MethodName: methodName,
42 | LogId: logId,
43 | }
44 |
45 | So(serviceName, ShouldEqual, request.GetServiceName())
46 | So(methodName, ShouldEqual, request.GetMethodName())
47 | So(logId, ShouldEqual, request.GetLogId())
48 |
49 | data, err := proto.Marshal(&request)
50 | So(err, ShouldBeNil)
51 |
52 | request2 := new(baidurpc.Request)
53 | err = proto.Unmarshal(data, request2)
54 | So(err, ShouldBeNil)
55 |
56 | So(request.GetServiceName(), ShouldEqual, request2.GetServiceName())
57 | })
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/log.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "log"
20 | )
21 |
22 | // Info logs to the INFO log.
23 | // Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
24 | func Info(args ...interface{}) {
25 | log.Println(args...)
26 | }
27 |
28 | // Infof logs to the INFO log.
29 | // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
30 | func Infof(format string, args ...interface{}) {
31 | log.Printf(format, args...)
32 | }
33 |
34 | // Warning logs to the WARNING and INFO logs.
35 | // Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
36 | func Warning(args ...interface{}) {
37 | log.Println(args...)
38 | }
39 |
40 | // Warningf logs to the WARNING and INFO logs.
41 | // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
42 | func Warningf(format string, args ...interface{}) {
43 | log.Printf(format, args...)
44 | }
45 |
46 | // Error logs to the ERROR, WARNING, and INFO logs.
47 | // Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
48 | func Error(args ...interface{}) {
49 | log.Println(args...)
50 | }
51 |
52 | // Errorf logs to the ERROR, WARNING, and INFO logs.
53 | // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
54 | func Errorf(format string, args ...interface{}) {
55 | log.Printf(format, args...)
56 | }
57 |
--------------------------------------------------------------------------------
/example/haclient_example_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | /*
17 | * @Author: Malin Xie
18 | * @Description:
19 | * @Date: 2021-08-03 19:12:14
20 | */
21 | package example
22 |
23 | import (
24 | "fmt"
25 | "time"
26 |
27 | baidurpc "github.com/baidu-golang/pbrpc"
28 | "google.golang.org/protobuf/proto"
29 | )
30 |
31 | // ExampleTcpClient
32 | func ExampleHaTcpClient() {
33 |
34 | host := "localhost"
35 | timeout := time.Second * 5
36 | errPort := 100
37 | port := 1031
38 | urls := []baidurpc.URL{{Host: &host, Port: &errPort}, {Host: &host, Port: &port}}
39 |
40 | connections, err := baidurpc.NewBatchTCPConnection(urls, timeout)
41 | if err != nil {
42 | return
43 | }
44 | defer baidurpc.CloseBatchConnection(connections)
45 |
46 | haClient, err := baidurpc.NewHaRpcCient(connections)
47 | if err != nil {
48 | return
49 | }
50 | defer haClient.Close()
51 |
52 | serviceName := "echoService"
53 | methodName := "echo"
54 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
55 |
56 | message := "say hello from xiemalin中文测试"
57 | dm := DataMessage{Name: message}
58 |
59 | rpcInvocation.SetParameterIn(&dm)
60 | rpcInvocation.LogId = proto.Int64(1)
61 | rpcInvocation.Attachment = []byte("hello world")
62 |
63 | parameterOut := DataMessage{}
64 |
65 | response, err := haClient.SendRpcRequest(rpcInvocation, ¶meterOut)
66 | if err != nil {
67 | return
68 | }
69 |
70 | if response == nil {
71 | fmt.Println("Reponse is nil")
72 | return
73 | }
74 |
75 | fmt.Println("attachement", response.Attachment)
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/codec_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-07-24 16:54:14
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | package baidurpc_test
22 |
23 | import (
24 | "bytes"
25 | "testing"
26 |
27 | baidurpc "github.com/baidu-golang/pbrpc"
28 | . "github.com/smartystreets/goconvey/convey"
29 | )
30 |
31 | // TestCodecSend
32 | func TestCodecSend(t *testing.T) {
33 | Convey("TestCodecSend", t, func() {
34 | protocol := &baidurpc.RpcDataPackageProtocol[*baidurpc.RpcDataPackage, *baidurpc.RpcDataPackage]{}
35 |
36 | buf := new(bytes.Buffer)
37 |
38 | rpcDataPackagecodec, _ := protocol.NewCodec(buf)
39 |
40 | rpcDataPackage := initRpcDataPackage()
41 |
42 | rpcDataPackagecodec.Send(rpcDataPackage)
43 |
44 | r2 := baidurpc.RpcDataPackage{}
45 | err := r2.ReadIO(buf)
46 | So(err, ShouldBeNil)
47 |
48 | err = equalRpcDataPackage(r2, t)
49 | So(err, ShouldBeNil)
50 | })
51 |
52 | }
53 |
54 | // TestCodecReceive
55 | func TestCodecReceive(t *testing.T) {
56 |
57 | Convey("TestCodecReceive", t, func() {
58 | protocol := &baidurpc.RpcDataPackageProtocol[*baidurpc.RpcDataPackage, *baidurpc.RpcDataPackage]{}
59 |
60 | buf := new(bytes.Buffer)
61 | // write prepare value to buf
62 | rpcDataPackage := initRpcDataPackage()
63 | bytes, err := rpcDataPackage.Write()
64 | So(err, ShouldBeNil)
65 |
66 | buf.Write(bytes)
67 | rpcDataPackagecodec, _ := protocol.NewCodec(buf)
68 |
69 | rsp, err := rpcDataPackagecodec.Receive()
70 | So(err, ShouldBeNil)
71 | mc := rsp.GetMagicCode()
72 | So(string(magicCode), ShouldEqual, string(mc))
73 | })
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | baidurpc
8 |
9 |
10 | baidurpc是一种基于TCP协议的二进制高性能RPC通信协议实现。它以Protobuf作为基本的数据交换格式。
11 | 本版本基于golang实现.完全兼容jprotobuf-rpc-socket: https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
12 |
13 |
14 | [](https://goreportcard.com/report/github.com/baidu-golang/pbrpc)
15 | [](https://github.com/baidu-golang/pbrpc/actions/workflows/main.yml)
16 | [](https://codecov.io/gh/baidu-golang/pbrpc)
17 | [](https://github.com/baidu-golang/pbrpc/releases)
18 | [](https://golang.com.cn/github.com/baidu-golang/pbrpc)
19 | [](https://github.com/baidu-golang/pbrpc/blob/master/LICENSE)
20 |
21 |
22 | ### features:
23 |
24 | - 内置连接池,具备更高的性能,低延迟 QPS: 5w+
25 | - 支持自动重连功能[Done]
26 | - 支持附件发送[Done]
27 | - 支持超时功能[Done]
28 | - 压缩功能,支持GZip与Snappy[Done]
29 | - 集成内置HTTP管理功能[TODO]
30 | - Client支持Ha的负载均衡功能[Done]
31 | - 灵活的超时设置功能[Done] 基于[timewheel](https://github.com/jhunters/timewheel)实现
32 | - 分包chunk支持,针对大数据包支持拆分包的发送的功能[Done]
33 | - 支持Web管理能力以及内置能力[Done] [查看](https://github.com/jhunters/brpcweb)
34 | - 支持同步发布为Http JSON协议[Done] [>= v1.2.0]
35 |
36 | ### Installing
37 |
38 | To start using pbrpc, install Go and run `go get`:
39 |
40 | ```sh
41 | $ go get github.com/baidu-golang/pbrpc
42 | ```
43 |
44 | ### Which version
45 | |version | protobuf package |
46 | | ---- | ---- |
47 | |<= 1.2.x| github.com/golang/protobuf|
48 | |1.3.x| google.golang.org/protobuf|
49 |
50 | FYI: 由于这两个pb类库并不是完全兼容,官方推荐使用 google.golang.org/protobuf
51 |
52 | ### 使用说明与Demo
53 |
54 | [Quick Start(服务发布)](./docs/quickstart_server.md)
55 | [Quick Start(客户端调用)](./docs/quickstart_client.md)
56 | [同步发布http rpc服务](./docs/httprpc.md)
57 | [更多特性使用说明](./docs/Demo.md)
58 | [Demo开发示例代码](./example)
59 | ## License
60 | brpc is [Apache 2.0 licensed](./LICENSE).
61 |
--------------------------------------------------------------------------------
/benchmark_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-08-25 19:33:37
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | /*
22 | * @Author: Malin Xie
23 | * @Description:
24 | * @Date: 2021-08-03 15:52:08
25 | */
26 | package baidurpc_test
27 |
28 | import (
29 | "testing"
30 | "time"
31 |
32 | baidurpc "github.com/baidu-golang/pbrpc"
33 | "google.golang.org/protobuf/proto"
34 | )
35 |
36 | // BenchmarkTestLocalConnectionPerformance bench mark test
37 | func BenchmarkTestLocalConnectionPerformance(b *testing.B) {
38 | host := "localhost"
39 | port := PORT_1
40 |
41 | tcpServer := startRpcServer(0)
42 | defer stopRpcServer(tcpServer)
43 |
44 | conn, client, _ := createClient()
45 | defer client.Close()
46 | defer conn.Close()
47 |
48 | url := baidurpc.URL{}
49 | url.SetHost(&host).SetPort(&port)
50 |
51 | timeout := time.Second * 5
52 | // create client by simple connection
53 | connection, err := baidurpc.NewTCPConnection(url, &timeout)
54 | if err != nil {
55 | return
56 | }
57 | defer connection.Close()
58 | for i := 0; i < b.N; i++ {
59 | doSimpleRPCInvokeWithSignature(client, "EchoService", "echo")
60 | }
61 |
62 | }
63 |
64 | // doSimpleRPCInvokeWithSignature send rpc request
65 | func doSimpleRPCInvokeWithSignature(rpcClient *baidurpc.RpcClient, serviceName, methodName string) {
66 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
67 |
68 | name := "马林"
69 | dm := DataMessage{Name: name}
70 |
71 | rpcInvocation.SetParameterIn(&dm)
72 | rpcInvocation.LogId = proto.Int64(1)
73 |
74 | parameterOut := DataMessage{}
75 |
76 | rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
77 | }
78 |
--------------------------------------------------------------------------------
/header.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "bytes"
20 | "encoding/binary"
21 | )
22 |
23 | const (
24 | SIZE = 12
25 |
26 | MagicSize = 4
27 |
28 | MAGIC_CODE = "PRPC"
29 |
30 | COMPRESS_NO int32 = 0
31 | COMPRESS_SNAPPY int32 = 1
32 | COMPRESS_GZIP int32 = 2
33 | )
34 |
35 | // Writable is the interface that do serialize to []byte
36 | // if errror ocurres should return non-nil error
37 | type Writable interface {
38 | Write() ([]byte, error)
39 | }
40 |
41 | // Readable is the interface that deserialize from []byte
42 | // if errror ocurres should return non-nil error
43 | type Readable interface {
44 | Read(bytes []byte) error
45 | }
46 |
47 | // RPC header content
48 | type Header struct {
49 | MagicCode []byte
50 | MessageSize int32
51 | MetaSize int32
52 | }
53 |
54 | // EmptyHead return a empty head with default value
55 | func EmptyHead() *Header {
56 | h := Header{}
57 | h.MagicCode = []byte(MAGIC_CODE)
58 | h.MessageSize = 0
59 | h.MetaSize = 0
60 | return &h
61 | }
62 |
63 | /*
64 | Convert Header struct to byte array
65 | */
66 | func (h *Header) Write() ([]byte, error) {
67 | b := new(bytes.Buffer)
68 |
69 | binary.Write(b, binary.BigEndian, h.GetMagicCode())
70 | binary.Write(b, binary.BigEndian, intToBytes(h.GetMessageSize()))
71 | binary.Write(b, binary.BigEndian, intToBytes(h.GetMetaSize()))
72 | return b.Bytes(), nil
73 | }
74 |
75 | func intToBytes(i int32) []byte {
76 | bytes := make([]byte, MagicSize)
77 | binary.BigEndian.PutUint32(bytes, uint32(i))
78 | return bytes
79 | }
80 |
81 | // Read read byte array
82 | func (h *Header) Read(bytes []byte) error {
83 | if bytes == nil || len(bytes) != SIZE {
84 | return nil
85 | }
86 | h.MagicCode = bytes[0:MagicSize]
87 | // message size offset 4 and 8
88 | h.MessageSize = int32(binary.BigEndian.Uint32(bytes[4:8]))
89 | // meta size offset 8 and 12
90 | h.MetaSize = int32(binary.BigEndian.Uint32(bytes[8:12]))
91 | return nil
92 | }
93 |
94 | func (h *Header) SetMagicCode(MagicCode []byte) {
95 | if MagicCode == nil || len(MagicCode) != MagicSize {
96 | return
97 | }
98 | h.MagicCode = MagicCode
99 | }
100 |
101 | func (h *Header) GetMagicCode() []byte {
102 | return h.MagicCode
103 | }
104 |
105 | func (h *Header) SetMessageSize(MessageSize int32) {
106 | h.MessageSize = MessageSize
107 | }
108 |
109 | func (h *Header) GetMessageSize() int32 {
110 | return h.MessageSize
111 | }
112 |
113 | func (h *Header) SetMetaSize(MetaSize int32) {
114 | h.MetaSize = MetaSize
115 | }
116 |
117 | func (h *Header) GetMetaSize() int32 {
118 | return h.MetaSize
119 | }
120 |
--------------------------------------------------------------------------------
/status_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-08-04 10:43:27
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | /*
22 | * @Author: Malin Xie
23 | * @Description:
24 | * @Date: 2021-08-04 10:43:27
25 | */
26 | package baidurpc_test
27 |
28 | import (
29 | "fmt"
30 | "reflect"
31 | "testing"
32 | "time"
33 |
34 | baidurpc "github.com/baidu-golang/pbrpc"
35 | . "github.com/smartystreets/goconvey/convey"
36 | "google.golang.org/protobuf/proto"
37 | )
38 |
39 | const (
40 | Default_Timeout = 10 * time.Second
41 | )
42 |
43 | // TestRpcStatus
44 | func TestRpcStatus(t *testing.T) {
45 | Convey("TestRpcStatus", t, func() {
46 | tcpServer := startRpcServer(0)
47 | defer stopRpcServer(tcpServer)
48 |
49 | serviceName := baidurpc.RPC_STATUS_SERVICENAME
50 | methodName := "Status"
51 |
52 | parameterOut := &baidurpc.RPCStatus{}
53 | err := sendRpc("localhost", PORT_1, serviceName, methodName, nil, parameterOut)
54 | So(err, ShouldBeNil)
55 | So(parameterOut.Port, ShouldEqual, PORT_1)
56 | echoservice := new(EchoService)
57 | tt := reflect.TypeOf(echoservice)
58 |
59 | So(len(parameterOut.Methods), ShouldEqual, tt.NumMethod()+2)
60 |
61 | })
62 | }
63 |
64 | // TestRpcRequestStatus
65 | func TestRpcRequestStatus(t *testing.T) {
66 | Convey("TestRpcStatus", t, func() {
67 | tcpServer := startRpcServer(0)
68 | defer stopRpcServer(tcpServer)
69 |
70 | serviceName := baidurpc.RPC_STATUS_SERVICENAME
71 | methodName := "QpsDataStatus"
72 |
73 | parameterOut := &baidurpc.QpsData{}
74 | parameterIn := &baidurpc.RPCMethod{Service: baidurpc.RPC_STATUS_SERVICENAME, Method: methodName}
75 | err := sendRpc("localhost", PORT_1, serviceName, methodName, parameterIn, parameterOut)
76 | So(err, ShouldBeNil)
77 |
78 | })
79 | }
80 |
81 | func sendRpc(host string, port int, serviceName, methodName string, parameterIn, parameterOut proto.Message) error {
82 | url := baidurpc.URL{}
83 | url.SetHost(&host).SetPort(&port)
84 |
85 | timeout := Default_Timeout
86 | connection, err := baidurpc.NewTCPConnection(url, &timeout)
87 | if err != nil {
88 | return err
89 | }
90 | defer connection.Close()
91 |
92 | // create client
93 | rpcClient, err := baidurpc.NewRpcCient(connection)
94 | if err != nil {
95 | return err
96 | }
97 |
98 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
99 | if parameterIn != nil {
100 | rpcInvocation.SetParameterIn(parameterIn)
101 | }
102 |
103 | rpcDataPackage, err := rpcClient.SendRpcRequest(rpcInvocation, parameterOut)
104 | if int(rpcDataPackage.Meta.GetResponse().ErrorCode) == baidurpc.ST_SERVICE_NOTFOUND {
105 | return fmt.Errorf("remote server not support this feature, please upgrade version")
106 | }
107 |
108 | return err
109 | }
110 |
--------------------------------------------------------------------------------
/haclient_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-04-26 18:18:59
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | package baidurpc_test
22 |
23 | import (
24 | "testing"
25 | "time"
26 |
27 | baidurpc "github.com/baidu-golang/pbrpc"
28 | . "github.com/smartystreets/goconvey/convey"
29 | "google.golang.org/protobuf/proto"
30 | )
31 |
32 | // TestHaClient test ha client
33 | func TestHaClient(t *testing.T) {
34 | Convey("TestSingleTcpConnectionClient", t, func() {
35 | tcpServer := startRpcServer(0)
36 | defer stopRpcServer(tcpServer)
37 |
38 | host := "localhost"
39 | timeout := time.Second * 5
40 | errPort := 100
41 | urls := []baidurpc.URL{{Host: &host, Port: &errPort}, {Host: &host, Port: Int(PORT_1)}}
42 |
43 | connections, err := baidurpc.NewBatchTCPConnection(urls, timeout)
44 | So(err, ShouldBeNil)
45 | defer baidurpc.CloseBatchConnection(connections)
46 |
47 | haClient, err := baidurpc.NewHaRpcCient(connections)
48 | So(err, ShouldBeNil)
49 | So(haClient, ShouldNotBeNil)
50 | defer haClient.Close()
51 |
52 | Convey("Test send request EchoService!echo", func() {
53 | doHaSimpleRPCInvokeWithSignatureWithConvey(haClient, "EchoService", "echo", false, false, false, false)
54 | })
55 | Convey("Test send request async EchoService!echo", func() {
56 | doHaSimpleRPCInvokeWithSignatureWithConvey(haClient, "EchoService", "echo", false, false, true, false)
57 | })
58 |
59 | })
60 | }
61 |
62 | // doSimpleRPCInvokeWithSignatureWithConvey send rpc request
63 | func doHaSimpleRPCInvokeWithSignatureWithConvey(rpcClient *baidurpc.HaRpcClient, serviceName, methodName string, withAttachement, withCustomErr, async, timeout bool) {
64 | Convey("Test Client send rpc request", func() {
65 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
66 |
67 | name := "马林"
68 | dm := DataMessage{Name: name}
69 |
70 | rpcInvocation.SetParameterIn(&dm)
71 | rpcInvocation.LogId = proto.Int64(1)
72 |
73 | if withAttachement {
74 | rpcInvocation.Attachment = []byte("This is attachment data")
75 | }
76 |
77 | parameterOut := DataMessage{}
78 | var response *baidurpc.RpcDataPackage
79 | var err error
80 | if async {
81 | response, err = rpcClient.SendRpcRequestWithTimeout(1*time.Second, rpcInvocation, ¶meterOut)
82 | if timeout {
83 | So(err, ShouldNotBeNil)
84 | return
85 | }
86 | } else {
87 | response, err = rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
88 | }
89 | if withCustomErr {
90 | So(err, ShouldNotBeNil)
91 | return
92 | } else {
93 | So(err, ShouldBeNil)
94 | }
95 | So(response, ShouldNotBeNil)
96 | expect := "hello " + name
97 | So(expect, ShouldEqual, parameterOut.Name)
98 |
99 | if withAttachement {
100 | So(string(response.Attachment), ShouldEqual, "I am a attachementThis is attachment data")
101 | }
102 |
103 | })
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/echoservice_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-08-03 14:08:57
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | /*
22 | * @Author: Malin Xie
23 | * @Description:
24 | * @Date: 2021-08-03 14:08:57
25 | */
26 | package baidurpc_test
27 |
28 | import (
29 | "context"
30 | "fmt"
31 | "time"
32 |
33 | baidurpc "github.com/baidu-golang/pbrpc"
34 | )
35 |
36 | // EchoService define service
37 | type EchoService struct {
38 | }
39 |
40 | // Echo test publish method with return type has context argument
41 | func (rpc *EchoService) Echo(c context.Context, in *DataMessage) (*DataMessage, context.Context) {
42 | var ret = "hello "
43 |
44 | if len(in.Name) == 0 {
45 | ret = ret + "veryone"
46 | } else {
47 | ret = ret + in.Name
48 | }
49 |
50 | // return result
51 | dm := DataMessage{Name: ret}
52 |
53 | // time.Sleep(50 * time.Second)
54 |
55 | // bind with err
56 | // cc = baidurpc.BindError(cc, errors.New("manule error"))
57 | return &dm, context.TODO()
58 | }
59 |
60 | // Echo test publish method with return type has context argument
61 | func (rpc *EchoService) EchoWithAttchement(c context.Context, in *DataMessage) (*DataMessage, context.Context) {
62 | var ret = "hello "
63 |
64 | // get attchement
65 | attachement := baidurpc.Attachement(c)
66 |
67 | if len(in.Name) == 0 {
68 | ret = ret + "veryone"
69 | } else {
70 | ret = ret + in.Name
71 | }
72 |
73 | // return result
74 | dm := DataMessage{Name: ret}
75 |
76 | att := "I am a attachement, " + string(attachement)
77 |
78 | // bind attachment
79 | cc := baidurpc.BindAttachement(context.Background(), []byte(att))
80 | return &dm, cc
81 | }
82 |
83 | // Echo test publish method with return type has context argument
84 | func (rpc *EchoService) EchoWithCustomizedError(c context.Context, in *DataMessage) (*DataMessage, context.Context) {
85 | var ret = "hello "
86 |
87 | if len(in.Name) == 0 {
88 | ret = ret + "veryone"
89 | } else {
90 | ret = ret + in.Name
91 | }
92 |
93 | // return result
94 | dm := DataMessage{Name: ret}
95 |
96 | // bind with err
97 | cc := baidurpc.BindError(context.Background(), fmt.Errorf("this is customized error"))
98 | return &dm, cc
99 | }
100 |
101 | // Echo test publish method with return type has context argument
102 | func (rpc *EchoService) EchoWithoutContext(c context.Context, in *DataMessage) *DataMessage {
103 | var ret = "hello "
104 |
105 | if len(in.Name) == 0 {
106 | ret = ret + "veryone"
107 | } else {
108 | ret = ret + in.Name
109 | }
110 |
111 | // return result
112 | dm := DataMessage{Name: ret}
113 |
114 | return &dm
115 | }
116 |
117 | // Echo test publish method with return type has context argument
118 | func (rpc *EchoService) EchoSlowTest(c context.Context, in *DataMessage) *DataMessage {
119 | var ret = "hello "
120 |
121 | time.Sleep(2 * time.Second)
122 | if len(in.Name) == 0 {
123 | ret = ret + "veryone"
124 | } else {
125 | ret = ret + in.Name
126 | }
127 |
128 | // return result
129 | dm := DataMessage{Name: ret}
130 |
131 | return &dm
132 | }
133 |
--------------------------------------------------------------------------------
/example/client_example_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | /*
17 | * @Author: Malin Xie
18 | * @Description:
19 | * @Date: 2021-08-03 19:12:14
20 | */
21 | package example
22 |
23 | import (
24 | "fmt"
25 | "time"
26 |
27 | baidurpc "github.com/baidu-golang/pbrpc"
28 | pool "github.com/jolestar/go-commons-pool/v2"
29 | "google.golang.org/protobuf/proto"
30 | )
31 |
32 | // ExampleTcpClient
33 | func ExampleTcpClient() {
34 |
35 | host := "localhost"
36 | port := 1031
37 |
38 | url := baidurpc.URL{}
39 | url.SetHost(&host).SetPort(&port)
40 |
41 | timeout := time.Second * 5
42 | // create client by connection pool
43 | connection, err := baidurpc.NewTCPConnection(url, &timeout)
44 | if err != nil {
45 | return
46 | }
47 | defer connection.Close()
48 |
49 | // create client
50 | rpcClient, err := baidurpc.NewRpcCient(connection)
51 | if err != nil {
52 | return
53 | }
54 | defer rpcClient.Close()
55 |
56 | serviceName := "echoService"
57 | methodName := "echo"
58 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
59 |
60 | message := "say hello from xiemalin中文测试"
61 | dm := DataMessage{Name: message}
62 |
63 | rpcInvocation.SetParameterIn(&dm)
64 | rpcInvocation.LogId = proto.Int64(1)
65 | rpcInvocation.Attachment = []byte("hello world")
66 |
67 | parameterOut := DataMessage{}
68 |
69 | response, err := rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
70 | if err != nil {
71 | return
72 | }
73 |
74 | if response == nil {
75 | fmt.Println("Reponse is nil")
76 | return
77 | }
78 |
79 | fmt.Println("attachement", response.Attachment)
80 |
81 | }
82 |
83 | // ExampleTcpClient
84 | func ExamplePooledTcpClient() {
85 |
86 | host := "localhost"
87 | port := 1031
88 |
89 | url := baidurpc.URL{}
90 | url.SetHost(&host).SetPort(&port)
91 |
92 | timeout := time.Second * 5
93 |
94 | parell := 2
95 |
96 | // create client by connection pool
97 | config := pool.NewDefaultPoolConfig()
98 | config.MaxTotal = parell
99 | config.MaxIdle = parell
100 |
101 | // create client by connection pool
102 | connection, err := baidurpc.NewTCPConnectionPool(url, &timeout, config)
103 | if err != nil {
104 | return
105 | }
106 | defer connection.Close()
107 |
108 | // create client
109 | rpcClient, err := baidurpc.NewRpcCient(connection)
110 | if err != nil {
111 | return
112 | }
113 | defer rpcClient.Close()
114 |
115 | serviceName := "echoService"
116 | methodName := "echo"
117 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
118 |
119 | message := "say hello from xiemalin中文测试"
120 | dm := DataMessage{Name: message}
121 |
122 | rpcInvocation.SetParameterIn(&dm)
123 | rpcInvocation.LogId = proto.Int64(1)
124 | rpcInvocation.Attachment = []byte("hello world")
125 |
126 | parameterOut := DataMessage{}
127 |
128 | response, err := rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
129 | if err != nil {
130 | return
131 | }
132 |
133 | if response == nil {
134 | fmt.Println("Reponse is nil")
135 | return
136 | }
137 |
138 | fmt.Println("attachement", response.Attachment)
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
5 | github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
6 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
7 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
8 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
9 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
10 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
11 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
12 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
13 | github.com/jhunters/goassist v1.0.9 h1:YBkUxjVFiyYWchWP1gR/zXAx7NZIUggW600ppuKNxXo=
14 | github.com/jhunters/goassist v1.0.9/go.mod h1:xswAjXTwkXnAa/qoO0F47I6AFuFPIh77ywU0TumWLUc=
15 | github.com/jhunters/link v0.0.0-20221207123848-6322292415b2 h1:rb4UVfWWSBGu84ytzQxSrmeHK0DXCnEAfAvlKw3bk7M=
16 | github.com/jhunters/link v0.0.0-20221207123848-6322292415b2/go.mod h1:4kSwKnKlQVeqldrX+9V3Zoiu9Pc0Wd4KoAD766GbolY=
17 | github.com/jhunters/timewheel v1.1.0 h1:3iNVpT9C/0sejAM+URlQS8dgvipwmkxkZWyILKH0Al8=
18 | github.com/jhunters/timewheel v1.1.0/go.mod h1:vpcvhzktGWnQuL9x+zGA32JP4ZybJEV44cRCWY/TYQ8=
19 | github.com/jolestar/go-commons-pool/v2 v2.1.1 h1:KrbCEvx5KhwcHzLTWIE8SJJQL7zzNto5in+wnO9/gSA=
20 | github.com/jolestar/go-commons-pool/v2 v2.1.1/go.mod h1:kTOzcguO2zUoEd+BySdg7Xhk/YE0HEr2bAHdWDkhMXg=
21 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
22 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
23 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
24 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
25 | github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
26 | github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
27 | github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
28 | github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
29 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
30 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
31 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
32 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
33 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
34 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
35 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
36 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
37 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
38 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
39 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
40 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
41 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
42 | google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
43 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
44 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
45 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
46 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
47 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
48 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
49 |
--------------------------------------------------------------------------------
/httpserver_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-08-20 17:16:06
5 | */
6 | package baidurpc_test
7 |
8 | import (
9 | "bytes"
10 | "encoding/json"
11 | "io"
12 | "io/ioutil"
13 | "net/http"
14 | "net/url"
15 | "strconv"
16 | "testing"
17 |
18 | baidurpc "github.com/baidu-golang/pbrpc"
19 | . "github.com/smartystreets/goconvey/convey"
20 | )
21 |
22 | // TestHttpRpcServerWithPath
23 | func TestHttpRpcServerWithPath(t *testing.T) {
24 | Convey("test http mode with service not found", t, func() {
25 |
26 | tcpServer := startRpcServerWithHttpMode(0, true)
27 | defer stopRpcServer(tcpServer)
28 |
29 | Convey("test http mode with bad prefix path", func() {
30 | sport := strconv.Itoa(PORT_1)
31 | urlpath := "http://localhost:" + sport + "/badpath/EchoService/echo"
32 | paramters := map[string]string{}
33 | headers := map[string]string{}
34 |
35 | result := sendHttpRequest(urlpath, "POST", "{\"name\":\"matt\"}", paramters, headers)
36 | So(result, ShouldNotBeNil)
37 | data := &baidurpc.ResponseData{}
38 | err := json.Unmarshal(result, data)
39 | So(err, ShouldBeNil)
40 | So(data.ErrNo, ShouldEqual, baidurpc.ST_SERVICE_NOTFOUND)
41 | })
42 |
43 | Convey("test http mode with bad service and method path", func() {
44 | sport := strconv.Itoa(PORT_1)
45 | urlpath := "http://localhost:" + sport + "/rpc/BadService/BadMethod"
46 | paramters := map[string]string{}
47 | headers := map[string]string{}
48 |
49 | result := sendHttpRequest(urlpath, "POST", "{\"name\":\"matt\"}", paramters, headers)
50 | So(result, ShouldNotBeNil)
51 | data := &baidurpc.ResponseData{}
52 | err := json.Unmarshal(result, data)
53 | So(err, ShouldBeNil)
54 | So(data.ErrNo, ShouldEqual, baidurpc.ST_SERVICE_NOTFOUND)
55 | })
56 |
57 | })
58 | }
59 |
60 | // TestHttpRpcServer
61 | func TestHttpRpcServer(t *testing.T) {
62 | Convey("test http rpc with common request", t, func() {
63 |
64 | tcpServer := startRpcServerWithHttpMode(0, true)
65 | defer stopRpcServer(tcpServer)
66 |
67 | sport := strconv.Itoa(PORT_1)
68 | urlpath := "http://localhost:" + sport + "/rpc/EchoService/echo"
69 | paramters := map[string]string{}
70 | headers := map[string]string{}
71 |
72 | result := sendHttpRequest(urlpath, "POST", "{\"name\":\"matt\"}", paramters, headers)
73 |
74 | So(result, ShouldNotBeNil)
75 | data := &baidurpc.ResponseData{}
76 | err := json.Unmarshal(result, data)
77 | So(err, ShouldBeNil)
78 | So(data.ErrNo, ShouldEqual, 0)
79 |
80 | })
81 | }
82 |
83 | // TestHttpRpcServerWithAuthenticate
84 | func TestHttpRpcServerWithAuthenticate(t *testing.T) {
85 | Convey("test http rpc with authenticate", t, func() {
86 |
87 | tcpServer := startRpcServerWithHttpMode(0, true)
88 | tcpServer.SetAuthService(new(StringMatchAuthService))
89 | tcpServer.SetTraceService(new(AddOneTraceService))
90 | defer stopRpcServer(tcpServer)
91 |
92 | sport := strconv.Itoa(PORT_1)
93 | urlpath := "http://localhost:" + sport + "/rpc/EchoService/echo"
94 | paramters := map[string]string{}
95 | headers := map[string]string{}
96 | headers[baidurpc.Auth_key] = AUTH_TOKEN
97 | headers[baidurpc.LogId_key] = "1"
98 |
99 | headers[baidurpc.Trace_Id_key] = "1"
100 | headers[baidurpc.Trace_Span_key] = "2"
101 | headers[baidurpc.Trace_Parent_key] = "3"
102 |
103 | result := sendHttpRequest(urlpath, "POST", "{\"name\":\"matt\"}", paramters, headers)
104 |
105 | So(result, ShouldNotBeNil)
106 | data := &baidurpc.ResponseData{}
107 | err := json.Unmarshal(result, data)
108 | So(err, ShouldBeNil)
109 | So(data.ErrNo, ShouldEqual, 0)
110 |
111 | })
112 | }
113 |
114 | func sendHttpRequest(urlpath, method, body string, paramters, headers map[string]string) []byte {
115 | params := url.Values{}
116 | Url, err := url.Parse(urlpath)
117 | if err != nil {
118 | return nil
119 | }
120 |
121 | for k, v := range paramters {
122 | params.Set(k, v)
123 | }
124 |
125 | urlPath := Url.String()
126 |
127 | client := &http.Client{}
128 | req, _ := http.NewRequest(method, urlPath, nil)
129 |
130 | data := []byte(body)
131 | bs := bytes.NewBuffer(data)
132 | req.ContentLength = int64(len(data))
133 | // buf := body.Bytes()
134 | req.GetBody = func() (io.ReadCloser, error) {
135 | r := bytes.NewReader(data)
136 | return ioutil.NopCloser(r), nil
137 | }
138 |
139 | req.Body = ioutil.NopCloser(bs)
140 |
141 | for k, v := range headers {
142 | req.Header.Add(k, v)
143 | }
144 |
145 | resp, _ := client.Do(req)
146 | rbody, _ := ioutil.ReadAll(resp.Body)
147 |
148 | return rbody
149 | }
150 |
--------------------------------------------------------------------------------
/datamessage_test.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // versions:
3 | // protoc-gen-go v1.26.0
4 | // protoc v3.9.2
5 | // source: DataMessage.proto
6 |
7 | package baidurpc_test
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 | type DataMessage struct {
24 | state protoimpl.MessageState
25 | sizeCache protoimpl.SizeCache
26 | unknownFields protoimpl.UnknownFields
27 |
28 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
29 | }
30 |
31 | func (x *DataMessage) Reset() {
32 | *x = DataMessage{}
33 | if protoimpl.UnsafeEnabled {
34 | mi := &file_DataMessage_proto_msgTypes[0]
35 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
36 | ms.StoreMessageInfo(mi)
37 | }
38 | }
39 |
40 | func (x *DataMessage) String() string {
41 | return protoimpl.X.MessageStringOf(x)
42 | }
43 |
44 | func (*DataMessage) ProtoMessage() {}
45 |
46 | func (x *DataMessage) ProtoReflect() protoreflect.Message {
47 | mi := &file_DataMessage_proto_msgTypes[0]
48 | if protoimpl.UnsafeEnabled && x != nil {
49 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
50 | if ms.LoadMessageInfo() == nil {
51 | ms.StoreMessageInfo(mi)
52 | }
53 | return ms
54 | }
55 | return mi.MessageOf(x)
56 | }
57 |
58 | // Deprecated: Use DataMessage.ProtoReflect.Descriptor instead.
59 | func (*DataMessage) Descriptor() ([]byte, []int) {
60 | return file_DataMessage_proto_rawDescGZIP(), []int{0}
61 | }
62 |
63 | func (x *DataMessage) GetName() string {
64 | if x != nil {
65 | return x.Name
66 | }
67 | return ""
68 | }
69 |
70 | var File_DataMessage_proto protoreflect.FileDescriptor
71 |
72 | var file_DataMessage_proto_rawDesc = []byte{
73 | 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
74 | 0x6f, 0x74, 0x6f, 0x22, 0x21, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61,
75 | 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
76 | 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x1f, 0x5a, 0x1d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
77 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x69, 0x64, 0x75, 0x2d, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
78 | 0x67, 0x2f, 0x70, 0x62, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
79 | }
80 |
81 | var (
82 | file_DataMessage_proto_rawDescOnce sync.Once
83 | file_DataMessage_proto_rawDescData = file_DataMessage_proto_rawDesc
84 | )
85 |
86 | func file_DataMessage_proto_rawDescGZIP() []byte {
87 | file_DataMessage_proto_rawDescOnce.Do(func() {
88 | file_DataMessage_proto_rawDescData = protoimpl.X.CompressGZIP(file_DataMessage_proto_rawDescData)
89 | })
90 | return file_DataMessage_proto_rawDescData
91 | }
92 |
93 | var file_DataMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
94 | var file_DataMessage_proto_goTypes = []interface{}{
95 | (*DataMessage)(nil), // 0: DataMessage
96 | }
97 | var file_DataMessage_proto_depIdxs = []int32{
98 | 0, // [0:0] is the sub-list for method output_type
99 | 0, // [0:0] is the sub-list for method input_type
100 | 0, // [0:0] is the sub-list for extension type_name
101 | 0, // [0:0] is the sub-list for extension extendee
102 | 0, // [0:0] is the sub-list for field type_name
103 | }
104 |
105 | func init() { file_DataMessage_proto_init() }
106 | func file_DataMessage_proto_init() {
107 | if File_DataMessage_proto != nil {
108 | return
109 | }
110 | if !protoimpl.UnsafeEnabled {
111 | file_DataMessage_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
112 | switch v := v.(*DataMessage); i {
113 | case 0:
114 | return &v.state
115 | case 1:
116 | return &v.sizeCache
117 | case 2:
118 | return &v.unknownFields
119 | default:
120 | return nil
121 | }
122 | }
123 | }
124 | type x struct{}
125 | out := protoimpl.TypeBuilder{
126 | File: protoimpl.DescBuilder{
127 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
128 | RawDescriptor: file_DataMessage_proto_rawDesc,
129 | NumEnums: 0,
130 | NumMessages: 1,
131 | NumExtensions: 0,
132 | NumServices: 0,
133 | },
134 | GoTypes: file_DataMessage_proto_goTypes,
135 | DependencyIndexes: file_DataMessage_proto_depIdxs,
136 | MessageInfos: file_DataMessage_proto_msgTypes,
137 | }.Build()
138 | File_DataMessage_proto = out.File
139 | file_DataMessage_proto_rawDesc = nil
140 | file_DataMessage_proto_goTypes = nil
141 | file_DataMessage_proto_depIdxs = nil
142 | }
143 |
--------------------------------------------------------------------------------
/example/pb_example_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | /*
17 | * @Author: Malin Xie
18 | * @Description:
19 | * @Date: 2021-08-03 19:24:19
20 | */
21 | package example
22 |
23 | import (
24 | reflect "reflect"
25 | sync "sync"
26 |
27 | protoreflect "google.golang.org/protobuf/reflect/protoreflect"
28 | protoimpl "google.golang.org/protobuf/runtime/protoimpl"
29 | )
30 |
31 | const (
32 | // Verify that this generated code is sufficiently up-to-date.
33 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
34 | // Verify that runtime/protoimpl is sufficiently up-to-date.
35 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
36 | )
37 |
38 | type DataMessage struct {
39 | state protoimpl.MessageState
40 | sizeCache protoimpl.SizeCache
41 | unknownFields protoimpl.UnknownFields
42 |
43 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
44 | }
45 |
46 | func (x *DataMessage) Reset() {
47 | *x = DataMessage{}
48 | if protoimpl.UnsafeEnabled {
49 | mi := &file_DataMessage_proto_msgTypes[0]
50 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
51 | ms.StoreMessageInfo(mi)
52 | }
53 | }
54 |
55 | func (x *DataMessage) String() string {
56 | return protoimpl.X.MessageStringOf(x)
57 | }
58 |
59 | func (*DataMessage) ProtoMessage() {}
60 |
61 | func (x *DataMessage) ProtoReflect() protoreflect.Message {
62 | mi := &file_DataMessage_proto_msgTypes[0]
63 | if protoimpl.UnsafeEnabled && x != nil {
64 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
65 | if ms.LoadMessageInfo() == nil {
66 | ms.StoreMessageInfo(mi)
67 | }
68 | return ms
69 | }
70 | return mi.MessageOf(x)
71 | }
72 |
73 | // Deprecated: Use DataMessage.ProtoReflect.Descriptor instead.
74 | func (*DataMessage) Descriptor() ([]byte, []int) {
75 | return file_DataMessage_proto_rawDescGZIP(), []int{0}
76 | }
77 |
78 | func (x *DataMessage) GetName() string {
79 | if x != nil {
80 | return x.Name
81 | }
82 | return ""
83 | }
84 |
85 | var File_DataMessage_proto protoreflect.FileDescriptor
86 |
87 | var file_DataMessage_proto_rawDesc = []byte{
88 | 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
89 | 0x6f, 0x74, 0x6f, 0x22, 0x21, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61,
90 | 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
91 | 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x1f, 0x5a, 0x1d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
92 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x69, 0x64, 0x75, 0x2d, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
93 | 0x67, 0x2f, 0x70, 0x62, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
94 | }
95 |
96 | var (
97 | file_DataMessage_proto_rawDescOnce sync.Once
98 | file_DataMessage_proto_rawDescData = file_DataMessage_proto_rawDesc
99 | )
100 |
101 | func file_DataMessage_proto_rawDescGZIP() []byte {
102 | file_DataMessage_proto_rawDescOnce.Do(func() {
103 | file_DataMessage_proto_rawDescData = protoimpl.X.CompressGZIP(file_DataMessage_proto_rawDescData)
104 | })
105 | return file_DataMessage_proto_rawDescData
106 | }
107 |
108 | var file_DataMessage_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
109 | var file_DataMessage_proto_goTypes = []interface{}{
110 | (*DataMessage)(nil), // 0: DataMessage
111 | }
112 | var file_DataMessage_proto_depIdxs = []int32{
113 | 0, // [0:0] is the sub-list for method output_type
114 | 0, // [0:0] is the sub-list for method input_type
115 | 0, // [0:0] is the sub-list for extension type_name
116 | 0, // [0:0] is the sub-list for extension extendee
117 | 0, // [0:0] is the sub-list for field type_name
118 | }
119 |
120 | func init() { file_DataMessage_proto_init() }
121 | func file_DataMessage_proto_init() {
122 | if File_DataMessage_proto != nil {
123 | return
124 | }
125 | if !protoimpl.UnsafeEnabled {
126 | file_DataMessage_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
127 | switch v := v.(*DataMessage); i {
128 | case 0:
129 | return &v.state
130 | case 1:
131 | return &v.sizeCache
132 | case 2:
133 | return &v.unknownFields
134 | default:
135 | return nil
136 | }
137 | }
138 | }
139 | type x struct{}
140 | out := protoimpl.TypeBuilder{
141 | File: protoimpl.DescBuilder{
142 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
143 | RawDescriptor: file_DataMessage_proto_rawDesc,
144 | NumEnums: 0,
145 | NumMessages: 1,
146 | NumExtensions: 0,
147 | NumServices: 0,
148 | },
149 | GoTypes: file_DataMessage_proto_goTypes,
150 | DependencyIndexes: file_DataMessage_proto_depIdxs,
151 | MessageInfos: file_DataMessage_proto_msgTypes,
152 | }.Build()
153 | File_DataMessage_proto = out.File
154 | file_DataMessage_proto_rawDesc = nil
155 | file_DataMessage_proto_goTypes = nil
156 | file_DataMessage_proto_depIdxs = nil
157 | }
158 |
--------------------------------------------------------------------------------
/server_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc_test
17 |
18 | import (
19 | "context"
20 | "errors"
21 | "testing"
22 | "time"
23 |
24 | baidurpc "github.com/baidu-golang/pbrpc"
25 | . "github.com/smartystreets/goconvey/convey"
26 | "google.golang.org/protobuf/proto"
27 | )
28 |
29 | const (
30 | PORT_1 = 1031
31 | PORT_2 = 1032
32 | PORT_3 = 1033
33 |
34 | Shutdown_Timeout = time.Second
35 | )
36 |
37 | // createRpcServer create rpc server by port and localhost
38 | func createRpcServer(port int) *baidurpc.TcpServer {
39 | serverMeta := baidurpc.ServerMeta{}
40 | serverMeta.Port = Int(port)
41 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
42 | return rpcServer
43 | }
44 |
45 | type CustomAuthService struct {
46 | }
47 |
48 | // Authenticate
49 | func (as *CustomAuthService) Authenticate(service, name string, authToken []byte) bool {
50 | return true
51 | }
52 |
53 | // TestServerWithAuthenticate
54 | func TestServerWithAuthenticate(t *testing.T) {
55 | Convey("TestServerWithoutPublishMethods", t, func() {
56 |
57 | rpcServer := createRpcServer(PORT_2)
58 | authservice := new(CustomAuthService)
59 | rpcServer.SetAuthService(authservice)
60 | err := rpcServer.Start()
61 | So(err, ShouldBeNil)
62 | stopRpcServer(rpcServer)
63 | So(err, ShouldBeNil)
64 | })
65 | }
66 |
67 | // TestServerWithoutPublishMethods
68 | func TestServerWithoutPublishMethods(t *testing.T) {
69 | Convey("TestServerWithoutPublishMethods", t, func() {
70 |
71 | rpcServer := createRpcServer(PORT_2)
72 | err := rpcServer.Start()
73 | So(err, ShouldBeNil)
74 | stopRpcServer(rpcServer)
75 | So(err, ShouldBeNil)
76 | })
77 | }
78 |
79 | // TestServerWithPublishMethods
80 | func TestServerWithPublishMethods(t *testing.T) {
81 | Convey("TestServerWithoutPublishMethods", t, func() {
82 |
83 | Convey("publish method with RegisterName", func() {
84 | rpcServer := createRpcServer(PORT_2)
85 |
86 | echoservice := new(EchoService)
87 | rpcServer.RegisterName("EchoService", echoservice)
88 |
89 | err := rpcServer.Start()
90 | So(err, ShouldBeNil)
91 | stopRpcServer(rpcServer)
92 | So(err, ShouldBeNil)
93 | })
94 |
95 | Convey("publish method with RegisterNameWithMethodMapping", func() {
96 | rpcServer := createRpcServer(PORT_2)
97 |
98 | echoservice := new(EchoService)
99 | methodMapping := map[string]string{
100 | "Echo": "echo",
101 | "EchoWithAttchement": "echoWithAttchement",
102 | "EchoWithCustomizedError": "echoWithCustomizedError",
103 | "EchoWithoutContext": "echoWithoutContext",
104 | }
105 | rpcServer.RegisterNameWithMethodMapping("EchoService", echoservice, methodMapping)
106 |
107 | err := rpcServer.Start()
108 | So(err, ShouldBeNil)
109 | stopRpcServer(rpcServer)
110 | So(err, ShouldBeNil)
111 | })
112 |
113 | })
114 | }
115 |
116 | // SimpleService
117 | type SimpleService struct {
118 | serviceName string
119 | methodName string
120 | }
121 |
122 | // NewSimpleService create RPC service
123 | func NewSimpleService(serviceName, methodName string) *SimpleService {
124 | ret := SimpleService{serviceName, methodName}
125 | return &ret
126 | }
127 |
128 | func (ss *SimpleService) DoService(msg proto.Message, attachment []byte, logId *int64) (proto.Message, []byte, error) {
129 | var ret = "hello "
130 |
131 | if msg != nil {
132 |
133 | var name string
134 |
135 | m, ok := msg.(*DataMessage)
136 | if !ok {
137 | errStr := "message type is not type of 'DataMessage'"
138 | return nil, nil, errors.New(errStr)
139 | }
140 | name = m.Name
141 |
142 | if len(name) == 0 {
143 | ret = ret + "veryone"
144 | } else {
145 | ret = ret + name
146 | }
147 | }
148 | dm := DataMessage{}
149 | dm.Name = ret
150 | return &dm, []byte{1, 5, 9}, nil
151 |
152 | }
153 |
154 | func (ss *SimpleService) GetServiceName() string {
155 | return ss.serviceName
156 | }
157 |
158 | func (ss *SimpleService) GetMethodName() string {
159 | return ss.methodName
160 | }
161 |
162 | func (ss *SimpleService) NewParameter() proto.Message {
163 | ret := DataMessage{}
164 | return &ret
165 | }
166 |
167 | // TestServerWithOldRegisterWay
168 | func TestServerWithOldRegisterWay(t *testing.T) {
169 |
170 | Convey("TestServerWithOldRegisterWay", t, func() {
171 | rpcServer := createRpcServer(PORT_3)
172 | So(rpcServer, ShouldNotBeNil)
173 |
174 | service := NewSimpleService("OldService", "OldMethod")
175 | rpcServer.Register(service)
176 |
177 | err := rpcServer.Start()
178 | So(err, ShouldBeNil)
179 | stopRpcServer(rpcServer)
180 | So(err, ShouldBeNil)
181 | })
182 |
183 | }
184 |
185 | func stopRpcServer(rpcServer *baidurpc.TcpServer) {
186 | timeContext, _ := context.WithTimeout(context.Background(), Shutdown_Timeout)
187 | rpcServer.Stop(timeContext)
188 | }
189 |
190 | // Int convert to pointer type of int
191 | func Int(v int) *int {
192 | p := new(int)
193 | *p = int(v)
194 | return p
195 | }
196 |
--------------------------------------------------------------------------------
/example/server_example_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-08-03 19:30:12
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | /*
22 | * @Author: Malin Xie
23 | * @Description:
24 | * @Date: 2021-08-03 19:12:14
25 | */
26 | package example
27 |
28 | import (
29 | "context"
30 | "errors"
31 | "fmt"
32 | "log"
33 | "net"
34 | "net/rpc"
35 | "reflect"
36 | "strings"
37 | "time"
38 |
39 | baidurpc "github.com/baidu-golang/pbrpc"
40 | "google.golang.org/protobuf/proto"
41 | )
42 |
43 | const (
44 | Shutdown_Timeout = time.Second
45 | )
46 |
47 | // ExampleRpcServer
48 | func ExampleRpcServer() {
49 | port := 1031
50 |
51 | serverMeta := baidurpc.ServerMeta{}
52 | serverMeta.QPSExpireInSecs = 600 // set qps monitor expire time
53 | serverMeta.Port = &port
54 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
55 |
56 | echoService := new(EchoService)
57 |
58 | mapping := make(map[string]string)
59 | mapping["Echo"] = "echo"
60 | rpcServer.RegisterNameWithMethodMapping("echoService", echoService, mapping)
61 |
62 | rpcServer.Start()
63 | defer stopRpcServer(rpcServer)
64 |
65 | }
66 |
67 | func ExampleRpcServerWithHttp() {
68 | port := 1031
69 |
70 | serverMeta := baidurpc.ServerMeta{}
71 | serverMeta.QPSExpireInSecs = 600 // set qps monitor expire time
72 | serverMeta.Port = &port
73 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
74 |
75 | echoService := new(EchoService)
76 |
77 | mapping := make(map[string]string)
78 | mapping["Echo"] = "echo"
79 | rpcServer.RegisterNameWithMethodMapping("echoService", echoService, mapping)
80 |
81 | // start http rpc mode
82 | rpcServer.EnableHttp()
83 | rpcServer.Start()
84 | defer stopRpcServer(rpcServer)
85 |
86 | }
87 |
88 | // ExampleRpcServerWithListener
89 | func ExampleRpcServerWithListener() {
90 | serverMeta := baidurpc.ServerMeta{}
91 | serverMeta.QPSExpireInSecs = 600 // set qps monitor expire time
92 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
93 |
94 | echoService := new(EchoService)
95 |
96 | mapping := make(map[string]string)
97 | mapping["Echo"] = "echo"
98 | rpcServer.RegisterNameWithMethodMapping("echoService", echoService, mapping)
99 |
100 | addr := ":1031"
101 | listener, err := net.Listen("tcp", addr)
102 | if err != nil {
103 | return
104 | }
105 | rpcServer.StartServer(listener)
106 | defer stopRpcServer(rpcServer)
107 |
108 | }
109 |
110 | // ExampleRpcServerWithListener
111 | func ExampleRpcServerRegisterWithCallback() {
112 | serverMeta := baidurpc.ServerMeta{}
113 | serverMeta.QPSExpireInSecs = 600 // set qps monitor expire time
114 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
115 |
116 | callback := func(msg proto.Message, attachment []byte, logId *int64) (proto.Message, []byte, error) {
117 | var ret = "hello "
118 |
119 | if msg != nil {
120 | t := reflect.TypeOf(msg)
121 |
122 | if !strings.Contains(t.String(), "DataMessage") {
123 | errStr := "message type is not type of 'DataMessage'" + t.String()
124 | return nil, nil, errors.New(errStr)
125 | }
126 |
127 | var name string
128 |
129 | m := msg.(*DataMessage)
130 | name = m.Name
131 |
132 | if len(name) == 0 {
133 | ret = ret + "veryone"
134 | } else {
135 | ret = ret + name
136 | }
137 | }
138 | dm := DataMessage{}
139 | dm.Name = ret
140 | return &dm, []byte{1, 5, 9}, nil
141 | }
142 |
143 | rpcServer.RegisterRpc("echoService", "echo", callback, &DataMessage{})
144 |
145 | rpcServer.Start()
146 | defer stopRpcServer(rpcServer)
147 |
148 | }
149 |
150 | type EchoService struct {
151 | }
152 |
153 | // Echo test publish method with return type has context argument
154 | func (rpc *EchoService) Echo(c context.Context, in *DataMessage) (*DataMessage, context.Context) {
155 | var ret = "hello "
156 |
157 | attachement := baidurpc.Attachement(c)
158 | fmt.Println("attachement", attachement)
159 |
160 | if len(in.Name) == 0 {
161 | ret = ret + "veryone"
162 | } else {
163 | ret = ret + in.Name
164 | }
165 | dm := DataMessage{}
166 | dm.Name = ret
167 |
168 | // bind attachment
169 | cc := baidurpc.BindAttachement(context.Background(), []byte("hello"))
170 | // bind with err
171 | // cc = baidurpc.BindError(cc, errors.New("manule error"))
172 | return &dm, cc
173 | }
174 |
175 | type HelloService struct{}
176 |
177 | func (p *HelloService) Hello(request string, reply *string) error {
178 | *reply = "hello:" + request
179 | return nil
180 | }
181 |
182 | func DoRPCServer() {
183 | fmt.Println("server starting...")
184 | rpc.RegisterName("HelloService", new(HelloService)) // 注册RPC, RPC名称为 HelloService
185 |
186 | listener, err := net.Listen("tcp", ":1234")
187 | if err != nil {
188 | log.Fatal("ListenTCP error:", err)
189 | }
190 |
191 | conn, err := listener.Accept()
192 | if err != nil {
193 | log.Fatal("Accept error:", err)
194 | }
195 |
196 | rpc.ServeConn(conn) // 绑定tcp服务链接
197 |
198 | fmt.Println("server started.")
199 | }
200 |
201 | func stopRpcServer(rpcServer *baidurpc.TcpServer) {
202 | timeContext, _ := context.WithTimeout(context.Background(), Shutdown_Timeout)
203 | rpcServer.Stop(timeContext)
204 | }
205 |
--------------------------------------------------------------------------------
/status.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | /*
17 | * @Author: Malin Xie
18 | * @Description:
19 | * @Date: 2021-07-26 17:09:25
20 | */
21 | package baidurpc
22 |
23 | import (
24 | "context"
25 | "encoding/json"
26 | "fmt"
27 | "time"
28 |
29 | "github.com/jhunters/timewheel"
30 | )
31 |
32 | // HttpStatusView
33 | type HttpStatusView struct {
34 | server *TcpServer
35 | }
36 |
37 | func (hsv *HttpStatusView) Status(c context.Context) (*RPCStatus, context.Context) {
38 | s := hsv.server
39 | result := &RPCStatus{}
40 | if s.serverMeta.Host != nil {
41 | result.Host = *s.serverMeta.Host
42 | }
43 | if s.serverMeta.Port != nil {
44 | result.Port = int32(*s.serverMeta.Port)
45 | }
46 | if s.serverMeta.IdleTimeoutSeconds != nil {
47 | result.TimeoutSenconds = int32(*s.serverMeta.IdleTimeoutSeconds)
48 | }
49 |
50 | rpcServices := s.services
51 | methods := make([]*RPCMethod, len(rpcServices))
52 | var i int = 0
53 | for sname, service := range rpcServices {
54 | m := &RPCMethod{Service: service.GetServiceName(), Method: service.GetMethodName()}
55 | // query meta info
56 | serviceMeta, ok := s.servicesMeta[sname]
57 | if ok {
58 | if serviceMeta.InPbFieldMetas != nil {
59 | metaString, _ := json.Marshal(serviceMeta.InPbFieldMetas)
60 | m.InTypeMeta = string(metaString)
61 | }
62 | if serviceMeta.RetrunPbFieldMetas != nil {
63 | metaString, _ := json.Marshal(serviceMeta.RetrunPbFieldMetas)
64 | m.ReturnTypeMeta = string(metaString)
65 | }
66 | }
67 |
68 | methods[i] = m
69 | i++
70 | }
71 | result.Methods = methods
72 | return result, c
73 | }
74 |
75 | func (hsv *HttpStatusView) QpsDataStatus(c context.Context, method *RPCMethod) (*QpsData, context.Context) {
76 | serviceId := GetServiceId(method.Service, method.Method)
77 | ret := &QpsData{Qpsinfo: make(map[int64]int32)}
78 | requestStatus, ok := hsv.server.requestStatus.Methods[serviceId]
79 | if ok {
80 | ret.Qpsinfo = requestStatus.QpsStatus
81 | }
82 | // add current current
83 | ret.Qpsinfo[time.Now().Unix()] += 0
84 | return ret, c
85 | }
86 |
87 | // RPCRequestStatus
88 | type RPCRequestStatus struct {
89 | Methods map[string]*RPCMethodReuqestStatus
90 |
91 | reqeustChan chan request
92 |
93 | closeChan chan bool
94 |
95 | expireAfterSecs int16
96 |
97 | started bool
98 |
99 | tw *timewheel.TimeWheel[request]
100 | }
101 |
102 | type request struct {
103 | method string
104 | t time.Time
105 | count int
106 | }
107 |
108 | // RPCMethodReuqestStatus
109 | type RPCMethodReuqestStatus struct {
110 | QpsStatus map[int64]int32
111 | }
112 |
113 | // NewRPCRequestStatus
114 | func NewRPCRequestStatus(services map[string]Service) *RPCRequestStatus {
115 | ret := &RPCRequestStatus{
116 | Methods: make(map[string]*RPCMethodReuqestStatus, len(services)),
117 | reqeustChan: make(chan request, 1024),
118 | closeChan: make(chan bool),
119 | }
120 |
121 | for name := range services {
122 | ret.Methods[name] = &RPCMethodReuqestStatus{QpsStatus: make(map[int64]int32, 1024)}
123 | }
124 |
125 | return ret
126 | }
127 |
128 | // Start
129 | func (r *RPCRequestStatus) Start() error {
130 | Infof("RPC method reuqest status record starting. expire time within %d seconds ", r.expireAfterSecs)
131 | r.started = true
132 |
133 | // start time wheel to delete expire data
134 | tw, err := timewheel.New[request](1*time.Second, uint16(r.expireAfterSecs))
135 | if err != nil {
136 | r.started = false
137 | return err
138 | }
139 | r.tw = tw
140 | r.tw.Start()
141 |
142 | for {
143 | select {
144 | case m := <-r.reqeustChan:
145 | status, ok := r.Methods[m.method]
146 | if !ok {
147 | status = &RPCMethodReuqestStatus{QpsStatus: make(map[int64]int32, 1024)}
148 | r.Methods[m.method] = status
149 | }
150 | k := m.t.Unix()
151 | count, ok := status.QpsStatus[k]
152 | if !ok {
153 | count = int32(m.count)
154 | // add task
155 | task := timewheel.Task[request]{
156 | Data: m,
157 | TimeoutCallback: func(tt timewheel.Task[request]) { // call back function on time out
158 | k := tt.Data
159 | r.expire(k.method, k.t)
160 |
161 | }}
162 | // add task and return unique task id
163 | r.tw.AddTask(time.Duration(r.expireAfterSecs)*time.Second, task) // add delay task
164 | } else {
165 | count += int32(m.count)
166 | }
167 | status.QpsStatus[k] = count
168 |
169 | case <-r.closeChan:
170 | r.started = false
171 | return nil
172 | }
173 | }
174 |
175 | }
176 |
177 | // RequestIn
178 | func (r *RPCRequestStatus) RequestIn(methodName string, t time.Time, count int) error {
179 | if !r.started {
180 | return fmt.Errorf("RequestIn failed status not started")
181 | }
182 | req := request{method: methodName, t: t, count: count}
183 | r.reqeustChan <- req
184 |
185 | return nil
186 | }
187 |
188 | // expire remove qps data after time expire
189 | func (r *RPCRequestStatus) expire(methodName string, t time.Time) {
190 | status, ok := r.Methods[methodName]
191 | if ok {
192 | delete(status.QpsStatus, t.Unix())
193 | }
194 | }
195 |
196 | // Stop
197 | func (r *RPCRequestStatus) Stop() {
198 | if !r.started {
199 | return
200 | }
201 | r.started = false
202 | r.closeChan <- true
203 |
204 | r.tw.Stop()
205 | }
206 |
--------------------------------------------------------------------------------
/connection.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "errors"
20 | "fmt"
21 | "strconv"
22 | "time"
23 |
24 | "github.com/jhunters/link"
25 | )
26 |
27 | var (
28 | errSessionIsNil = errors.New("[conn-001]Session is nil, maybe not init Connect() function")
29 | errInvalidUrl = errors.New("[conn-002]parameter 'url' of host property is nil")
30 | LOG_INVALID_PORT = "[conn-003]invalid parameter 'url' of port property is '%d'"
31 | )
32 |
33 | /*
34 | Connection handler interface
35 | */
36 | type Connection interface {
37 | SendReceive(rpcDataPackage *RpcDataPackage) (*RpcDataPackage, error)
38 | Send(rpcDataPackage *RpcDataPackage) error
39 | Receive() (*RpcDataPackage, error)
40 | Close() error
41 | Reconnect() error
42 | }
43 |
44 | type ConnectionTester interface {
45 | TestConnection() error
46 | }
47 |
48 | // TCPConnection simple tcp based connection implementation
49 | type TCPConnection struct {
50 | address string
51 | sendChanSize int
52 | session *link.Session[*RpcDataPackage, *RpcDataPackage]
53 | protocol *RpcDataPackageProtocol[*RpcDataPackage, *RpcDataPackage]
54 | }
55 |
56 | /*
57 | Create a new TCPConnection and try to connect to target server by URL.
58 | */
59 | func NewTCPConnection(url URL, timeout *time.Duration) (*TCPConnection, error) {
60 | connection := TCPConnection{}
61 |
62 | err := connection.connect(url, timeout, 0)
63 | if err != nil {
64 | return nil, err
65 | }
66 |
67 | return &connection, nil
68 | }
69 |
70 | func (c *TCPConnection) connect(url URL, timeout *time.Duration, sendChanSize int) error {
71 | host := url.Host
72 | if host == nil || len(*host) == 0 {
73 | return errInvalidUrl
74 | }
75 | port := url.Port
76 | if port == nil || *port <= 0 {
77 | return fmt.Errorf(fmt.Sprintf(LOG_INVALID_PORT, port))
78 | }
79 |
80 | u := *host + ":" + strconv.Itoa(*port)
81 | protocol, err := NewRpcDataPackageProtocol()
82 | if err != nil {
83 | return err
84 | }
85 |
86 | c.protocol = protocol
87 | c.protocol.timeout = timeout
88 | c.address = u
89 | c.sendChanSize = sendChanSize
90 | session, err := doConnect(u, protocol, timeout, sendChanSize)
91 | if err != nil {
92 | return err
93 | }
94 | c.session = session
95 | return nil
96 | }
97 |
98 | func doConnect[S, R *RpcDataPackage](address string, protocol *RpcDataPackageProtocol[*RpcDataPackage, *RpcDataPackage], timeout *time.Duration, sendChanSize int) (*link.Session[*RpcDataPackage, *RpcDataPackage], error) {
99 | var session *link.Session[*RpcDataPackage, *RpcDataPackage]
100 | var err error
101 | if timeout == nil {
102 | session, err = link.Dial[*RpcDataPackage, *RpcDataPackage]("tcp", address, protocol, sendChanSize)
103 | } else {
104 | session, err = link.DialTimeout[*RpcDataPackage, *RpcDataPackage]("tcp", address, *timeout, protocol, sendChanSize)
105 | }
106 | if err != nil {
107 | return nil, err
108 | }
109 | return session, nil
110 | }
111 |
112 | func (c *TCPConnection) TestConnection() error {
113 | if c.session == nil {
114 | return errSessionIsNil
115 | }
116 | closed := c.session.IsClosed()
117 | if closed {
118 | return fmt.Errorf("session closed")
119 | }
120 | return nil
121 | }
122 |
123 | func (c *TCPConnection) GetId() uint64 {
124 | if c.session != nil {
125 | return c.session.ID()
126 | }
127 |
128 | return uint64(0)
129 | }
130 |
131 | // SendReceive send data to connect and block wait data recevie
132 | func (c *TCPConnection) SendReceive(rpcDataPackage *RpcDataPackage) (*RpcDataPackage, error) {
133 | if c.session == nil {
134 | return nil, errSessionIsNil
135 | }
136 |
137 | err := c.session.Send(rpcDataPackage)
138 |
139 | if err != nil {
140 | return nil, err
141 | }
142 |
143 | return doReceive(c.session)
144 |
145 | }
146 |
147 | // Send data to connection
148 | func (c *TCPConnection) Send(rpcDataPackage *RpcDataPackage) error {
149 | if c.session == nil {
150 | return errSessionIsNil
151 | }
152 |
153 | return c.session.Send(rpcDataPackage)
154 |
155 | }
156 |
157 | // Receive data from connection
158 | func (c *TCPConnection) Receive() (*RpcDataPackage, error) {
159 | if c.session == nil {
160 | return nil, errSessionIsNil
161 | }
162 |
163 | return doReceive(c.session)
164 | }
165 |
166 | func doReceive(session *link.Session[*RpcDataPackage, *RpcDataPackage]) (rpcDataPackage *RpcDataPackage, err error) {
167 | rsp, err := session.Receive()
168 | if err != nil {
169 | return nil, err
170 | }
171 |
172 | if rsp == nil { // receive a error data could be ignored
173 | return nil, nil
174 | }
175 |
176 | return rsp, nil
177 |
178 | }
179 |
180 | // Close close connection
181 | func (c *TCPConnection) Close() error {
182 | if c.session != nil {
183 | Info("close session id=", c.session.ID())
184 | return c.session.Close()
185 | }
186 |
187 | if c.protocol != nil {
188 | c.protocol.Stop()
189 | }
190 | return nil
191 | }
192 |
193 | // Reconnect do connect by saved info
194 | func (c *TCPConnection) Reconnect() error {
195 | Info("try to reconnect to server", c.address)
196 | session, err := doConnect(c.address, c.protocol, c.protocol.timeout, c.sendChanSize)
197 | if err != nil {
198 | return err
199 | }
200 | Info("reconnect success to server", c.address)
201 | c.session = session
202 | return nil
203 | }
204 |
--------------------------------------------------------------------------------
/connectionpool.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "context"
20 | "errors"
21 | "time"
22 |
23 | pool "github.com/jolestar/go-commons-pool/v2"
24 | )
25 |
26 | var (
27 | Empty_Head = make([]byte, SIZE)
28 |
29 | errPoolNotInit = errors.New("[connpool-001]Object pool is nil maybe not init Connect() function")
30 | errGetConnFail = errors.New("[connpool-002]Can not get connection from connection pool. target object is nil")
31 | errDestroyObjectNil = errors.New("[connpool-003]Destroy object failed due to target object is nil")
32 |
33 | HB_SERVICE_NAME = "__heartbeat"
34 | HB_METHOD_NAME = "__beat"
35 | )
36 |
37 | /*
38 | type Connection interface {
39 | SendReceive(rpcDataPackage *RpcDataPackage) (*RpcDataPackage, error)
40 | Close() error
41 | }
42 | */
43 |
44 | type TCPConnectionPool struct {
45 | Config *pool.ObjectPoolConfig
46 | objectPool *pool.ObjectPool
47 | timeout *time.Duration
48 | }
49 |
50 | func NewDefaultTCPConnectionPool(url URL, timeout *time.Duration) (*TCPConnectionPool, error) {
51 | return NewTCPConnectionPool(url, timeout, nil)
52 | }
53 |
54 | func NewTCPConnectionPool(url URL, timeout *time.Duration, config *pool.ObjectPoolConfig) (*TCPConnectionPool, error) {
55 | connection := TCPConnectionPool{timeout: timeout}
56 | if config == nil {
57 | connection.Config = pool.NewDefaultPoolConfig()
58 | connection.Config.TestOnBorrow = true
59 |
60 | } else {
61 | connection.Config = config
62 | }
63 |
64 | err := connection.connect(url, timeout, 0)
65 | if err != nil {
66 | return nil, err
67 | }
68 |
69 | return &connection, nil
70 | }
71 |
72 | func (c *TCPConnectionPool) connect(url URL, timeout *time.Duration, sendChanSize int) error {
73 |
74 | factory := ConnectionPoolFactory{timeout: timeout}
75 | factory.url = &url
76 |
77 | var objectPool *pool.ObjectPool
78 |
79 | eConfig := c.Config
80 | if eConfig == nil {
81 | eConfig = pool.NewDefaultPoolConfig()
82 | }
83 |
84 | objectPool = pool.NewObjectPool(context.Background(), &factory, eConfig)
85 | c.objectPool = objectPool
86 |
87 | return nil
88 |
89 | }
90 |
91 | func (c *TCPConnectionPool) borrowObject() (*TCPConnection, error) {
92 | if c.objectPool == nil {
93 | return nil, errPoolNotInit
94 | }
95 |
96 | object, err := c.objectPool.BorrowObject(context.Background())
97 | if err != nil {
98 | return nil, err
99 | }
100 |
101 | if object == nil {
102 | return nil, errGetConnFail
103 | }
104 |
105 | return object.(*TCPConnection), nil
106 | }
107 |
108 | func (c *TCPConnectionPool) SendReceive(rpcDataPackage *RpcDataPackage) (*RpcDataPackage, error) {
109 | object, err := c.borrowObject()
110 | if err != nil {
111 | return nil, err
112 | }
113 | defer c.objectPool.ReturnObject(context.Background(), object)
114 |
115 | return object.SendReceive(rpcDataPackage)
116 |
117 | }
118 |
119 | // Send
120 | func (c *TCPConnectionPool) Send(rpcDataPackage *RpcDataPackage) error {
121 | object, err := c.borrowObject()
122 | if err != nil {
123 | return err
124 | }
125 | defer c.objectPool.ReturnObject(context.Background(), object)
126 | err = object.Send(rpcDataPackage)
127 | return err
128 |
129 | }
130 |
131 | // Receive
132 | func (c *TCPConnectionPool) Receive() (*RpcDataPackage, error) {
133 | object, err := c.borrowObject()
134 | if err != nil {
135 | return nil, err
136 | }
137 | defer c.objectPool.ReturnObject(context.Background(), object)
138 |
139 | return object.Receive()
140 | }
141 |
142 | func (c *TCPConnectionPool) Close() error {
143 | if c.objectPool == nil {
144 | return errPoolNotInit
145 | }
146 |
147 | c.objectPool.Close(context.Background())
148 | return nil
149 | }
150 |
151 | func (c *TCPConnectionPool) GetNumActive() int {
152 | if c.objectPool == nil {
153 | return 0
154 | }
155 |
156 | return c.objectPool.GetNumActive()
157 | }
158 |
159 | // Reconnect do connect by saved info
160 | func (c *TCPConnectionPool) Reconnect() error {
161 | // do nothing
162 | return nil
163 | }
164 |
165 | type ConnectionPoolFactory struct {
166 | url *URL
167 | timeout *time.Duration
168 | }
169 |
170 | func (c *ConnectionPoolFactory) MakeObject(ctx context.Context) (*pool.PooledObject, error) {
171 | if c.url == nil {
172 | return nil, errPoolNotInit
173 | }
174 |
175 | connection := TCPConnection{}
176 | err := connection.connect(*c.url, c.timeout, 0)
177 | if err != nil {
178 | return nil, err
179 | }
180 |
181 | return pool.NewPooledObject(&connection), nil
182 | }
183 |
184 | func (c *ConnectionPoolFactory) DestroyObject(ctx context.Context, object *pool.PooledObject) error {
185 | obj := object.Object
186 | if obj == nil {
187 | return errDestroyObjectNil
188 | }
189 |
190 | conn := obj.(Connection)
191 | return conn.Close()
192 | }
193 |
194 | func (c *ConnectionPoolFactory) ValidateObject(ctx context.Context, object *pool.PooledObject) bool {
195 |
196 | obj := object.Object
197 | if obj == nil {
198 | return false
199 | }
200 |
201 | conn := obj.(ConnectionTester)
202 |
203 | return conn.TestConnection() == nil
204 | }
205 |
206 | func (c *ConnectionPoolFactory) ActivateObject(ctx context.Context, object *pool.PooledObject) error {
207 | return nil
208 | }
209 |
210 | func (c *ConnectionPoolFactory) PassivateObject(ctx context.Context, object *pool.PooledObject) error {
211 | return nil
212 | }
213 |
--------------------------------------------------------------------------------
/rpcpackage_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc_test
17 |
18 | import (
19 | "testing"
20 |
21 | baidurpc "github.com/baidu-golang/pbrpc"
22 | . "github.com/smartystreets/goconvey/convey"
23 | "google.golang.org/protobuf/proto"
24 | )
25 |
26 | var sericeName = "thisIsAServiceName"
27 | var methodName = "thisIsAMethodName"
28 | var magicCode = "PRPC"
29 | var logId int64 = 1001
30 | var correlationId int64 = 20001
31 | var data []byte = []byte{1, 2, 3, 1, 2, 3, 1, 1, 2, 2, 20}
32 | var attachment []byte = []byte{2, 2, 2, 2, 2, 1, 1, 1, 1}
33 |
34 | func initRpcDataPackage() *baidurpc.RpcDataPackage {
35 |
36 | rpcDataPackage := baidurpc.RpcDataPackage{}
37 |
38 | rpcDataPackage.MagicCode(magicCode)
39 | rpcDataPackage.SetData(data)
40 | rpcDataPackage.ServiceName(sericeName)
41 | rpcDataPackage.MethodName(methodName)
42 |
43 | rpcDataPackage.LogId(logId)
44 | rpcDataPackage.CorrelationId(correlationId)
45 |
46 | rpcDataPackage.SetAttachment(attachment)
47 |
48 | return &rpcDataPackage
49 | }
50 |
51 | func equalRpcDataPackage(r baidurpc.RpcDataPackage, t *testing.T) error {
52 | Convey("test RpcDataPackage", func() {
53 | So(sericeName, ShouldEqual, r.Meta.Request.ServiceName)
54 | So(methodName, ShouldEqual, r.Meta.Request.MethodName)
55 | So(string(magicCode), ShouldEqual, string(r.GetMagicCode()))
56 | So(r.Meta.Request.LogId, ShouldEqual, logId)
57 | So(r.Meta.CorrelationId, ShouldEqual, correlationId)
58 | So(len(data), ShouldEqual, len(r.Data))
59 | So(len(attachment), ShouldEqual, len(r.Attachment))
60 | })
61 | return nil
62 | }
63 |
64 | func validateRpcDataPackage(t *testing.T, r2 baidurpc.RpcDataPackage) {
65 | Convey("validateRpcDataPackage", func() {
66 | So(string(magicCode), ShouldEqual, string(r2.GetMagicCode()))
67 | So(sericeName, ShouldEqual, r2.GetMeta().GetRequest().GetServiceName())
68 | So(methodName, ShouldEqual, r2.GetMeta().GetRequest().GetMethodName())
69 | })
70 |
71 | }
72 |
73 | // TestWriteReaderWithMockData
74 | func TestWriteReaderWithMockData(t *testing.T) {
75 |
76 | Convey("TestWriteReaderWithMockData", t, func() {
77 | rpcDataPackage := initRpcDataPackage()
78 |
79 | b, err := rpcDataPackage.Write()
80 | if err != nil {
81 | t.Error(err.Error())
82 | }
83 |
84 | r2 := baidurpc.RpcDataPackage{}
85 |
86 | err = r2.Read(b)
87 | if err != nil {
88 | t.Error(err.Error())
89 | }
90 |
91 | validateRpcDataPackage(t, r2)
92 | })
93 |
94 | }
95 |
96 | // WriteReaderWithRealData
97 | func WriteReaderWithRealData(rpcDataPackage *baidurpc.RpcDataPackage,
98 | compressType int32, t *testing.T) {
99 |
100 | Convey("Test with real data", func() {
101 | dataMessage := DataMessage{}
102 | name := "hello, xiemalin. this is repeated string aaaaaaaaaaaaaaaaaaaaaa"
103 | dataMessage.Name = name
104 |
105 | data, err := proto.Marshal(&dataMessage)
106 | So(err, ShouldBeNil)
107 | rpcDataPackage.SetData(data)
108 |
109 | b, err := rpcDataPackage.Write()
110 | So(err, ShouldBeNil)
111 |
112 | r2 := baidurpc.RpcDataPackage{}
113 | r2.CompressType(compressType)
114 |
115 | err = r2.Read(b)
116 | So(err, ShouldBeNil)
117 |
118 | validateRpcDataPackage(t, r2)
119 |
120 | newData := r2.GetData()
121 | dataMessage2 := DataMessage{}
122 | proto.Unmarshal(newData, &dataMessage2)
123 |
124 | So(name, ShouldEqual, dataMessage2.Name)
125 | })
126 |
127 | }
128 |
129 | // TestWriteReaderWithRealData
130 | func TestWriteReaderWithRealData(t *testing.T) {
131 |
132 | Convey("TestWriteReaderWithRealData", t, func() {
133 | rpcDataPackage := initRpcDataPackage()
134 | WriteReaderWithRealData(rpcDataPackage, baidurpc.COMPRESS_NO, t)
135 | })
136 |
137 | }
138 |
139 | // TestWriteReaderWithGZIP
140 | func TestWriteReaderWithGZIP(t *testing.T) {
141 |
142 | Convey("TestWriteReaderWithGZIP", t, func() {
143 | rpcDataPackage := initRpcDataPackage()
144 | rpcDataPackage.CompressType(baidurpc.COMPRESS_GZIP)
145 | WriteReaderWithRealData(rpcDataPackage, baidurpc.COMPRESS_GZIP, t)
146 | })
147 |
148 | }
149 |
150 | // TestWriteReaderWithSNAPPY
151 | func TestWriteReaderWithSNAPPY(t *testing.T) {
152 |
153 | Convey("TestWriteReaderWithSNAPPY", t, func() {
154 | rpcDataPackage := initRpcDataPackage()
155 |
156 | rpcDataPackage.CompressType(baidurpc.COMPRESS_SNAPPY)
157 |
158 | WriteReaderWithRealData(rpcDataPackage, baidurpc.COMPRESS_SNAPPY, t)
159 | })
160 |
161 | }
162 |
163 | // TestChunk
164 | func TestChunk(t *testing.T) {
165 |
166 | Convey("Test package chunk", t, func() {
167 | rpcDataPackage := initRpcDataPackage()
168 |
169 | Convey("Test package chunk with invalid chunk size", func() {
170 | chunkSize := 0
171 | chunkPackages := rpcDataPackage.Chunk(chunkSize)
172 | So(len(chunkPackages), ShouldEqual, 1)
173 | })
174 |
175 | Convey("Test package chunk with chunk size", func() {
176 | chunkSize := 1
177 | count := len(rpcDataPackage.Data)
178 | chunkPackages := rpcDataPackage.Chunk(chunkSize)
179 | So(len(chunkPackages), ShouldEqual, count)
180 | So(len(chunkPackages[0].Data), ShouldEqual, 1)
181 | })
182 |
183 | Convey("Test package chunk with large chunk size", func() {
184 | chunkSize := 100
185 | datasize := len(rpcDataPackage.Data)
186 | chunkPackages := rpcDataPackage.Chunk(chunkSize)
187 | So(len(chunkPackages), ShouldEqual, 1)
188 | So(len(chunkPackages[0].Data), ShouldEqual, datasize)
189 | })
190 | })
191 |
192 | }
193 |
--------------------------------------------------------------------------------
/httpserver.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-08-19 13:22:01
5 | */
6 | package baidurpc
7 |
8 | import (
9 | "context"
10 | "encoding/json"
11 | "fmt"
12 | "io/ioutil"
13 | "log"
14 | "net"
15 | "net/http"
16 | "strconv"
17 | "strings"
18 | )
19 |
20 | const (
21 | HttpRpcPath = "/rpc/"
22 |
23 | LogId_key = "X-LogID"
24 | Auth_key = "X-Authenticate"
25 | Trace_Id_key = "X-Trace_ID"
26 | Trace_Span_key = "X-Trace_Span"
27 | Trace_Parent_key = "X-Trace_Parent"
28 | Request_Meta_Key = "X-Request-Meta" // Json value
29 | )
30 |
31 | // ResponseData
32 | type ResponseData struct {
33 | ErrNo int `json:"errno"`
34 | Message string `json:"message,omitempty"`
35 | Data interface{} `json:"data,omitempty"`
36 | }
37 |
38 | type HttpServer struct {
39 | s *TcpServer
40 | httpsrv *http.Server
41 | }
42 |
43 | func (h *HttpServer) serverHttp(l net.Listener) {
44 |
45 | srv := &http.Server{
46 | Handler: h,
47 | }
48 |
49 | h.httpsrv = srv
50 |
51 | go func() {
52 | // service connections
53 | if err := srv.Serve(l); err != nil && err != http.ErrServerClosed {
54 | log.Fatalf("listen: %s\n", err)
55 | }
56 | }()
57 |
58 | }
59 |
60 | // ServeHTTP to serve http reqeust and response to process http rpc handle
61 | func (h *HttpServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
62 | path := req.URL.Path
63 | if !strings.HasPrefix(path, HttpRpcPath) {
64 | data := toJson(errResponse(ST_SERVICE_NOTFOUND, fmt.Sprintf("no service or method found by path='%s'", path)))
65 | w.Write(data)
66 | return
67 | }
68 | serviceName, method, err := getServiceMethod(path)
69 | if err != nil {
70 | data := toJson(errResponse(ST_ERROR, err.Error()))
71 | w.Write(data)
72 | return
73 | }
74 |
75 | sid := GetServiceId(serviceName, method)
76 |
77 | service, ok := h.s.services[sid]
78 | if !ok {
79 | data := toJson(errResponse(ST_SERVICE_NOTFOUND, fmt.Sprintf("no service or method found by path='%s'", path)))
80 | w.Write(data)
81 | return
82 | }
83 |
84 | // authenticate
85 | if h.s.authService != nil {
86 | authData := getHeaderAsByte(req, Auth_key)
87 | authOk := h.s.authService.Authenticate(serviceName, method, authData)
88 | if !authOk {
89 | data := toJson(errResponse(ST_AUTH_ERROR, errAuth.Error()))
90 | w.Write(data)
91 | return
92 | }
93 | }
94 |
95 | if h.s.traceService != nil {
96 | traceId := getHeaderAsInt64(req, Trace_Id_key)
97 | spanId := getHeaderAsInt64(req, Trace_Span_key)
98 | parentId := getHeaderAsInt64(req, Trace_Parent_key)
99 | traceInfo := &TraceInfo{TraceId: traceId, SpanId: spanId, ParentSpanId: parentId}
100 |
101 | value := getHeaderAsByte(req, Request_Meta_Key)
102 | if value != nil {
103 | value, _ = UnescapeUnicode(value)
104 | metaExt := map[string]string{}
105 | err := json.Unmarshal(value, &metaExt)
106 | if err == nil {
107 | traceInfo.RpcRequestMetaExt = metaExt
108 | }
109 | }
110 |
111 | traceRetrun := h.s.traceService.Trace(serviceName, method, traceInfo)
112 | if traceRetrun != nil {
113 | w.Header().Set(Trace_Id_key, int64ToString(traceRetrun.TraceId))
114 | w.Header().Set(Trace_Span_key, int64ToString(traceRetrun.SpanId))
115 | w.Header().Set(Trace_Parent_key, int64ToString(traceRetrun.ParentSpanId))
116 | if traceRetrun.RpcRequestMetaExt != nil {
117 | metaData, err := json.Marshal(traceRetrun.RpcRequestMetaExt)
118 | if err == nil {
119 | w.Header().Set(Request_Meta_Key, string(metaData))
120 | }
121 | }
122 | }
123 | }
124 |
125 | // get json data
126 | jsonData, err := ioutil.ReadAll(req.Body)
127 | if err != nil {
128 | data := toJson(errResponse(ST_ERROR, err.Error()))
129 | w.Write(data)
130 | return
131 | }
132 |
133 | paramIn := service.NewParameter()
134 | err = json.Unmarshal(jsonData, paramIn)
135 | if err != nil {
136 | data := toJson(errResponse(ST_ERROR, err.Error()))
137 | w.Write(data)
138 | return
139 | }
140 |
141 | // get logid
142 | var logid int64 = getHeaderAsInt64(req, LogId_key)
143 |
144 | ec := &ErrorContext{}
145 | ret, _, err := h.s.doServiceInvoke(ec, paramIn, serviceName, method, nil, logid, service)
146 | if err != nil {
147 | data := toJson(errResponse(ST_ERROR, err.Error()))
148 | w.Write(data)
149 | return
150 | }
151 |
152 | resData := &ResponseData{ErrNo: 0, Data: ret}
153 | data, err := json.Marshal(resData)
154 | if err != nil {
155 | data := toJson(errResponse(ST_ERROR, err.Error()))
156 | w.Write(data)
157 | return
158 | }
159 |
160 | w.Write(data)
161 |
162 | }
163 |
164 | // shutdown do shutdown action to close http server
165 | func (h *HttpServer) shutdown(ctx context.Context) {
166 | if h.httpsrv != nil {
167 | h.httpsrv.Shutdown(ctx)
168 | }
169 | }
170 |
171 | func getHeaderAsByte(req *http.Request, key string) []byte {
172 | value, ok := req.Header[http.CanonicalHeaderKey(key)]
173 | if !ok || len(value) != 1 {
174 | return nil
175 | }
176 | return []byte(value[0])
177 | }
178 |
179 | func getHeaderAsInt64(req *http.Request, key string) int64 {
180 | value, ok := req.Header[http.CanonicalHeaderKey(key)]
181 | if !ok || len(value) != 1 {
182 | return -1
183 | }
184 |
185 | id, _ := strconv.Atoi(value[0])
186 | return int64(id)
187 | }
188 |
189 | func int64ToString(i int64) string {
190 | return strconv.Itoa(int(i))
191 | }
192 |
193 | func errResponse(errno int, message string) *ResponseData {
194 | return &ResponseData{ErrNo: errno, Message: message}
195 | }
196 |
197 | func toJson(o interface{}) []byte {
198 | data, _ := json.Marshal(o)
199 | return data
200 | }
201 |
202 | func getServiceMethod(path string) (string, string, error) {
203 | p := strings.TrimPrefix(path, HttpRpcPath)
204 | p = strings.TrimSuffix(p, "/")
205 |
206 | seperate := strings.Split(p, "/")
207 | if len(seperate) != 2 {
208 | return "", "", fmt.Errorf("no service or method found by path='%s'", p)
209 | }
210 | return seperate[0], seperate[1], nil
211 | }
212 |
213 | // UnescapeUnicode
214 | func UnescapeUnicode(raw []byte) ([]byte, error) {
215 | str, err := strconv.Unquote(strings.Replace(strconv.Quote(string(raw)), `\\u`, `\u`, -1))
216 | if err != nil {
217 | return nil, err
218 | }
219 | return []byte(str), nil
220 | }
221 |
--------------------------------------------------------------------------------
/haclient.go:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: Malin Xie
3 | * @Description:
4 | * @Date: 2021-04-26 18:18:59
5 | */
6 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
7 | //
8 | // Copyright 2002-2007 the original author or authors.
9 | //
10 | // Licensed under the Apache License, Version 2.0 (the "License");
11 | // you may not use this file except in compliance with the License.
12 | // You may obtain a copy of the License at
13 | //
14 | // http://www.apache.org/licenses/LICENSE-2.0
15 | //
16 | // Unless required by applicable law or agreed to in writing, software
17 | // distributed under the License is distributed on an "AS IS" BASIS,
18 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | // See the License for the specific language governing permissions and
20 | // limitations under the License.
21 | package baidurpc
22 |
23 | import (
24 | "errors"
25 | "fmt"
26 | "log"
27 | "sync"
28 | "time"
29 |
30 | "github.com/jhunters/timewheel"
31 | "google.golang.org/protobuf/proto"
32 | )
33 |
34 | // HaRpcClient high avialbe RpcClient
35 | type HaRpcClient struct {
36 | rpcClients []*RpcClient
37 |
38 | current int32
39 |
40 | locker sync.Mutex
41 |
42 | tw *timewheel.TimeWheel[*RpcDataPackage]
43 | }
44 |
45 | // NewBatchTCPConnection to create batch connection
46 | func NewBatchTCPConnection(urls []URL, timeout time.Duration) ([]Connection, error) {
47 | if len(urls) == 0 {
48 | return nil, errors.New("param 'urls' is empty")
49 | }
50 |
51 | var result []Connection
52 | for _, url := range urls {
53 | conn, err := NewTCPConnection(url, &timeout)
54 | if err != nil {
55 | log.Println("create connection failed:", err)
56 | continue
57 | }
58 | result = append(result, conn)
59 | }
60 |
61 | return result, nil
62 | }
63 |
64 | // CloseBatchConnection close batch connections
65 | func CloseBatchConnection(connections []Connection) {
66 | for _, conn := range connections {
67 | conn.Close()
68 | }
69 | }
70 |
71 | // NewHaRpcCient
72 | func NewHaRpcCient(connections []Connection) (*HaRpcClient, error) {
73 | return NewHaRpcCientWithTimewheelSetting(connections, defaultTimewheelInterval, uint16(defaultTimewheelSlot))
74 | }
75 |
76 | // NewHaRpcCient
77 | func NewHaRpcCientWithTimewheelSetting(connections []Connection, timewheelInterval time.Duration, timewheelSlot uint16) (*HaRpcClient, error) {
78 | if len(connections) == 0 {
79 | return nil, errors.New("param 'connections' is empty")
80 | }
81 |
82 | rpcClients := make([]*RpcClient, len(connections))
83 | for idx, connection := range connections {
84 | rpcClient, err := NewRpcCient(connection)
85 | if err != nil {
86 | return nil, err
87 | }
88 | rpcClients[idx] = rpcClient
89 | }
90 | result := &HaRpcClient{rpcClients: rpcClients, current: 0}
91 | result.tw, _ = timewheel.New[*RpcDataPackage](timewheelInterval, timewheelSlot)
92 | result.tw.Start()
93 | return result, nil
94 | }
95 |
96 | // electClient
97 | func (c *HaRpcClient) electClient() *RpcClient {
98 | if len(c.rpcClients) == 0 {
99 | return nil
100 | }
101 |
102 | c.locker.Lock()
103 | defer c.locker.Unlock()
104 |
105 | client := c.rpcClients[int(c.current)%len(c.rpcClients)]
106 | c.current++
107 | return client
108 | }
109 |
110 | // SendRpcRequest send rpc request by elect one client
111 | func (c *HaRpcClient) SendRpcRequest(rpcInvocation *RpcInvocation, responseMessage proto.Message) (*RpcDataPackage, error) {
112 | var errRet error
113 | size := len(c.rpcClients)
114 | if size == 0 {
115 | return nil, errors.New("no rpc client avaible")
116 | }
117 |
118 | for i := 0; i < size; i++ {
119 | rpcClient := c.electClient()
120 | if rpcClient == nil {
121 | return nil, errors.New("no rpc client avaible")
122 | }
123 |
124 | data, err := rpcClient.SendRpcRequest(rpcInvocation, responseMessage)
125 | if err == nil {
126 | return data, nil
127 | } else {
128 | errRet = err
129 | }
130 | }
131 |
132 | return nil, errRet
133 | }
134 |
135 | // SendRpcRequest send rpc request by elect one client with timeout feature
136 | func (c *HaRpcClient) SendRpcRequestWithTimeout(timeout time.Duration, rpcInvocation *RpcInvocation, responseMessage proto.Message) (*RpcDataPackage, error) {
137 | var errRet error
138 | size := len(c.rpcClients)
139 | if size == 0 {
140 | return nil, errors.New("no rpc client avaible")
141 | }
142 |
143 | ch := make(chan *RpcDataPackage)
144 | go c.asyncRequest(timeout, rpcInvocation, responseMessage, ch)
145 | defer close(ch)
146 | // wait for message
147 | rsp := <-ch
148 |
149 | return rsp, errRet
150 | }
151 |
152 | // asyncRequest
153 | func (c *HaRpcClient) asyncRequest(timeout time.Duration, rpcInvocation *RpcInvocation, responseMessage proto.Message, ch chan<- *RpcDataPackage) {
154 | request, err := rpcInvocation.GetRequestRpcDataPackage()
155 | if err != nil {
156 | errorcode := int32(ST_ERROR)
157 | request.ErrorCode(errorcode)
158 | errormsg := err.Error()
159 | request.ErrorText(errormsg)
160 |
161 | ch <- request
162 | return
163 | }
164 |
165 | // create a task bind with key, data and time out call back function.
166 | t := &timewheel.Task[*RpcDataPackage]{
167 | Data: nil, // business data
168 | TimeoutCallback: func(task timewheel.Task[*RpcDataPackage]) { // call back function on time out
169 | // process someting after time out happened.
170 | errorcode := int32(ST_READ_TIMEOUT)
171 | request.ErrorCode(errorcode)
172 | errormsg := fmt.Sprintf("request time out of %v", task.Delay())
173 | request.ErrorText(errormsg)
174 | ch <- request
175 | }}
176 |
177 | // add task and return unique task id
178 | taskid, err := c.tw.AddTask(timeout, *t) // add delay task
179 | if err != nil {
180 | errorcode := int32(ST_ERROR)
181 | request.ErrorCode(errorcode)
182 | errormsg := err.Error()
183 | request.ErrorText(errormsg)
184 |
185 | ch <- request
186 | return
187 | }
188 |
189 | defer func() {
190 | c.tw.RemoveTask(taskid)
191 | if e := recover(); e != nil {
192 | Warningf("asyncRequest failed with error %v", e)
193 | }
194 | }()
195 |
196 | rsp, err := c.SendRpcRequest(rpcInvocation, responseMessage)
197 | if err != nil {
198 | errorcode := int32(ST_ERROR)
199 | request.ErrorCode(errorcode)
200 | errormsg := err.Error()
201 | request.ErrorText(errormsg)
202 |
203 | ch <- request
204 | return
205 | }
206 |
207 | ch <- rsp
208 | }
209 |
210 | // Close do close all client
211 | func (c *HaRpcClient) Close() {
212 | if c.tw != nil {
213 | c.tw.Stop()
214 | }
215 | for _, client := range c.rpcClients {
216 | client.Close()
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/codec.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "errors"
20 | "io"
21 | "log"
22 | "net"
23 | "time"
24 |
25 | "github.com/jhunters/link"
26 | "github.com/jhunters/timewheel"
27 | )
28 |
29 | const REQUIRED_TYPE = "baidurpc.RpcDataPackage"
30 |
31 | var (
32 | LOG_CLOSE_CONNECT_INFO = "[codec-100]Do close connection. connection info:%v"
33 | chunkPackageCacheExpire = 60 * time.Second
34 | )
35 |
36 | /*
37 | Codec implements for RpcDataPackage.
38 | */
39 | type RpcDataPackageCodec[S, R *RpcDataPackage] struct {
40 | readWriter io.ReadWriter
41 | closer io.Closer
42 | p *RpcDataPackageProtocol[S, R]
43 | timeout *time.Duration
44 |
45 | chunkPackageCache map[int64]*RpcDataPackage
46 | }
47 |
48 | // Here begin to implements link module Codec interface for RpcDataPackageCodec
49 | /*
50 | type Codec[S, R any] interface {
51 | Receive() (R, error)
52 | Send(S) error
53 | Close() error
54 | }
55 | */
56 |
57 | // send serialized data to target server by connection IO
58 | // msg: param 'msg' must type of RpcDataPackage
59 | func (r *RpcDataPackageCodec[S, R]) Send(dataPackage *RpcDataPackage) error {
60 | if dataPackage == nil {
61 | return errors.New("parameter 'msg' is nil")
62 | }
63 |
64 | rw := r.readWriter
65 | if r.timeout != nil {
66 | conn := rw.(net.Conn)
67 | conn.SetWriteDeadline(time.Now().Add(*r.timeout))
68 | }
69 |
70 | // check if use chunk mode
71 | chunkSize := dataPackage.chunkSize
72 | if chunkSize > 0 {
73 | dataPackageList := dataPackage.Chunk(int(chunkSize))
74 | for _, pack := range dataPackageList {
75 | err := pack.WriteIO(rw)
76 | if err != nil {
77 | return err
78 | }
79 | }
80 | } else {
81 | err := dataPackage.WriteIO(rw)
82 | if err != nil {
83 | return err
84 | }
85 | }
86 | return nil
87 | }
88 |
89 | // receive serialized data to target server by connection IO
90 | // return param:
91 | // 1. RpcDataPackage unserialized from connection io. or nil if exception found
92 | // 2. a non-nil error if any io exception occurred
93 | func (r *RpcDataPackageCodec[S, R]) Receive() (*RpcDataPackage, error) {
94 |
95 | rw := r.readWriter
96 |
97 | if r.timeout != nil { // set time out
98 | conn := rw.(net.Conn)
99 | conn.SetReadDeadline(time.Now().Add(*r.timeout))
100 | }
101 |
102 | return r.doReceive(rw)
103 |
104 | }
105 |
106 | func (r *RpcDataPackageCodec[S, R]) doReceive(conn io.ReadWriter) (*RpcDataPackage, error) {
107 | dataPackage := dataPackagePool.Get()
108 | dataPackage.Clear()
109 | err := dataPackage.ReadIO(conn)
110 | if err != nil {
111 | if err == errIgnoreErr {
112 | return nil, nil
113 | }
114 | return nil, err
115 | }
116 |
117 | // if chunk mode enabled
118 | if r.p.chunkSize > 0 {
119 | dataPackage.chunkSize = r.p.chunkSize
120 | }
121 |
122 | // check if chunk package
123 | if dataPackage.IsChunkPackage() {
124 | streamId := dataPackage.GetChunkStreamId()
125 |
126 | cachedPackage, exist := r.chunkPackageCache[streamId]
127 | if !exist {
128 | r.chunkPackageCache[streamId] = dataPackage
129 | cachedPackage = dataPackage
130 |
131 | // add task
132 | task := timewheel.Task[int64]{
133 | Data: streamId,
134 | TimeoutCallback: func(tt timewheel.Task[int64]) { // call back function on time out
135 | k := tt.Data
136 | delete(r.chunkPackageCache, k)
137 | }}
138 | // add task and return unique task id
139 | r.p.tw.AddTask(chunkPackageCacheExpire, task) // add delay task
140 |
141 | } else {
142 | // if exist should merge data
143 | size := len(cachedPackage.Data) + len(dataPackage.Data)
144 | newData := make([]byte, size)
145 | copy(newData, cachedPackage.Data)
146 | copy(newData[len(cachedPackage.Data):], dataPackage.Data)
147 | cachedPackage.Data = newData
148 | r.chunkPackageCache[streamId] = cachedPackage
149 | }
150 |
151 | if dataPackage.IsFinalPackage() {
152 | delete(r.chunkPackageCache, streamId)
153 | // clear chunk status
154 | cachedPackage.ClearChunkStatus()
155 | return cachedPackage, nil
156 | } else {
157 | return r.doReceive(conn) // to receive next chunk package
158 | }
159 | }
160 |
161 | return dataPackage, nil
162 | }
163 |
164 | // do close connection io
165 | // return non-nil if any error ocurred while doing close
166 | func (r *RpcDataPackageCodec[S, R]) Close() error {
167 | if r.closer != nil {
168 | log.Printf(LOG_CLOSE_CONNECT_INFO, r.closer)
169 | return r.closer.Close()
170 | }
171 | return nil
172 | }
173 |
174 | // set connection io read and write dead line
175 | func (r *RpcDataPackageCodec[S, R]) SetTimeout(timeout *time.Duration) {
176 | r.timeout = timeout
177 | }
178 |
179 | // Here begin to implements link module Protocol interface for RpcDataPackageCodec
180 | /*
181 | type Protocol[S, R any] interface {
182 | NewCodec(rw io.ReadWriter) (Codec[S, R], error)
183 | }
184 |
185 | */
186 |
187 | // Protocol codec factory object for RpcDataPackage
188 | type RpcDataPackageProtocol[S, R *RpcDataPackage] struct {
189 | timeout *time.Duration
190 |
191 | tw *timewheel.TimeWheel[int64]
192 |
193 | chunkSize uint32
194 | }
195 |
196 | // NewRpcDataPackageProtocol create a RpcDataPackageProtocol and start timewheel
197 | func NewRpcDataPackageProtocol[S, R *RpcDataPackage]() (*RpcDataPackageProtocol[S, R], error) {
198 | protocol := &RpcDataPackageProtocol[S, R]{}
199 | tw, err := timewheel.New[int64](chunkExpireTimewheelInterval, uint16(chunkExpireTimeWheelSlot))
200 | if err != nil {
201 | return nil, err
202 | }
203 | protocol.tw = tw
204 | protocol.tw.Start()
205 | return protocol, nil
206 | }
207 |
208 | func (r *RpcDataPackageProtocol[S, R]) NewCodec(rw io.ReadWriter) (link.Codec[*RpcDataPackage, *RpcDataPackage], error) {
209 | rpcDataPackage := &RpcDataPackageCodec[S, R]{
210 | readWriter: rw,
211 | p: r,
212 | timeout: r.timeout,
213 | chunkPackageCache: make(map[int64]*RpcDataPackage),
214 | }
215 |
216 | rpcDataPackage.closer, _ = rw.(io.Closer)
217 |
218 | return rpcDataPackage, nil
219 |
220 | }
221 |
222 | // Stop
223 | func (r *RpcDataPackageProtocol[S, R]) Stop() {
224 | if r.tw != nil {
225 | r.tw.Stop()
226 | }
227 | }
228 |
229 | // Here end to implements link module Codec interface
230 |
--------------------------------------------------------------------------------
/docs/Demo.md:
--------------------------------------------------------------------------------
1 | baidurpc
2 |
3 |
4 | baidurpc是一种基于TCP协议的二进制高性能RPC通信协议实现。它以Protobuf作为基本的数据交换格式。
5 | 本版本基于golang实现.完全兼容jprotobuf-rpc-socket: https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
6 |
7 |
8 | ### 更多特性使用介绍
9 |
10 | #### 开发RPC服务端
11 |
12 | 1. 定义PB对象
13 | ```property
14 | message DataMessae {
15 | string name = 1;
16 | }
17 | ```
18 | 用protoc工具 生成 pb go 定义文件
19 | protoc --go_out=. datamessage.proto
20 | 2. 定义一个对象以及方法,用于发布服务
21 |
22 | ```go
23 |
24 | type EchoService struct {
25 | }
26 |
27 | // Echo test publish method with return type has context argument
28 | // 方法要求
29 | // 参数个数必须为1个或2个, 第一个类型必须为 context.Context
30 | // 第二个类型必须是实现 proto.Message接口(如果是无参,可以省略)
31 | // 返回个数可以为1个或2个 第一个类型必须是实现 proto.Message接口
32 | // 第2个参数为可选。 当使用时,必须为 context.Context类型
33 | func (rpc *EchoService) Echo(c context.Context, in *DataMessage) (*DataMessage, context.Context) {
34 | var ret = "hello "
35 |
36 | // if receive with attachement
37 | attachement := baidurpc.Attachement(c)
38 | fmt.Println(c)
39 |
40 | if len(*in.Name) == 0 {
41 | ret = ret + "veryone"
42 | } else {
43 | ret = ret + *in.Name
44 | }
45 | dm := DataMessage{}
46 | dm.Name = proto.String(ret)
47 | return &dm, baidurpc.BindAttachement(context.Background(), []byte("hello")) // return with attachement
48 | }
49 | ```
50 |
51 | 以下都是合法的定义方法
52 | 1. Echo(c context.Context, in *DataMessage) (*DataMessage, context.Context)
53 | 2. Echo(c context.Context) (*DataMessage, context.Context)
54 | 3. Echo(c context.Context) (*DataMessage)
55 |
56 |
57 | 2. 指定发布端口,把EchoService发布成RPC服务
58 |
59 | ```go
60 | serverMeta := baidurpc.ServerMeta{}
61 | serverMeta.Host = nil
62 | serverMeta.Port = Int(*port)
63 | // set chunk size this will open server chunk package by specified size
64 | // serverMeta.ChunkSize = 1024 // 1k
65 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
66 |
67 | echoService := new(EchoService)
68 |
69 | // mapping可选,如果需要映射成新的function名称时使用
70 | mapping := make(map[string]string)
71 | mapping["Echo"] = "echo"
72 | // 第一个参数 "echoService" 为空时,则会使用 EchoService的struct 的type name
73 | rpcServer.RegisterNameWithMethodMapping("echoService", echoService, mapping)
74 | // 最简注册方式 rpcServer.Register(echoService)
75 |
76 | // 启动RPC服务
77 | err := rpcServer.StartAndBlock()
78 |
79 | if err != nil {
80 | baidurpc.Error(err)
81 | os.Exit(-1)
82 | }
83 | ```
84 |
85 | 至此RPC已经开发完成,运行上面代码,就可以发布完成.
86 |
87 | #### 开发启验证功能
88 |
89 | 实现 AuthService 接口
90 |
91 | ```go
92 | type StringMatchAuthService struct {
93 | }
94 |
95 | // Authenticate
96 | func (as *StringMatchAuthService) Authenticate(service, name string, authToken []byte) bool {
97 | if authToken == nil {
98 | return false
99 | }
100 | return strings.Compare(AUTH_TOKEN, string(authToken)) == 0
101 | }
102 |
103 | ```
104 | 设置到service对象
105 | ```go
106 |
107 | // ...
108 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
109 | rpcServer.SetAuthService(new(StringMatchAuthService))
110 |
111 | ```
112 |
113 | #### 设置trace功能
114 |
115 | 实现 TraceService 接口
116 |
117 | ```go
118 | type AddOneTraceService struct {
119 | }
120 |
121 | // Trace
122 | func (as *AddOneTraceService) Trace(service, name string, traceInfo *baidurpc.TraceInfo) *baidurpc.TraceInfo {
123 | *traceInfo.SpanId++
124 | *traceInfo.TraceId++
125 | *traceInfo.ParentSpanId++
126 | return traceInfo
127 | }
128 |
129 | ```
130 |
131 | 设置到service对象
132 | ```go
133 |
134 | // ...
135 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
136 | rpcServer.SetTraceService(new(AddOneTraceService))
137 |
138 | ```
139 |
140 | ### 开发RPC客户端
141 |
142 | ```go
143 | // 创建链接(本示例使用连接池方式)
144 | url := baidurpc.URL{}
145 | url.SetHost(host).SetPort(port)
146 | timeout := time.Second * 5
147 |
148 | // 创建连接
149 | connection, err := baidurpc.NewDefaultTCPConnectionPool(url, &timeout)
150 | if err != nil {
151 | fmt.Println(err)
152 | os.Exit(-1)
153 | }
154 | defer connection.Close()
155 |
156 | // 创建client
157 | rpcClient, err := baidurpc.NewRpcCient(connection)
158 | if err != nil {
159 | fmt.Println(err)
160 | os.Exit(-1)
161 | }
162 | defer rpcClient.Close()
163 | // 调用RPC
164 | serviceName := "echoService"
165 | methodName := "echo"
166 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
167 |
168 | message := "say hello from xiemalin中文测试"
169 | dm := DataMessage{&message}
170 |
171 | rpcInvocation.SetParameterIn(&dm)
172 | rpcInvocation.LogId = proto.Int64(1)
173 |
174 | // 可选, 设置logid 与 附件
175 | // rpcInvocation.LogId = proto.Int64(1)
176 | // rpcInvocation.Attachment = []byte("this is attachement contenet")
177 |
178 | parameterOut := DataMessage{}
179 |
180 | response, err := rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
181 | if err != nil {
182 | fmt.Println(err)
183 | os.Exit(-1)
184 | }
185 |
186 | if response == nil {
187 | fmt.Println("Reponse is nil")
188 | return
189 | }
190 | ```
191 |
192 | ### 设置调用超时
193 |
194 | ```go
195 | // baidurpc的超时控制功能使用了 时间轮 timewheel功能 https://github.com/jhunters/timewheel
196 | // 可以在初始化Client时设置
197 | timewheelInterval := 1 * time.Second
198 | var timewheelSlot uint16 = 300
199 | rpcClient, err := baidurpc.NewRpcCientWithTimeWheelSetting(connection, timewheelInterval, timewheelSlot)
200 |
201 | // 调用时,设置超时功能
202 | response, err := rpcClient.SendRpcRequestWithTimeout(100*time.Millisecond, rpcInvocation, ¶meterOut)
203 | // 如果发生超时, 返回的错误码为 62
204 |
205 | ```
206 |
207 | ### 设置验证
208 | ```go
209 | // 调用RPC
210 | serviceName := "echoService"
211 | methodName := "echo"
212 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
213 | // set auth token
214 | rpcInvocation.AuthenticateData = []byte("AUTH_TOKEN")
215 | // 调用时,设置超时功能
216 | response, err := rpcClient.SendRpcRequestWithTimeout(100*time.Millisecond, rpcInvocation, ¶meterOut)
217 | // 如果发生超时, 返回的错误码为 62
218 |
219 | ```
220 |
221 | ### 设置分包chunk功能
222 | ```go
223 | // 调用RPC
224 | serviceName := "echoService"
225 | methodName := "echo"
226 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
227 | // 设置分包大小(byte)
228 | rpcInvocation.ChunkSize = 1024 //1k
229 | // 调用时,设置超时功能
230 | response, err := rpcClient.SendRpcRequestWithTimeout(100*time.Millisecond, rpcInvocation, ¶meterOut)
231 | // 如果发生超时, 返回的错误码为 62
232 |
233 | ```
234 |
235 | ### 设置Trace功能
236 | ```go
237 | // 调用RPC
238 | serviceName := "echoService"
239 | methodName := "echo"
240 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
241 | // 设置trace信息
242 | rpcInvocation.TraceId = 10
243 | rpcInvocation.SpanId = 11
244 | rpcInvocation.ParentSpanId = 12
245 | rpcInvocation.RpcRequestMetaExt = map[string]string{"key1": "value1"}
246 | // 调用时,设置超时功能
247 | response, err := rpcClient.SendRpcRequestWithTimeout(100*time.Millisecond, rpcInvocation, ¶meterOut)
248 | // 如果发生超时, 返回的错误码为 62
249 |
250 | // 获取服务端返回的trace信息
251 | response.GetTraceId()
252 | response.GetParentSpanId()
253 | response.GetParentSpanId()
254 | response.GetRpcRequestMetaExt()
255 |
256 | ```
257 |
258 |
259 | ### 开发Ha RPC客户端
260 |
261 | ```go
262 | urls := []baidurpc.URL{{Host: host, Port: &errPort}, {Host: host, Port: port}}
263 |
264 | connections, err := baidurpc.NewBatchTCPConnection(urls, timeout)
265 | if err != nil {
266 | fmt.Println(err)
267 | os.Exit(-1)
268 | }
269 | defer baidurpc.CloseBatchConnection(connections)
270 |
271 | haClient, err := baidurpc.NewHaRpcCient(connections)
272 | if err != nil {
273 | fmt.Println(err)
274 | os.Exit(-1)
275 | }
276 |
277 | serviceName := "echoService"
278 | methodName := "echo"
279 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
280 |
281 | message := "say hello from xiemalin中文测试"
282 | dm := DataMessage{&message}
283 |
284 | rpcInvocation.SetParameterIn(&dm)
285 | rpcInvocation.LogId = proto.Int64(1)
286 | rpcInvocation.Attachment = []byte("hello world")
287 |
288 | parameterOut := DataMessage{}
289 |
290 | response, err := haClient.SendRpcRequest(rpcInvocation, ¶meterOut)
291 | if err != nil {
292 | fmt.Println(err)
293 | os.Exit(-1)
294 | }
295 |
296 | if response == nil {
297 | fmt.Println("Reponse is nil")
298 | return
299 | }
300 |
301 | fmt.Println("attachement", response.Attachment)
302 |
303 | ```
304 |
--------------------------------------------------------------------------------
/pb_status.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // versions:
3 | // protoc-gen-go v1.26.0
4 | // protoc v3.9.2
5 | // source: go.proto
6 |
7 | package baidurpc
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 | type RPCStatus struct {
24 | state protoimpl.MessageState
25 | sizeCache protoimpl.SizeCache
26 | unknownFields protoimpl.UnknownFields
27 |
28 | Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"`
29 | Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"`
30 | TimeoutSenconds int32 `protobuf:"varint,3,opt,name=timeout,proto3" json:"timeout,omitempty"`
31 | Methods []*RPCMethod `protobuf:"bytes,4,rep,name=methods,proto3" json:"methods,omitempty"`
32 | }
33 |
34 | func (x *RPCStatus) Reset() {
35 | *x = RPCStatus{}
36 | if protoimpl.UnsafeEnabled {
37 | mi := &file_go_proto_msgTypes[0]
38 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
39 | ms.StoreMessageInfo(mi)
40 | }
41 | }
42 |
43 | func (x *RPCStatus) String() string {
44 | return protoimpl.X.MessageStringOf(x)
45 | }
46 |
47 | func (*RPCStatus) ProtoMessage() {}
48 |
49 | func (x *RPCStatus) ProtoReflect() protoreflect.Message {
50 | mi := &file_go_proto_msgTypes[0]
51 | if protoimpl.UnsafeEnabled && x != nil {
52 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
53 | if ms.LoadMessageInfo() == nil {
54 | ms.StoreMessageInfo(mi)
55 | }
56 | return ms
57 | }
58 | return mi.MessageOf(x)
59 | }
60 |
61 | // Deprecated: Use RPCStatus.ProtoReflect.Descriptor instead.
62 | func (*RPCStatus) Descriptor() ([]byte, []int) {
63 | return file_go_proto_rawDescGZIP(), []int{0}
64 | }
65 |
66 | func (x *RPCStatus) GetHost() string {
67 | if x != nil {
68 | return x.Host
69 | }
70 | return ""
71 | }
72 |
73 | func (x *RPCStatus) GetPort() int32 {
74 | if x != nil {
75 | return x.Port
76 | }
77 | return 0
78 | }
79 |
80 | func (x *RPCStatus) GetTimeout() int32 {
81 | if x != nil {
82 | return x.TimeoutSenconds
83 | }
84 | return 0
85 | }
86 |
87 | func (x *RPCStatus) GetMethods() []*RPCMethod {
88 | if x != nil {
89 | return x.Methods
90 | }
91 | return nil
92 | }
93 |
94 | type RPCMethod struct {
95 | state protoimpl.MessageState
96 | sizeCache protoimpl.SizeCache
97 | unknownFields protoimpl.UnknownFields
98 |
99 | Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
100 | Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"`
101 | InTypeMeta string `protobuf:"bytes,3,opt,name=intype,proto3" json:"intype,omitempty"`
102 | ReturnTypeMeta string `protobuf:"bytes,4,opt,name=returntype,proto3" json:"returntype,omitempty"`
103 | }
104 |
105 | func (x *RPCMethod) Reset() {
106 | *x = RPCMethod{}
107 | if protoimpl.UnsafeEnabled {
108 | mi := &file_go_proto_msgTypes[1]
109 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
110 | ms.StoreMessageInfo(mi)
111 | }
112 | }
113 |
114 | func (x *RPCMethod) String() string {
115 | return protoimpl.X.MessageStringOf(x)
116 | }
117 |
118 | func (*RPCMethod) ProtoMessage() {}
119 |
120 | func (x *RPCMethod) ProtoReflect() protoreflect.Message {
121 | mi := &file_go_proto_msgTypes[1]
122 | if protoimpl.UnsafeEnabled && x != nil {
123 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
124 | if ms.LoadMessageInfo() == nil {
125 | ms.StoreMessageInfo(mi)
126 | }
127 | return ms
128 | }
129 | return mi.MessageOf(x)
130 | }
131 |
132 | // Deprecated: Use RPCMethod.ProtoReflect.Descriptor instead.
133 | func (*RPCMethod) Descriptor() ([]byte, []int) {
134 | return file_go_proto_rawDescGZIP(), []int{1}
135 | }
136 |
137 | func (x *RPCMethod) GetService() string {
138 | if x != nil {
139 | return x.Service
140 | }
141 | return ""
142 | }
143 |
144 | func (x *RPCMethod) GetMethod() string {
145 | if x != nil {
146 | return x.Method
147 | }
148 | return ""
149 | }
150 |
151 | func (x *RPCMethod) GetInTypeMeta() string {
152 | if x != nil {
153 | return x.InTypeMeta
154 | }
155 | return ""
156 | }
157 |
158 | func (x *RPCMethod) GetReturnTypeMeta() string {
159 | if x != nil {
160 | return x.ReturnTypeMeta
161 | }
162 | return ""
163 | }
164 |
165 | type QpsData struct {
166 | state protoimpl.MessageState
167 | sizeCache protoimpl.SizeCache
168 | unknownFields protoimpl.UnknownFields
169 |
170 | Qpsinfo map[int64]int32 `protobuf:"bytes,1,rep,name=qpsinfo,proto3" json:"qpsinfo,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
171 | }
172 |
173 | func (x *QpsData) Reset() {
174 | *x = QpsData{}
175 | if protoimpl.UnsafeEnabled {
176 | mi := &file_go_proto_msgTypes[2]
177 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
178 | ms.StoreMessageInfo(mi)
179 | }
180 | }
181 |
182 | func (x *QpsData) String() string {
183 | return protoimpl.X.MessageStringOf(x)
184 | }
185 |
186 | func (*QpsData) ProtoMessage() {}
187 |
188 | func (x *QpsData) ProtoReflect() protoreflect.Message {
189 | mi := &file_go_proto_msgTypes[2]
190 | if protoimpl.UnsafeEnabled && x != nil {
191 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
192 | if ms.LoadMessageInfo() == nil {
193 | ms.StoreMessageInfo(mi)
194 | }
195 | return ms
196 | }
197 | return mi.MessageOf(x)
198 | }
199 |
200 | // Deprecated: Use QpsData.ProtoReflect.Descriptor instead.
201 | func (*QpsData) Descriptor() ([]byte, []int) {
202 | return file_go_proto_rawDescGZIP(), []int{2}
203 | }
204 |
205 | func (x *QpsData) GetQpsinfo() map[int64]int32 {
206 | if x != nil {
207 | return x.Qpsinfo
208 | }
209 | return nil
210 | }
211 |
212 | var File_go_proto protoreflect.FileDescriptor
213 |
214 | var file_go_proto_rawDesc = []byte{
215 | 0x0a, 0x08, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x09, 0x52, 0x50,
216 | 0x43, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18,
217 | 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70,
218 | 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12,
219 | 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
220 | 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x24, 0x0a, 0x07, 0x6d, 0x65, 0x74,
221 | 0x68, 0x6f, 0x64, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x50, 0x43,
222 | 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22,
223 | 0x85, 0x01, 0x0a, 0x09, 0x52, 0x50, 0x43, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x18, 0x0a,
224 | 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
225 | 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f,
226 | 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12,
227 | 0x1e, 0x0a, 0x0a, 0x49, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20,
228 | 0x01, 0x28, 0x09, 0x52, 0x0a, 0x49, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12,
229 | 0x26, 0x0a, 0x0e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x65, 0x74,
230 | 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x54,
231 | 0x79, 0x70, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x22, 0x76, 0x0a, 0x07, 0x51, 0x70, 0x73, 0x44, 0x61,
232 | 0x74, 0x61, 0x12, 0x2f, 0x0a, 0x07, 0x71, 0x70, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20,
233 | 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x51, 0x70, 0x73, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x51, 0x70,
234 | 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x71, 0x70, 0x73, 0x69,
235 | 0x6e, 0x66, 0x6f, 0x1a, 0x3a, 0x0a, 0x0c, 0x51, 0x70, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x45, 0x6e,
236 | 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
237 | 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
238 | 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42,
239 | 0x22, 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61,
240 | 0x69, 0x64, 0x75, 0x2d, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x62, 0x61, 0x69, 0x64, 0x75,
241 | 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
242 | }
243 |
244 | var (
245 | file_go_proto_rawDescOnce sync.Once
246 | file_go_proto_rawDescData = file_go_proto_rawDesc
247 | )
248 |
249 | func file_go_proto_rawDescGZIP() []byte {
250 | file_go_proto_rawDescOnce.Do(func() {
251 | file_go_proto_rawDescData = protoimpl.X.CompressGZIP(file_go_proto_rawDescData)
252 | })
253 | return file_go_proto_rawDescData
254 | }
255 |
256 | var file_go_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
257 | var file_go_proto_goTypes = []interface{}{
258 | (*RPCStatus)(nil), // 0: RPCStatus
259 | (*RPCMethod)(nil), // 1: RPCMethod
260 | (*QpsData)(nil), // 2: QpsData
261 | nil, // 3: QpsData.QpsinfoEntry
262 | }
263 | var file_go_proto_depIdxs = []int32{
264 | 1, // 0: RPCStatus.methods:type_name -> RPCMethod
265 | 3, // 1: QpsData.qpsinfo:type_name -> QpsData.QpsinfoEntry
266 | 2, // [2:2] is the sub-list for method output_type
267 | 2, // [2:2] is the sub-list for method input_type
268 | 2, // [2:2] is the sub-list for extension type_name
269 | 2, // [2:2] is the sub-list for extension extendee
270 | 0, // [0:2] is the sub-list for field type_name
271 | }
272 |
273 | func init() { file_go_proto_init() }
274 | func file_go_proto_init() {
275 | if File_go_proto != nil {
276 | return
277 | }
278 | if !protoimpl.UnsafeEnabled {
279 | file_go_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
280 | switch v := v.(*RPCStatus); i {
281 | case 0:
282 | return &v.state
283 | case 1:
284 | return &v.sizeCache
285 | case 2:
286 | return &v.unknownFields
287 | default:
288 | return nil
289 | }
290 | }
291 | file_go_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
292 | switch v := v.(*RPCMethod); i {
293 | case 0:
294 | return &v.state
295 | case 1:
296 | return &v.sizeCache
297 | case 2:
298 | return &v.unknownFields
299 | default:
300 | return nil
301 | }
302 | }
303 | file_go_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
304 | switch v := v.(*QpsData); i {
305 | case 0:
306 | return &v.state
307 | case 1:
308 | return &v.sizeCache
309 | case 2:
310 | return &v.unknownFields
311 | default:
312 | return nil
313 | }
314 | }
315 | }
316 | type x struct{}
317 | out := protoimpl.TypeBuilder{
318 | File: protoimpl.DescBuilder{
319 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
320 | RawDescriptor: file_go_proto_rawDesc,
321 | NumEnums: 0,
322 | NumMessages: 4,
323 | NumExtensions: 0,
324 | NumServices: 0,
325 | },
326 | GoTypes: file_go_proto_goTypes,
327 | DependencyIndexes: file_go_proto_depIdxs,
328 | MessageInfos: file_go_proto_msgTypes,
329 | }.Build()
330 | File_go_proto = out.File
331 | file_go_proto_rawDesc = nil
332 | file_go_proto_goTypes = nil
333 | file_go_proto_depIdxs = nil
334 | }
335 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/client.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "errors"
20 | "fmt"
21 | "log"
22 | "net"
23 | "sync/atomic"
24 | "time"
25 |
26 | "github.com/jhunters/goassist/concurrent/syncx"
27 | "github.com/jhunters/timewheel"
28 | "google.golang.org/protobuf/proto"
29 | )
30 |
31 | var (
32 | defaultTimewheelInterval = 10 * time.Millisecond
33 | defaultTimewheelSlot = 300
34 |
35 | errNeedInit = errors.New("[client-001]Session is not initialized, Please use NewRpcInvocation() to create instance")
36 | errResponseNil = errors.New("[client-003]No response result, mybe net work broken error")
37 | LOG_SERVER_RESPONSE_ERROR = "[client-002]Server response error. code=%d, msg='%s'"
38 | LOG_CLIENT_TIMECOUST_INFO = "[client-101]Server name '%s' method '%s' process cost '%.5g' seconds"
39 |
40 | closedTimeOut = time.Duration(0)
41 | )
42 |
43 | const (
44 | ST_READ_TIMEOUT = 62
45 | )
46 |
47 | /*
48 | RPC client invoke
49 | */
50 | type RpcClient struct {
51 | Session Connection
52 | tw *timewheel.TimeWheel[*RpcDataPackage]
53 |
54 | // 单次请求唯一标识
55 | correlationId int64
56 | // async request state map
57 | requestCallState *syncx.Map[int64, chan *RpcDataPackage] // use sync map for cocurrent access
58 |
59 | // to close loop receive
60 | closeChan chan bool
61 |
62 | asyncMode bool
63 | }
64 |
65 | // URL with host and port attribute
66 | type URL struct {
67 | Host *string
68 | Port *int
69 | }
70 |
71 | // SetHost set host name
72 | func (u *URL) SetHost(host *string) *URL {
73 | u.Host = host
74 | return u
75 | }
76 |
77 | // SetPort set port
78 | func (u *URL) SetPort(port *int) *URL {
79 | u.Port = port
80 | return u
81 | }
82 |
83 | // RpcInvocation define rpc invocation
84 | type RpcInvocation struct {
85 | ServiceName *string
86 | MethodName *string
87 | ParameterIn *proto.Message
88 | Attachment []byte
89 | LogId *int64
90 | CompressType *int32
91 | AuthenticateData []byte
92 | ChunkSize uint32
93 | TraceId int64
94 | SpanId int64
95 | ParentSpanId int64
96 | RpcRequestMetaExt map[string]string
97 | }
98 |
99 | // NewRpcCient new rpc client
100 | func NewRpcCient(connection Connection) (*RpcClient, error) {
101 | return NewRpcCientWithTimeWheelSetting(connection, defaultTimewheelInterval, uint16(defaultTimewheelSlot))
102 | }
103 |
104 | // NewRpcCientWithTimeWheelSetting new rpc client with set timewheel settings
105 | func NewRpcCientWithTimeWheelSetting(connection Connection, timewheelInterval time.Duration, timewheelSlot uint16) (*RpcClient, error) {
106 | c := RpcClient{}
107 | c.Session = connection
108 |
109 | // async mode not support under pooled connection
110 | _, pooled := connection.(*TCPConnectionPool)
111 | c.asyncMode = !pooled
112 |
113 | // initial timewheel to process async request on time out event handle
114 | c.tw, _ = timewheel.New[*RpcDataPackage](timewheelInterval, timewheelSlot)
115 | c.tw.Start()
116 | c.closeChan = make(chan bool, 1)
117 | c.requestCallState = syncx.NewMap[int64, chan *RpcDataPackage]() // make(map[int64]chan *RpcDataPackage)
118 |
119 | if c.asyncMode { // only enabled on async mode
120 | go c.startLoopReceive()
121 | }
122 | return &c, nil
123 | }
124 |
125 | // NewRpcInvocation create RpcInvocation with service name and method name
126 | func NewRpcInvocation(serviceName, methodName *string) *RpcInvocation {
127 | r := new(RpcInvocation)
128 | r.init(serviceName, methodName)
129 |
130 | return r
131 | }
132 |
133 | func (r *RpcInvocation) init(serviceName, methodName *string) {
134 |
135 | *r = RpcInvocation{}
136 | r.ServiceName = serviceName
137 | r.MethodName = methodName
138 | compressType := COMPRESS_NO
139 | r.CompressType = &compressType
140 | r.ParameterIn = nil
141 | }
142 |
143 | // SetParameterIn
144 | func (r *RpcInvocation) SetParameterIn(parameterIn proto.Message) {
145 | r.ParameterIn = ¶meterIn
146 | }
147 |
148 | // GetRequestRpcDataPackage
149 | func (r *RpcInvocation) GetRequestRpcDataPackage() (*RpcDataPackage, error) {
150 |
151 | rpcDataPackage := new(RpcDataPackage)
152 | rpcDataPackage.ServiceName(*r.ServiceName)
153 | rpcDataPackage.MethodName(*r.MethodName)
154 | rpcDataPackage.MagicCode(MAGIC_CODE)
155 | rpcDataPackage.AuthenticationData(r.AuthenticateData)
156 | rpcDataPackage.chunkSize = r.ChunkSize
157 | rpcDataPackage.TraceId(r.TraceId)
158 | rpcDataPackage.SpanId(r.SpanId)
159 | rpcDataPackage.ParentSpanId(r.ParentSpanId)
160 | rpcDataPackage.RpcRequestMetaExt(r.RpcRequestMetaExt)
161 | if r.CompressType != nil {
162 | rpcDataPackage.CompressType(*r.CompressType)
163 | }
164 | if r.LogId != nil {
165 | rpcDataPackage.LogId(*r.LogId)
166 | }
167 |
168 | rpcDataPackage.SetAttachment(r.Attachment)
169 |
170 | if r.ParameterIn != nil {
171 | data, err := proto.Marshal(*r.ParameterIn)
172 | if err != nil {
173 | return nil, err
174 | }
175 | rpcDataPackage.SetData(data)
176 | }
177 |
178 | return rpcDataPackage, nil
179 | }
180 |
181 | // define client methods
182 | // Close close client with time wheel
183 | func (c *RpcClient) Close() {
184 | c.closeChan <- true
185 | if c.tw != nil {
186 | c.tw.Stop()
187 | }
188 | }
189 |
190 | func (c *RpcClient) startLoopReceive() {
191 | for {
192 |
193 | select {
194 | case <-c.closeChan:
195 | // exit loop
196 | return
197 | default:
198 | dataPackage, err := c.safeReceive()
199 | if err != nil {
200 |
201 | netErr, ok := err.(*net.OpError)
202 | if ok {
203 | // if met network error, wait some time to retry or call client close method to close loop if met net error
204 | // error maybe about broken network or closed network
205 | log.Println(netErr)
206 | if !netErr.Timeout() {
207 | // try reconnect
208 | c.Session.Reconnect()
209 | }
210 |
211 | }
212 | time.Sleep(200 * time.Millisecond)
213 |
214 | }
215 |
216 | if dataPackage != nil && dataPackage.Meta != nil {
217 | correlationId := dataPackage.Meta.GetCorrelationId()
218 | v, exist := c.requestCallState.LoadAndDelete(correlationId) // [correlationId]
219 | if !exist {
220 | // bad response correlationId
221 | Errorf("bad correlationId '%d' not exist ", correlationId)
222 | continue
223 | }
224 | go func() {
225 | v <- dataPackage
226 | }()
227 | }
228 | }
229 |
230 | }
231 | }
232 |
233 | func (c *RpcClient) safeReceive() (*RpcDataPackage, error) {
234 | defer func() {
235 | if p := recover(); p != nil {
236 | Warningf("receive catched panic error %v", p)
237 | }
238 | }()
239 | return c.Session.Receive()
240 | }
241 |
242 | // asyncRequest
243 | func (c *RpcClient) asyncRequest(timeout time.Duration, request *RpcDataPackage, ch chan *RpcDataPackage) {
244 | // create a task bind with key, data and time out call back function.
245 | t := &timewheel.Task[*RpcDataPackage]{
246 | Data: request, // business data
247 | TimeoutCallback: func(task timewheel.Task[*RpcDataPackage]) { // call back function on time out
248 | // process someting after time out happened.
249 | errorcode := int32(ST_READ_TIMEOUT)
250 | task.Data.ErrorCode(errorcode)
251 | errormsg := fmt.Sprintf("request time out of %v", task.Delay())
252 | task.Data.ErrorText(errormsg)
253 | ch <- request
254 | }}
255 |
256 | // add task and return unique task id
257 | taskid, err := c.tw.AddTask(timeout, *t) // add delay task
258 | if err != nil {
259 | errorcode := int32(ST_ERROR)
260 | request.ErrorCode(errorcode)
261 | errormsg := err.Error()
262 | request.ErrorText(errormsg)
263 |
264 | ch <- request
265 | return
266 | }
267 |
268 | defer func() {
269 | c.tw.RemoveTask(taskid)
270 | if e := recover(); e != nil {
271 | Warningf("asyncRequest failed with error %v", e)
272 | }
273 | }()
274 |
275 | rsp, err := c.doSendReceive(request, ch)
276 | if err != nil {
277 | errorcode := int32(ST_ERROR)
278 | request.ErrorCode(errorcode)
279 | errormsg := err.Error()
280 | request.ErrorText(errormsg)
281 |
282 | ch <- request
283 | return
284 | }
285 |
286 | ch <- rsp
287 | }
288 |
289 | func (c *RpcClient) doSendReceive(rpcDataPackage *RpcDataPackage, ch <-chan *RpcDataPackage) (*RpcDataPackage, error) {
290 | if c.asyncMode {
291 | err := c.Session.Send(rpcDataPackage)
292 | if err != nil {
293 | return nil, err
294 | }
295 | // async wait response
296 | return <-ch, nil
297 | }
298 | // not async mode use block request
299 | return c.Session.SendReceive(rpcDataPackage)
300 |
301 | }
302 |
303 | // SendRpcRequest send rpc request to remote server
304 | func (c *RpcClient) SendRpcRequest(rpcInvocation *RpcInvocation, responseMessage proto.Message) (*RpcDataPackage, error) {
305 | return c.SendRpcRequestWithTimeout(closedTimeOut, rpcInvocation, responseMessage)
306 |
307 | }
308 |
309 | // SendRpcRequest send rpc request to remote server
310 | func (c *RpcClient) SendRpcRequestWithTimeout(timeout time.Duration, rpcInvocation *RpcInvocation, responseMessage proto.Message) (*RpcDataPackage, error) {
311 | if c.Session == nil {
312 | return nil, errNeedInit
313 | }
314 |
315 | now := time.Now().UnixNano()
316 |
317 | rpcDataPackage, err := rpcInvocation.GetRequestRpcDataPackage()
318 | if err != nil {
319 | return nil, err
320 | }
321 |
322 | // set request unique id
323 | correlationId := atomic.AddInt64(&c.correlationId, 1)
324 | rpcDataPackage.CorrelationId(correlationId)
325 |
326 | var rsp *RpcDataPackage
327 | if c.asyncMode {
328 | ch := make(chan *RpcDataPackage, 1)
329 | c.requestCallState.Store(correlationId, ch)
330 |
331 | if timeout > 0 {
332 | go c.asyncRequest(timeout, rpcDataPackage, ch)
333 | rsp = <-ch //异步等待返回, 可能返回的情况 1. 本地错误或超时返回 2. startLoopReceive 监听远程数据返回
334 | } else {
335 | rsp, err = c.doSendReceive(rpcDataPackage, ch)
336 | }
337 |
338 | } else {
339 | if timeout > 0 {
340 | ch := make(chan *RpcDataPackage, 1)
341 | go c.asyncRequest(timeout, rpcDataPackage, ch)
342 | defer close(ch)
343 | // wait for message
344 | rsp = <-ch
345 | } else {
346 | rsp, err = c.Session.SendReceive(rpcDataPackage)
347 | }
348 | }
349 |
350 | if err != nil {
351 | errorcode := int32(ST_ERROR)
352 | rpcDataPackage.ErrorCode(errorcode)
353 | errormsg := err.Error()
354 | rpcDataPackage.ErrorText(errormsg)
355 | return rpcDataPackage, err
356 | }
357 |
358 | r := rsp
359 | if r == nil {
360 | return nil, errResponseNil //to ignore this nil value
361 | }
362 |
363 | errorCode := r.GetMeta().GetResponse().GetErrorCode()
364 | if errorCode > 0 {
365 | errMsg := fmt.Sprintf(LOG_SERVER_RESPONSE_ERROR,
366 | errorCode, r.GetMeta().GetResponse().GetErrorText())
367 | return r, errors.New(errMsg)
368 | }
369 |
370 | response := r.GetData()
371 | if response != nil {
372 | err = proto.Unmarshal(response, responseMessage)
373 | if err != nil {
374 | return r, err
375 | }
376 | }
377 |
378 | took := TimetookInSeconds(now)
379 | Infof(LOG_CLIENT_TIMECOUST_INFO, *rpcInvocation.ServiceName, *rpcInvocation.MethodName, took)
380 |
381 | return r, nil
382 |
383 | }
384 |
385 | // RpcResult Rpc response result from client request api under asynchronous way
386 | type RpcResult struct {
387 | rpcData *RpcDataPackage
388 | err error
389 | message proto.Message
390 | }
391 |
392 | func (rr *RpcResult) Get() proto.Message {
393 | return rr.message
394 | }
395 |
396 | func (rr *RpcResult) GetRpcDataPackage() *RpcDataPackage {
397 | return rr.rpcData
398 | }
399 |
400 | func (rr *RpcResult) GetErr() error {
401 | return rr.err
402 | }
403 |
404 | // SendRpcRequestAsyc send rpc request to remote server in asynchronous way
405 | func (c *RpcClient) SendRpcRequestAsyc(rpcInvocation *RpcInvocation, responseMessage proto.Message) <-chan *RpcResult {
406 | ch := make(chan *RpcResult, 1)
407 |
408 | go func() {
409 | defer func() {
410 | if p := recover(); p != nil {
411 | if err, ok := p.(error); ok {
412 | r := &RpcResult{nil, err, responseMessage}
413 | ch <- r
414 | }
415 | }
416 | }()
417 |
418 | resp, err := c.SendRpcRequest(rpcInvocation, responseMessage)
419 | result := &RpcResult{resp, err, responseMessage}
420 | ch <- result
421 | }()
422 |
423 | return ch
424 | }
425 |
--------------------------------------------------------------------------------
/client_test.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc_test
17 |
18 | import (
19 | "strings"
20 | "testing"
21 | "time"
22 |
23 | baidurpc "github.com/baidu-golang/pbrpc"
24 | . "github.com/smartystreets/goconvey/convey"
25 | "google.golang.org/protobuf/proto"
26 | )
27 |
28 | const (
29 | AUTH_TOKEN = "SJIVNCQIN@#$@*sdjfsd"
30 | )
31 |
32 | type (
33 | StringMatchAuthService struct {
34 | }
35 |
36 | AddOneTraceService struct {
37 | }
38 | )
39 |
40 | // Authenticate
41 | func (as *StringMatchAuthService) Authenticate(service, name string, authToken []byte) bool {
42 | if authToken == nil {
43 | return false
44 | }
45 | return strings.Compare(AUTH_TOKEN, string(authToken)) == 0
46 | }
47 |
48 | // Trace
49 | func (as *AddOneTraceService) Trace(service, name string, traceInfo *baidurpc.TraceInfo) *baidurpc.TraceInfo {
50 | traceInfo.SpanId++
51 | traceInfo.TraceId++
52 | traceInfo.ParentSpanId++
53 | return traceInfo
54 | }
55 |
56 | // TestSingleTcpConnectionClient
57 | func TestSingleTcpConnectionClient(t *testing.T) {
58 | Convey("TestSingleTcpConnectionClient", t, func() {
59 | tcpServer := startRpcServer(0)
60 | defer stopRpcServer(tcpServer)
61 |
62 | conn, client, err := createClient()
63 | So(err, ShouldBeNil)
64 | So(conn, ShouldNotBeNil)
65 | So(client, ShouldNotBeNil)
66 | defer client.Close()
67 | defer conn.Close()
68 |
69 | testSendRpc("Client send rpc request", client, false, false, 0, false)
70 | testSendRpc("Client send rpc request(async)", client, true, false, 0, false)
71 | })
72 | }
73 |
74 | // TestSingleTcpConnectionClientWithAuthenticate
75 | func TestSingleTcpConnectionClientWithAuthenticate(t *testing.T) {
76 | Convey("TestSingleTcpConnectionClientWithAuthenticate", t, func() {
77 | tcpServer := startRpcServer(0)
78 | tcpServer.SetAuthService(new(StringMatchAuthService))
79 | defer stopRpcServer(tcpServer)
80 |
81 | conn, client, err := createClient()
82 | So(err, ShouldBeNil)
83 | So(conn, ShouldNotBeNil)
84 | So(client, ShouldNotBeNil)
85 | defer client.Close()
86 | defer conn.Close()
87 |
88 | testSendRpc("Client send rpc request", client, false, true, 0, false)
89 | testSendRpc("Client send rpc request(async)", client, true, true, 0, false)
90 | })
91 | }
92 |
93 | // TestSingleTcpConnectionClientWithChunk
94 | func TestSingleTcpConnectionClientWithChunk(t *testing.T) {
95 | Convey("TestSingleTcpConnectionClientWithChunk", t, func() {
96 | tcpServer := startRpcServer(0)
97 | tcpServer.SetAuthService(new(StringMatchAuthService))
98 | defer stopRpcServer(tcpServer)
99 |
100 | conn, client, err := createClient()
101 | So(err, ShouldBeNil)
102 | So(conn, ShouldNotBeNil)
103 | So(client, ShouldNotBeNil)
104 | defer client.Close()
105 | defer conn.Close()
106 |
107 | testSendRpc("Client send rpc request", client, false, true, 20, false)
108 | testSendRpc("Client send rpc request(async)", client, true, true, 20, false)
109 | })
110 | }
111 |
112 | // TestSingleTcpConnectionClientAndServerWithChunk
113 | func TestSingleTcpConnectionClientAndServerWithChunk(t *testing.T) {
114 | Convey("TestSingleTcpConnectionClientAndServerWithChunk", t, func() {
115 | tcpServer := startRpcServer(20)
116 | tcpServer.SetAuthService(new(StringMatchAuthService))
117 | defer stopRpcServer(tcpServer)
118 |
119 | conn, client, err := createClient()
120 | So(err, ShouldBeNil)
121 | So(conn, ShouldNotBeNil)
122 | So(client, ShouldNotBeNil)
123 | defer client.Close()
124 | defer conn.Close()
125 |
126 | testSendRpc("Client send rpc request", client, false, true, 20, false)
127 | testSendRpc("Client send rpc request(async)", client, true, true, 20, false)
128 | })
129 | }
130 |
131 | // TestSingleTcpConnectionClientWithBadChunkCase
132 | func TestSingleTcpConnectionClientWithBadChunkCase(t *testing.T) {
133 | Convey("TestSingleTcpConnectionClientWithBadChunkCase", t, func() {
134 | tcpServer := startRpcServer(0)
135 | defer stopRpcServer(tcpServer)
136 |
137 | conn, client, err := createClient()
138 | So(err, ShouldBeNil)
139 | So(conn, ShouldNotBeNil)
140 | So(client, ShouldNotBeNil)
141 | defer client.Close()
142 | defer conn.Close()
143 |
144 | serviceName := "EchoService"
145 | methodName := "echo"
146 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
147 |
148 | name := "(马林)(matthew)(XML)(jhunters)"
149 | dm := DataMessage{Name: name}
150 |
151 | rpcInvocation.SetParameterIn(&dm)
152 | rpcInvocation.LogId = proto.Int64(1)
153 |
154 | dataPackage, err := rpcInvocation.GetRequestRpcDataPackage()
155 | So(err, ShouldBeNil)
156 |
157 | dataPackage.ChuckInfo(10, 1) // bad chunk data package
158 | go func() {
159 | client.Session.SendReceive(dataPackage) // send bad chunk data package server will block unitl timeout
160 | }()
161 | time.Sleep(1 * time.Second)
162 | doSimpleRPCInvokeWithSignatureWithConvey(client, "EchoService", "echo", false, false, false, false, false, 0, false)
163 | })
164 | }
165 |
166 | // TestPooledTcpConnectionClient
167 | func TestPooledTcpConnectionClient(t *testing.T) {
168 | Convey("TestPooledTcpConnectionClient", t, func() {
169 | tcpServer := startRpcServer(0)
170 | defer stopRpcServer(tcpServer)
171 |
172 | conn, client, err := createPooledConnectionClient()
173 | So(err, ShouldBeNil)
174 | So(conn, ShouldNotBeNil)
175 | So(client, ShouldNotBeNil)
176 | defer client.Close()
177 | defer conn.Close()
178 |
179 | testSendRpc("Client send rpc request", client, false, true, 0, false)
180 | testSendRpc("Client send rpc request(async)", client, true, true, 0, false)
181 | })
182 | }
183 |
184 | // TestSingleTcpConnectionClientByAsync
185 | func TestSingleTcpConnectionClientByAsync(t *testing.T) {
186 | Convey("TestSingleTcpConnectionClientByAsync", t, func() {
187 | tcpServer := startRpcServer(0)
188 | tcpServer.SetAuthService(new(StringMatchAuthService))
189 | defer stopRpcServer(tcpServer)
190 |
191 | conn, client, err := createClient()
192 | So(err, ShouldBeNil)
193 | So(conn, ShouldNotBeNil)
194 | So(client, ShouldNotBeNil)
195 | defer client.Close()
196 | defer conn.Close()
197 |
198 | testSendRpc("Client send rpc request", client, false, true, 0, true)
199 | testSendRpc("Client send rpc request(async)", client, true, true, 0, true)
200 | })
201 | }
202 |
203 | func testSendRpc(testName string, client *baidurpc.RpcClient, timeout, auth bool, chunksize uint32, async bool) {
204 | Convey(testName, func() {
205 | Convey("Test send request EchoService!echo", func() {
206 | doSimpleRPCInvokeWithSignatureWithConvey(client, "EchoService", "echo", false, false, timeout, false, auth, chunksize, async)
207 | })
208 | Convey("Test send request EchoService!echoWithAttchement", func() {
209 | doSimpleRPCInvokeWithSignatureWithConvey(client, "EchoService", "echoWithAttchement", true, false, timeout, false, auth, chunksize, async)
210 | })
211 | Convey("Test send request EchoService!echoWithCustomizedError", func() {
212 | doSimpleRPCInvokeWithSignatureWithConvey(client, "EchoService", "echoWithCustomizedError", false, true, timeout, false, auth, chunksize, async)
213 | })
214 | Convey("Test send request EchoService!echoWithoutContext", func() {
215 | doSimpleRPCInvokeWithSignatureWithConvey(client, "EchoService", "echoWithoutContext", false, false, timeout, false, auth, chunksize, async)
216 | })
217 | Convey("Test send request EchoService!EchoSlowTest", func() {
218 | doSimpleRPCInvokeWithSignatureWithConvey(client, "EchoService", "EchoSlowTest", false, false, timeout, true, auth, chunksize, async)
219 | })
220 | })
221 | }
222 |
223 | // createRpcServer create rpc server by port and localhost
224 | func createRpcServerWithChunkSize(port int, chunksize uint32) *baidurpc.TcpServer {
225 | serverMeta := baidurpc.ServerMeta{}
226 | serverMeta.Port = Int(port)
227 | serverMeta.ChunkSize = chunksize
228 | rpcServer := baidurpc.NewTpcServer(&serverMeta)
229 | return rpcServer
230 | }
231 |
232 | func startRpcServer(chunksize uint32) *baidurpc.TcpServer {
233 | return startRpcServerWithHttpMode(chunksize, false)
234 | }
235 |
236 | // startRpcServer start rpc server and register echo service as default rpc service
237 | func startRpcServerWithHttpMode(chunksize uint32, httpMode bool) *baidurpc.TcpServer {
238 |
239 | rpcServer := createRpcServerWithChunkSize(PORT_1, chunksize)
240 |
241 | echoservice := new(EchoService)
242 | methodMapping := map[string]string{
243 | "Echo": "echo",
244 | "EchoWithAttchement": "echoWithAttchement",
245 | "EchoWithCustomizedError": "echoWithCustomizedError",
246 | "EchoWithoutContext": "echoWithoutContext",
247 | }
248 | rpcServer.RegisterNameWithMethodMapping("EchoService", echoservice, methodMapping)
249 |
250 | rpcServer.SetTraceService(new(AddOneTraceService))
251 | if httpMode {
252 | rpcServer.EnableHttp()
253 | }
254 | rpcServer.Start()
255 |
256 | return rpcServer
257 | }
258 |
259 | // createClient
260 | func createClient() (baidurpc.Connection, *baidurpc.RpcClient, error) {
261 |
262 | host := "localhost"
263 | port := PORT_1
264 |
265 | url := baidurpc.URL{}
266 | url.SetHost(&host).SetPort(&port)
267 |
268 | timeout := time.Second * 500
269 | // create client by simple connection
270 | connection, err := baidurpc.NewTCPConnection(url, &timeout)
271 | if err != nil {
272 | return nil, nil, err
273 | }
274 | rpcClient, err := baidurpc.NewRpcCient(connection)
275 | if err != nil {
276 | return nil, nil, err
277 | }
278 | return connection, rpcClient, nil
279 | }
280 |
281 | // createClient
282 | func createPooledConnectionClient() (baidurpc.Connection, *baidurpc.RpcClient, error) {
283 |
284 | host := "localhost"
285 | port := PORT_1
286 |
287 | url := baidurpc.URL{}
288 | url.SetHost(&host).SetPort(&port)
289 |
290 | timeout := time.Second * 5
291 | // create client by simple connection
292 | connection, err := baidurpc.NewTCPConnectionPool(url, &timeout, nil)
293 | if err != nil {
294 | return nil, nil, err
295 | }
296 | rpcClient, err := baidurpc.NewRpcCient(connection)
297 | if err != nil {
298 | return nil, nil, err
299 | }
300 | return connection, rpcClient, nil
301 | }
302 |
303 | // doSimpleRPCInvokeWithSignatureWithConvey send rpc request
304 | func doSimpleRPCInvokeWithSignatureWithConvey(rpcClient *baidurpc.RpcClient, serviceName, methodName string,
305 | withAttachement, withCustomErr, timeout, timeoutCheck, auth bool, chunkSize uint32, async bool) {
306 | Convey("Test Client send rpc request", func() {
307 | rpcInvocation := baidurpc.NewRpcInvocation(&serviceName, &methodName)
308 |
309 | name := "(马林)(matthew)(XML)(jhunters)"
310 | dm := DataMessage{Name: name}
311 |
312 | rpcInvocation.SetParameterIn(&dm)
313 | rpcInvocation.LogId = proto.Int64(1)
314 | rpcInvocation.ChunkSize = chunkSize
315 | rpcInvocation.TraceId = 10
316 | rpcInvocation.SpanId = 11
317 | rpcInvocation.ParentSpanId = 12
318 | rpcInvocation.RpcRequestMetaExt = map[string]string{"key1": "value1"}
319 |
320 | if withAttachement {
321 | rpcInvocation.Attachment = []byte("This is attachment data")
322 | }
323 |
324 | if auth {
325 | rpcInvocation.AuthenticateData = []byte(AUTH_TOKEN)
326 | }
327 |
328 | parameterOut := DataMessage{}
329 | var response *baidurpc.RpcDataPackage
330 | var err error
331 | if timeout {
332 | response, err = rpcClient.SendRpcRequestWithTimeout(1*time.Second, rpcInvocation, ¶meterOut)
333 | if timeoutCheck {
334 | So(err, ShouldNotBeNil)
335 | return
336 | }
337 | } else {
338 | if async {
339 | ch := rpcClient.SendRpcRequestAsyc(rpcInvocation, ¶meterOut)
340 | rpcResult := <-ch
341 | response = rpcResult.GetRpcDataPackage()
342 | err = rpcResult.GetErr()
343 | } else {
344 | response, err = rpcClient.SendRpcRequest(rpcInvocation, ¶meterOut)
345 | }
346 | }
347 | if withCustomErr {
348 | So(err, ShouldNotBeNil)
349 | return
350 | } else {
351 | So(err, ShouldBeNil)
352 | }
353 | So(response, ShouldNotBeNil)
354 | expect := "hello " + name
355 | So(expect, ShouldEqual, parameterOut.Name)
356 |
357 | if withAttachement {
358 | So(string(response.Attachment), ShouldEqual, "I am a attachement, This is attachment data")
359 | }
360 |
361 | So(response.GetTraceId(), ShouldEqual, rpcInvocation.TraceId+1)
362 | So(response.GetParentSpanId(), ShouldEqual, rpcInvocation.ParentSpanId+1)
363 | So(response.GetParentSpanId(), ShouldEqual, rpcInvocation.ParentSpanId+1)
364 | So(response.GetRpcRequestMetaExt()["key1"], ShouldEqual, "value1")
365 | })
366 |
367 | }
368 |
--------------------------------------------------------------------------------
/rpcpackage.go:
--------------------------------------------------------------------------------
1 | // Go support for Protocol Buffers RPC which compatible with https://github.com/Baidu-ecom/Jprotobuf-rpc-socket
2 | //
3 | // Copyright 2002-2007 the original author or authors.
4 | //
5 | // Licensed under the Apache License, Version 2.0 (the "License");
6 | // you may not use this file except in compliance with the License.
7 | // You may obtain a copy of the License at
8 | //
9 | // http://www.apache.org/licenses/LICENSE-2.0
10 | //
11 | // Unless required by applicable law or agreed to in writing, software
12 | // distributed under the License is distributed on an "AS IS" BASIS,
13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | // See the License for the specific language governing permissions and
15 | // limitations under the License.
16 | package baidurpc
17 |
18 | import (
19 | "bytes"
20 | "encoding/binary"
21 | "errors"
22 | "fmt"
23 | "io"
24 | "log"
25 | "math/rand"
26 | "strings"
27 |
28 | "github.com/golang/snappy"
29 | "google.golang.org/protobuf/proto"
30 | )
31 |
32 | // error log info definition
33 | var (
34 | errIgnoreErr = errors.New("[marshal-001]Ingore error")
35 | errMeta = errors.New("[marshal-003]Get nil value from Meta struct after marshal")
36 | LOG_INVALID_BYTES = "[marshal-004]Invalid byte array. maybe a broken byte stream. Received '%b'"
37 | )
38 |
39 | /*
40 | Data package for baidu RPC.
41 | all request and response data package should apply this.
42 |
43 | -----------------------------------
44 | | Head | Meta | Data | Attachment |
45 | -----------------------------------
46 |
47 | 1. with fixed 12 byte length as follow format
48 | ----------------------------------------------
49 | | PRPC | MessageSize(int32) | MetaSize(int32) |
50 | ----------------------------------------------
51 | MessageSize = totalSize - 12(Fixed Head Size)
52 | MetaSize = Meta object size
53 |
54 | 2. body proto description as follow
55 |
56 | message RpcMeta {
57 | optional Request request = 1;
58 | optional Response response = 2;
59 | optional int32 compress_type = 3; // 0:nocompress 1:Snappy 2:gzip
60 | optional int64 correlation_id = 4;
61 | optional int32 attachment_size = 5;
62 | optional ChuckInfo chuck_info = 6;
63 | optional bytes authentication_data = 7;
64 | };
65 |
66 | message Request {
67 | required string service_name = 1;
68 | required string method_name = 2;
69 | optional int64 log_id = 3;
70 | optional int64 traceId=4;
71 | optional int64 spanId=5;
72 | optional int64 parentSpanId=6;
73 | repeat RpcRequestMetaExtField extFields = 7;
74 | };
75 |
76 | message RpcRequestMetaExtField {
77 | optional string key = 1;
78 | optional string value = 2;
79 | }
80 |
81 | message Response {
82 | optional int32 error_code = 1;
83 | optional string error_text = 2;
84 | };
85 |
86 | messsage ChuckInfo {
87 | required int64 stream_id = 1;
88 | required int64 chunk_id = 2;
89 | };
90 |
91 | 3. customize transport data message.
92 |
93 | 4. attachment body data message
94 | */
95 | type RpcDataPackage struct {
96 | Head *Header // rpc head
97 | Meta *RpcMeta // rpc meta
98 | Data []byte
99 | Attachment []byte
100 |
101 | // private field
102 | chunkSize uint32
103 | }
104 |
105 | // NewRpcDataPackage returns a new RpcDataPackage and init all fields
106 | func NewRpcDataPackage() *RpcDataPackage {
107 | data := RpcDataPackage{}
108 | doInit(&data)
109 |
110 | data.GetMeta().Response = &Response{}
111 |
112 | return &data
113 | }
114 |
115 | // Clear to clear and init all fields
116 | func (r *RpcDataPackage) Clear() {
117 | // r.Head = &Header{}
118 | // r.Meta = &RpcMeta{}
119 | request := r.Meta.Request
120 | if request == nil {
121 | r.Meta.Request = &Request{}
122 | }
123 | response := r.Meta.Response
124 | if response == nil {
125 | r.Meta.Response = &Response{}
126 | }
127 | r.Data = nil
128 | r.Attachment = nil
129 | r.ClearChunkStatus()
130 | }
131 |
132 | // MagicCode set magic code field
133 | func (r *RpcDataPackage) MagicCode(magicCode string) {
134 | if len(magicCode) != 4 {
135 | return
136 | }
137 |
138 | initHeader(r)
139 | r.Head.SetMagicCode([]byte(magicCode))
140 |
141 | }
142 |
143 | // GetMagicCode return magic code value
144 | func (r *RpcDataPackage) GetMagicCode() string {
145 | initHeader(r)
146 | return string(r.Head.GetMagicCode())
147 |
148 | }
149 |
150 | func initHeader(r *RpcDataPackage) {
151 | if r.Head == nil {
152 | r.Head = &Header{}
153 | }
154 | }
155 |
156 | func initRpcMeta(r *RpcDataPackage) {
157 | if r.Meta == nil {
158 | r.Meta = &RpcMeta{}
159 | }
160 | }
161 |
162 | func initChuckInfo(r *RpcDataPackage) {
163 | initRpcMeta(r)
164 | if r.Meta.ChuckInfo == nil {
165 | r.Meta.ChuckInfo = &ChunkInfo{}
166 | }
167 | }
168 |
169 | func initRequest(r *RpcDataPackage) {
170 | initRpcMeta(r)
171 |
172 | request := r.Meta.Request
173 | if request == nil {
174 | r.Meta.Request = &Request{}
175 | }
176 |
177 | }
178 |
179 | func initResponse(r *RpcDataPackage) {
180 | initRpcMeta(r)
181 |
182 | response := r.Meta.Response
183 | if response == nil {
184 | r.Meta.Response = &Response{}
185 | }
186 |
187 | }
188 |
189 | // ServiceName set service name field
190 | func (r *RpcDataPackage) ServiceName(serviceName string) *RpcDataPackage {
191 | initRequest(r)
192 |
193 | r.Meta.Request.ServiceName = serviceName
194 |
195 | return r
196 | }
197 |
198 | // MethodName set method name field
199 | func (r *RpcDataPackage) MethodName(methodName string) *RpcDataPackage {
200 | initRequest(r)
201 |
202 | r.Meta.Request.MethodName = methodName
203 |
204 | return r
205 | }
206 |
207 | // SetData set data
208 | func (r *RpcDataPackage) SetData(Data []byte) *RpcDataPackage {
209 | r.Data = Data
210 | return r
211 | }
212 |
213 | // SetAttachment set attachment
214 | func (r *RpcDataPackage) SetAttachment(Attachment []byte) *RpcDataPackage {
215 | r.Attachment = Attachment
216 | return r
217 | }
218 |
219 | // AuthenticationData set authentication data
220 | func (r *RpcDataPackage) AuthenticationData(authenticationData []byte) *RpcDataPackage {
221 | initRpcMeta(r)
222 |
223 | r.Meta.AuthenticationData = authenticationData
224 | return r
225 | }
226 |
227 | // CorrelationId set correlationId data
228 | func (r *RpcDataPackage) CorrelationId(correlationId int64) *RpcDataPackage {
229 | initRpcMeta(r)
230 |
231 | r.Meta.CorrelationId = correlationId
232 | return r
233 | }
234 |
235 | // CompressType set compress type data
236 | func (r *RpcDataPackage) CompressType(compressType int32) *RpcDataPackage {
237 | initRpcMeta(r)
238 |
239 | r.Meta.CompressType = compressType
240 | return r
241 | }
242 |
243 | // LogId set log id data
244 | func (r *RpcDataPackage) LogId(logId int64) *RpcDataPackage {
245 | initRequest(r)
246 |
247 | r.Meta.Request.LogId = logId
248 |
249 | return r
250 | }
251 |
252 | // GetLogId return log id
253 | func (r *RpcDataPackage) GetLogId() int64 {
254 | initRequest(r)
255 | return r.Meta.Request.GetLogId()
256 | }
257 |
258 | // TraceId set trace id data
259 | func (r *RpcDataPackage) TraceId(traceId int64) *RpcDataPackage {
260 | initRequest(r)
261 | r.Meta.Request.TraceId = traceId
262 | return r
263 | }
264 |
265 | // GetTraceId return trace id
266 | func (r *RpcDataPackage) GetTraceId() int64 {
267 | initRequest(r)
268 | return r.Meta.Request.TraceId
269 | }
270 |
271 | // SpanId set span id
272 | func (r *RpcDataPackage) SpanId(spanId int64) *RpcDataPackage {
273 | initRequest(r)
274 | r.Meta.Request.SpanId = spanId
275 | return r
276 | }
277 |
278 | // GetSpanId return span id
279 | func (r *RpcDataPackage) GetSpanId() int64 {
280 | initRequest(r)
281 | return r.Meta.Request.SpanId
282 | }
283 |
284 | // ParentSpanId set parent span id
285 | func (r *RpcDataPackage) ParentSpanId(parentSpanId int64) *RpcDataPackage {
286 | initRequest(r)
287 | r.Meta.Request.ParentSpanId = parentSpanId
288 | return r
289 | }
290 |
291 | // GetParentSpanId return parent span id
292 | func (r *RpcDataPackage) GetParentSpanId() int64 {
293 | initRequest(r)
294 | return r.Meta.Request.ParentSpanId
295 | }
296 |
297 | // RpcRequestMetaExt set rpc request meta extendsion fields
298 | func (r *RpcDataPackage) RpcRequestMetaExt(ext map[string]string) *RpcDataPackage {
299 | initRequest(r)
300 | extMap := make([]*RpcRequestMetaExtField, 0)
301 | for key, value := range ext {
302 | extfield := &RpcRequestMetaExtField{Key: key, Value: value}
303 | extMap = append(extMap, extfield)
304 | }
305 | r.Meta.Request.RpcRequestMetaExt = extMap
306 | return r
307 | }
308 |
309 | // GetRpcRequestMetaExt return rpc request meta extendstion
310 | func (r *RpcDataPackage) GetRpcRequestMetaExt() map[string]string {
311 | initRequest(r)
312 | ret := make(map[string]string)
313 | for _, rr := range r.Meta.Request.RpcRequestMetaExt {
314 | ret[rr.Key] = rr.Value
315 | }
316 |
317 | return ret
318 | }
319 |
320 | // ErrorCode set error code field
321 | func (r *RpcDataPackage) ErrorCode(errorCode int32) *RpcDataPackage {
322 | initResponse(r)
323 |
324 | r.Meta.Response.ErrorCode = errorCode
325 |
326 | return r
327 | }
328 |
329 | // ErrorText set error text field
330 | func (r *RpcDataPackage) ErrorText(errorText string) *RpcDataPackage {
331 | initResponse(r)
332 |
333 | r.Meta.Response.ErrorText = errorText
334 |
335 | return r
336 | }
337 |
338 | // ExtraParams set extra parameters field
339 | func (r *RpcDataPackage) ExtraParams(extraParams []byte) *RpcDataPackage {
340 | initRequest(r)
341 |
342 | r.Meta.Request.ExtraParam = extraParams
343 |
344 | return r
345 | }
346 |
347 | // ChuckInfo set chuck info
348 | func (r *RpcDataPackage) ChuckInfo(streamId int64, chunkId int64) *RpcDataPackage {
349 | ChuckInfo := ChunkInfo{}
350 | ChuckInfo.StreamId = streamId
351 | ChuckInfo.ChunkId = chunkId
352 | initRpcMeta(r)
353 | r.Meta.ChuckInfo = &ChuckInfo
354 | return r
355 | }
356 |
357 | func doInit(r *RpcDataPackage) {
358 | initHeader(r)
359 | initRequest(r)
360 | initResponse(r)
361 | }
362 |
363 | // GetHead return Header data
364 | func (r *RpcDataPackage) GetHead() *Header {
365 | if r.Head == nil {
366 | return nil
367 | }
368 | return r.Head
369 | }
370 |
371 | // GetMeta return RpcMeta data
372 | func (r *RpcDataPackage) GetMeta() *RpcMeta {
373 | if r.Meta == nil {
374 | return nil
375 | }
376 | return r.Meta
377 | }
378 |
379 | // GetData return data field
380 | func (r *RpcDataPackage) GetData() []byte {
381 | return r.Data
382 | }
383 |
384 | // GetAttachment return attachment field
385 | func (r *RpcDataPackage) GetAttachment() []byte {
386 | return r.Attachment
387 | }
388 |
389 | /*
390 | Convert RpcPackage to byte array
391 | */
392 | func (r *RpcDataPackage) WriteIO(rw io.Writer) error {
393 |
394 | bytes, err := r.Write()
395 | if err != nil {
396 | return err
397 | }
398 |
399 | _, err = rw.Write(bytes)
400 | if err != nil {
401 | return err
402 | }
403 |
404 | return nil
405 | }
406 |
407 | /*
408 | Convert RpcPackage to byte array
409 | */
410 | func (r *RpcDataPackage) Write() ([]byte, error) {
411 | doInit(r)
412 |
413 | var totalSize int32 = 0
414 | var dataSize int32 = 0
415 | var err error
416 | if r.Data != nil {
417 | compressType := r.GetMeta().GetCompressType()
418 | if compressType == COMPRESS_GZIP {
419 | r.Data, err = GZIP(r.Data)
420 | if err != nil {
421 | return nil, err
422 | }
423 | } else if compressType == COMPRESS_SNAPPY {
424 | dst := make([]byte, snappy.MaxEncodedLen(len(r.Data)))
425 | r.Data = snappy.Encode(dst, r.Data)
426 | }
427 |
428 | dataSize = int32(len(r.Data))
429 | totalSize = totalSize + dataSize
430 | }
431 |
432 | var attachmentSize int32 = 0
433 | if r.Attachment != nil {
434 | attachmentSize = int32(len(r.Attachment))
435 | totalSize = totalSize + attachmentSize
436 | }
437 |
438 | r.Meta.AttachmentSize = int32(attachmentSize)
439 |
440 | metaBytes, err := proto.Marshal(r.Meta)
441 | if err != nil {
442 | return nil, err
443 | }
444 |
445 | if metaBytes == nil {
446 | return nil, errMeta
447 | }
448 |
449 | rpcMetaSize := int32(len(metaBytes))
450 | totalSize = totalSize + rpcMetaSize
451 |
452 | r.Head.MessageSize = int32(totalSize)
453 | r.Head.MetaSize = int32(rpcMetaSize)
454 | buf := new(bytes.Buffer)
455 |
456 | headBytes, _ := r.Head.Write()
457 | binary.Write(buf, binary.BigEndian, headBytes)
458 | binary.Write(buf, binary.BigEndian, metaBytes)
459 |
460 | if r.Data != nil {
461 | binary.Write(buf, binary.BigEndian, r.Data)
462 | }
463 |
464 | if r.Attachment != nil {
465 | binary.Write(buf, binary.BigEndian, r.Attachment)
466 | }
467 |
468 | return buf.Bytes(), nil
469 | }
470 |
471 | /*
472 | Read byte array and initialize RpcPackage
473 | */
474 | func (r *RpcDataPackage) ReadIO(rw io.Reader) error {
475 | if rw == nil {
476 | return errors.New("bytes is nil")
477 | }
478 |
479 | doInit(r)
480 |
481 | // read Head
482 | head := make([]byte, SIZE)
483 |
484 | _, err := io.ReadFull(rw, head)
485 | if err != nil {
486 | if err == io.EOF {
487 | return errIgnoreErr
488 | }
489 | log.Println("Read head error", err)
490 | // only to close current connection
491 | return err
492 | }
493 |
494 | // unmarshal Head message
495 | r.Head.Read(head)
496 | if strings.Compare(string(r.Head.MagicCode), MAGIC_CODE) != 0 {
497 | return fmt.Errorf("invalid magic code '%v'", string(r.Head.MagicCode))
498 | }
499 |
500 | // get RPC Meta size
501 | metaSize := r.Head.GetMetaSize()
502 | totalSize := r.Head.GetMessageSize()
503 | if totalSize <= 0 {
504 | // maybe heart beat data message, so do ignore here
505 | return errIgnoreErr
506 | }
507 |
508 | // read left
509 | leftSize := totalSize
510 | body := make([]byte, leftSize)
511 |
512 | _, err = io.ReadFull(rw, body)
513 | if err != nil {
514 | return fmt.Errorf("Read body error %w ", err)
515 | }
516 |
517 | proto.Unmarshal(body[0:metaSize], r.Meta)
518 |
519 | attachmentSize := r.Meta.GetAttachmentSize()
520 | dataSize := leftSize - metaSize - attachmentSize
521 |
522 | dataOffset := metaSize
523 | if dataSize > 0 {
524 | dataOffset = dataSize + metaSize
525 | r.Data = body[metaSize:dataOffset]
526 |
527 | compressType := r.GetMeta().GetCompressType()
528 | if compressType == COMPRESS_GZIP {
529 | r.Data, err = GUNZIP(r.Data)
530 |
531 | if err != nil {
532 | return err
533 | }
534 | } else if compressType == COMPRESS_SNAPPY {
535 | dst := make([]byte, 1)
536 | r.Data, err = snappy.Decode(dst, r.Data)
537 | if err != nil {
538 | return err
539 | }
540 | }
541 | }
542 | // if need read Attachment
543 | if attachmentSize > 0 {
544 | r.Attachment = body[dataOffset:leftSize]
545 | }
546 |
547 | return nil
548 | }
549 |
550 | // Read and parse data from target byte slice
551 | func (r *RpcDataPackage) Read(b []byte) error {
552 |
553 | if b == nil {
554 | return errors.New("parameter 'b' is nil")
555 | }
556 |
557 | buf := bytes.NewBuffer(b)
558 |
559 | return r.ReadIO(buf)
560 |
561 | }
562 |
563 | // Chunk chunk to small packages by chunk size
564 | func (r *RpcDataPackage) Chunk(chunkSize int) []*RpcDataPackage {
565 | if chunkSize <= 0 {
566 | return []*RpcDataPackage{r}
567 | }
568 |
569 | dataSize := len(r.Data)
570 | chunkCount := dataSize / chunkSize
571 | if dataSize%chunkSize != 0 {
572 | chunkCount++
573 | }
574 | if chunkCount == 1 {
575 | return []*RpcDataPackage{r}
576 | }
577 |
578 | ret := make([]*RpcDataPackage, chunkCount)
579 | startPos := 0
580 | chunkStreamID := rand.Int63()
581 |
582 | for i := 0; i < chunkCount; i++ {
583 | temp := *r
584 | base := &temp // copy value
585 |
586 | tempMeta := *base.Meta
587 | base.Meta = &tempMeta
588 | initChuckInfo(base)
589 | offset := startPos + chunkSize
590 | if offset > dataSize {
591 | offset = dataSize
592 | }
593 | base.Data = base.Data[startPos:offset]
594 | startPos += chunkSize
595 | tempChuckInfo := &ChunkInfo{StreamId: chunkStreamID, ChunkId: int64(i + 1)}
596 | if i == chunkCount-1 {
597 | // this is last package
598 | tempChuckInfo.ChunkId = int64(-1)
599 | }
600 | if i > 0 {
601 | // fix duplicate attachment data
602 | base.Attachment = nil
603 | }
604 | ChuckInfo := *tempChuckInfo
605 | base.Meta.ChuckInfo = &ChuckInfo
606 | ret[i] = base
607 | }
608 |
609 | return ret
610 | }
611 |
612 | // GetChunkStreamId return chunk stream id
613 | func (r *RpcDataPackage) GetChunkStreamId() int64 {
614 | initRpcMeta(r)
615 | return r.Meta.ChuckInfo.GetStreamId()
616 | }
617 |
618 | // getChunkId
619 | func (r *RpcDataPackage) getChunkId() int64 {
620 | initRpcMeta(r)
621 | return r.Meta.ChuckInfo.GetChunkId()
622 | }
623 |
624 | // IsChunkPackage return if chunk package type
625 | func (r *RpcDataPackage) IsChunkPackage() bool {
626 | return r.GetChunkStreamId() != 0
627 | }
628 |
629 | // IsFinalPackage return if the final chunk package
630 | func (r *RpcDataPackage) IsFinalPackage() bool {
631 | return r.getChunkId() == -1
632 | }
633 |
634 | // ClearChunkStatus to clear chunk status
635 | func (r *RpcDataPackage) ClearChunkStatus() {
636 | r.ChuckInfo(0, 0)
637 | }
638 |
--------------------------------------------------------------------------------
/pb_data.go:
--------------------------------------------------------------------------------
1 | // Code generated by protoc-gen-go. DO NOT EDIT.
2 | // versions:
3 | // protoc-gen-go v1.26.0
4 | // protoc v3.9.2
5 | // source: brpc_meta.proto
6 |
7 | package baidurpc
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 | type RpcMeta struct {
24 | state protoimpl.MessageState
25 | sizeCache protoimpl.SizeCache
26 | unknownFields protoimpl.UnknownFields
27 |
28 | Request *Request `protobuf:"bytes,1,opt,name=request,proto3" json:"request,omitempty"`
29 | Response *Response `protobuf:"bytes,2,opt,name=response,proto3" json:"response,omitempty"`
30 | CompressType int32 `protobuf:"varint,3,opt,name=compress_type,json=compressType,proto3" json:"compress_type,omitempty"` // 0:nocompress 1:Snappy 2:gzip
31 | CorrelationId int64 `protobuf:"varint,4,opt,name=correlation_id,json=correlationId,proto3" json:"correlation_id,omitempty"`
32 | AttachmentSize int32 `protobuf:"varint,5,opt,name=attachment_size,json=attachmentSize,proto3" json:"attachment_size,omitempty"`
33 | ChuckInfo *ChunkInfo `protobuf:"bytes,6,opt,name=chuck_info,json=chuckInfo,proto3" json:"chuck_info,omitempty"`
34 | AuthenticationData []byte `protobuf:"bytes,7,opt,name=authentication_data,json=authenticationData,proto3" json:"authentication_data,omitempty"`
35 | }
36 |
37 | func (x *RpcMeta) Reset() {
38 | *x = RpcMeta{}
39 | if protoimpl.UnsafeEnabled {
40 | mi := &file_brpc_meta_proto_msgTypes[0]
41 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
42 | ms.StoreMessageInfo(mi)
43 | }
44 | }
45 |
46 | func (x *RpcMeta) String() string {
47 | return protoimpl.X.MessageStringOf(x)
48 | }
49 |
50 | func (*RpcMeta) ProtoMessage() {}
51 |
52 | func (x *RpcMeta) ProtoReflect() protoreflect.Message {
53 | mi := &file_brpc_meta_proto_msgTypes[0]
54 | if protoimpl.UnsafeEnabled && x != nil {
55 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
56 | if ms.LoadMessageInfo() == nil {
57 | ms.StoreMessageInfo(mi)
58 | }
59 | return ms
60 | }
61 | return mi.MessageOf(x)
62 | }
63 |
64 | // Deprecated: Use RpcMeta.ProtoReflect.Descriptor instead.
65 | func (*RpcMeta) Descriptor() ([]byte, []int) {
66 | return file_brpc_meta_proto_rawDescGZIP(), []int{0}
67 | }
68 |
69 | func (x *RpcMeta) GetRequest() *Request {
70 | if x != nil {
71 | return x.Request
72 | }
73 | return nil
74 | }
75 |
76 | func (x *RpcMeta) GetResponse() *Response {
77 | if x != nil {
78 | return x.Response
79 | }
80 | return nil
81 | }
82 |
83 | func (x *RpcMeta) GetCompressType() int32 {
84 | if x != nil {
85 | return x.CompressType
86 | }
87 | return 0
88 | }
89 |
90 | func (x *RpcMeta) GetCorrelationId() int64 {
91 | if x != nil {
92 | return x.CorrelationId
93 | }
94 | return 0
95 | }
96 |
97 | func (x *RpcMeta) GetAttachmentSize() int32 {
98 | if x != nil {
99 | return x.AttachmentSize
100 | }
101 | return 0
102 | }
103 |
104 | func (x *RpcMeta) GetChuckInfo() *ChunkInfo {
105 | if x != nil {
106 | return x.ChuckInfo
107 | }
108 | return nil
109 | }
110 |
111 | func (x *RpcMeta) GetAuthenticationData() []byte {
112 | if x != nil {
113 | return x.AuthenticationData
114 | }
115 | return nil
116 | }
117 |
118 | type Request struct {
119 | state protoimpl.MessageState
120 | sizeCache protoimpl.SizeCache
121 | unknownFields protoimpl.UnknownFields
122 |
123 | ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
124 | MethodName string `protobuf:"bytes,2,opt,name=method_name,json=methodName,proto3" json:"method_name,omitempty"`
125 | LogId int64 `protobuf:"varint,3,opt,name=log_id,json=logId,proto3" json:"log_id,omitempty"`
126 | TraceId int64 `protobuf:"varint,4,opt,name=traceId,proto3" json:"traceId,omitempty"`
127 | SpanId int64 `protobuf:"varint,5,opt,name=spanId,proto3" json:"spanId,omitempty"`
128 | ParentSpanId int64 `protobuf:"varint,6,opt,name=parentSpanId,proto3" json:"parentSpanId,omitempty"`
129 | RpcRequestMetaExt []*RpcRequestMetaExtField `protobuf:"bytes,7,rep,name=rpcRequestMetaExt,proto3" json:"rpcRequestMetaExt,omitempty"`
130 | ExtraParam []byte `protobuf:"bytes,110,opt,name=extraParam,proto3" json:"extraParam,omitempty"`
131 | }
132 |
133 | func (x *Request) Reset() {
134 | *x = Request{}
135 | if protoimpl.UnsafeEnabled {
136 | mi := &file_brpc_meta_proto_msgTypes[1]
137 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
138 | ms.StoreMessageInfo(mi)
139 | }
140 | }
141 |
142 | func (x *Request) String() string {
143 | return protoimpl.X.MessageStringOf(x)
144 | }
145 |
146 | func (*Request) ProtoMessage() {}
147 |
148 | func (x *Request) ProtoReflect() protoreflect.Message {
149 | mi := &file_brpc_meta_proto_msgTypes[1]
150 | if protoimpl.UnsafeEnabled && x != nil {
151 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
152 | if ms.LoadMessageInfo() == nil {
153 | ms.StoreMessageInfo(mi)
154 | }
155 | return ms
156 | }
157 | return mi.MessageOf(x)
158 | }
159 |
160 | // Deprecated: Use Request.ProtoReflect.Descriptor instead.
161 | func (*Request) Descriptor() ([]byte, []int) {
162 | return file_brpc_meta_proto_rawDescGZIP(), []int{1}
163 | }
164 |
165 | func (x *Request) GetServiceName() string {
166 | if x != nil {
167 | return x.ServiceName
168 | }
169 | return ""
170 | }
171 |
172 | func (x *Request) GetMethodName() string {
173 | if x != nil {
174 | return x.MethodName
175 | }
176 | return ""
177 | }
178 |
179 | func (x *Request) GetLogId() int64 {
180 | if x != nil {
181 | return x.LogId
182 | }
183 | return 0
184 | }
185 |
186 | func (x *Request) GetTraceId() int64 {
187 | if x != nil {
188 | return x.TraceId
189 | }
190 | return 0
191 | }
192 |
193 | func (x *Request) GetSpanId() int64 {
194 | if x != nil {
195 | return x.SpanId
196 | }
197 | return 0
198 | }
199 |
200 | func (x *Request) GetParentSpanId() int64 {
201 | if x != nil {
202 | return x.ParentSpanId
203 | }
204 | return 0
205 | }
206 |
207 | func (x *Request) GetRpcRequestMetaExt() []*RpcRequestMetaExtField {
208 | if x != nil {
209 | return x.RpcRequestMetaExt
210 | }
211 | return nil
212 | }
213 |
214 | func (x *Request) GetExtraParam() []byte {
215 | if x != nil {
216 | return x.ExtraParam
217 | }
218 | return nil
219 | }
220 |
221 | type Response struct {
222 | state protoimpl.MessageState
223 | sizeCache protoimpl.SizeCache
224 | unknownFields protoimpl.UnknownFields
225 |
226 | ErrorCode int32 `protobuf:"varint,1,opt,name=error_code,json=errorCode,proto3" json:"error_code,omitempty"`
227 | ErrorText string `protobuf:"bytes,2,opt,name=error_text,json=errorText,proto3" json:"error_text,omitempty"`
228 | }
229 |
230 | func (x *Response) Reset() {
231 | *x = Response{}
232 | if protoimpl.UnsafeEnabled {
233 | mi := &file_brpc_meta_proto_msgTypes[2]
234 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
235 | ms.StoreMessageInfo(mi)
236 | }
237 | }
238 |
239 | func (x *Response) String() string {
240 | return protoimpl.X.MessageStringOf(x)
241 | }
242 |
243 | func (*Response) ProtoMessage() {}
244 |
245 | func (x *Response) ProtoReflect() protoreflect.Message {
246 | mi := &file_brpc_meta_proto_msgTypes[2]
247 | if protoimpl.UnsafeEnabled && x != nil {
248 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
249 | if ms.LoadMessageInfo() == nil {
250 | ms.StoreMessageInfo(mi)
251 | }
252 | return ms
253 | }
254 | return mi.MessageOf(x)
255 | }
256 |
257 | // Deprecated: Use Response.ProtoReflect.Descriptor instead.
258 | func (*Response) Descriptor() ([]byte, []int) {
259 | return file_brpc_meta_proto_rawDescGZIP(), []int{2}
260 | }
261 |
262 | func (x *Response) GetErrorCode() int32 {
263 | if x != nil {
264 | return x.ErrorCode
265 | }
266 | return 0
267 | }
268 |
269 | func (x *Response) GetErrorText() string {
270 | if x != nil {
271 | return x.ErrorText
272 | }
273 | return ""
274 | }
275 |
276 | type ChunkInfo struct {
277 | state protoimpl.MessageState
278 | sizeCache protoimpl.SizeCache
279 | unknownFields protoimpl.UnknownFields
280 |
281 | StreamId int64 `protobuf:"varint,1,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"`
282 | ChunkId int64 `protobuf:"varint,2,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"`
283 | }
284 |
285 | func (x *ChunkInfo) Reset() {
286 | *x = ChunkInfo{}
287 | if protoimpl.UnsafeEnabled {
288 | mi := &file_brpc_meta_proto_msgTypes[3]
289 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
290 | ms.StoreMessageInfo(mi)
291 | }
292 | }
293 |
294 | func (x *ChunkInfo) String() string {
295 | return protoimpl.X.MessageStringOf(x)
296 | }
297 |
298 | func (*ChunkInfo) ProtoMessage() {}
299 |
300 | func (x *ChunkInfo) ProtoReflect() protoreflect.Message {
301 | mi := &file_brpc_meta_proto_msgTypes[3]
302 | if protoimpl.UnsafeEnabled && x != nil {
303 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
304 | if ms.LoadMessageInfo() == nil {
305 | ms.StoreMessageInfo(mi)
306 | }
307 | return ms
308 | }
309 | return mi.MessageOf(x)
310 | }
311 |
312 | // Deprecated: Use ChunkInfo.ProtoReflect.Descriptor instead.
313 | func (*ChunkInfo) Descriptor() ([]byte, []int) {
314 | return file_brpc_meta_proto_rawDescGZIP(), []int{3}
315 | }
316 |
317 | func (x *ChunkInfo) GetStreamId() int64 {
318 | if x != nil {
319 | return x.StreamId
320 | }
321 | return 0
322 | }
323 |
324 | func (x *ChunkInfo) GetChunkId() int64 {
325 | if x != nil {
326 | return x.ChunkId
327 | }
328 | return 0
329 | }
330 |
331 | type RpcRequestMetaExtField struct {
332 | state protoimpl.MessageState
333 | sizeCache protoimpl.SizeCache
334 | unknownFields protoimpl.UnknownFields
335 |
336 | Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
337 | Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
338 | }
339 |
340 | func (x *RpcRequestMetaExtField) Reset() {
341 | *x = RpcRequestMetaExtField{}
342 | if protoimpl.UnsafeEnabled {
343 | mi := &file_brpc_meta_proto_msgTypes[4]
344 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
345 | ms.StoreMessageInfo(mi)
346 | }
347 | }
348 |
349 | func (x *RpcRequestMetaExtField) String() string {
350 | return protoimpl.X.MessageStringOf(x)
351 | }
352 |
353 | func (*RpcRequestMetaExtField) ProtoMessage() {}
354 |
355 | func (x *RpcRequestMetaExtField) ProtoReflect() protoreflect.Message {
356 | mi := &file_brpc_meta_proto_msgTypes[4]
357 | if protoimpl.UnsafeEnabled && x != nil {
358 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
359 | if ms.LoadMessageInfo() == nil {
360 | ms.StoreMessageInfo(mi)
361 | }
362 | return ms
363 | }
364 | return mi.MessageOf(x)
365 | }
366 |
367 | // Deprecated: Use RpcRequestMetaExtField.ProtoReflect.Descriptor instead.
368 | func (*RpcRequestMetaExtField) Descriptor() ([]byte, []int) {
369 | return file_brpc_meta_proto_rawDescGZIP(), []int{4}
370 | }
371 |
372 | func (x *RpcRequestMetaExtField) GetKey() string {
373 | if x != nil {
374 | return x.Key
375 | }
376 | return ""
377 | }
378 |
379 | func (x *RpcRequestMetaExtField) GetValue() string {
380 | if x != nil {
381 | return x.Value
382 | }
383 | return ""
384 | }
385 |
386 | var File_brpc_meta_proto protoreflect.FileDescriptor
387 |
388 | var file_brpc_meta_proto_rawDesc = []byte{
389 | 0x0a, 0x0f, 0x62, 0x72, 0x70, 0x63, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74,
390 | 0x6f, 0x22, 0xa5, 0x02, 0x0a, 0x07, 0x52, 0x70, 0x63, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x22, 0x0a,
391 | 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08,
392 | 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
393 | 0x74, 0x12, 0x25, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x02, 0x20,
394 | 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x08,
395 | 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x70,
396 | 0x72, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
397 | 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a,
398 | 0x0e, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18,
399 | 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
400 | 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65,
401 | 0x6e, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x61,
402 | 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a,
403 | 0x0a, 0x63, 0x68, 0x75, 0x63, 0x6b, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x01, 0x28,
404 | 0x0b, 0x32, 0x0a, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x63,
405 | 0x68, 0x75, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2f, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68,
406 | 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18,
407 | 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
408 | 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x22, 0xa1, 0x02, 0x0a, 0x07, 0x52, 0x65,
409 | 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
410 | 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72,
411 | 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x65, 0x74, 0x68,
412 | 0x6f, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d,
413 | 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6c, 0x6f, 0x67,
414 | 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x49, 0x64,
415 | 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
416 | 0x03, 0x52, 0x07, 0x74, 0x72, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x70,
417 | 0x61, 0x6e, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x70, 0x61, 0x6e,
418 | 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x53, 0x70, 0x61, 0x6e,
419 | 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
420 | 0x53, 0x70, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x11, 0x72, 0x70, 0x63, 0x52, 0x65, 0x71,
421 | 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x78, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28,
422 | 0x0b, 0x32, 0x17, 0x2e, 0x52, 0x70, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65,
423 | 0x74, 0x61, 0x45, 0x78, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x11, 0x72, 0x70, 0x63, 0x52,
424 | 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x78, 0x74, 0x12, 0x1e, 0x0a,
425 | 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x6e, 0x20, 0x01, 0x28,
426 | 0x0c, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x72, 0x61, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x48, 0x0a,
427 | 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72,
428 | 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x65,
429 | 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f,
430 | 0x72, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x72,
431 | 0x72, 0x6f, 0x72, 0x54, 0x65, 0x78, 0x74, 0x22, 0x43, 0x0a, 0x09, 0x43, 0x68, 0x75, 0x6e, 0x6b,
432 | 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x69,
433 | 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49,
434 | 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
435 | 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x64, 0x22, 0x40, 0x0a, 0x16,
436 | 0x52, 0x70, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x78,
437 | 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
438 | 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
439 | 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x22,
440 | 0x5a, 0x20, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x61, 0x69,
441 | 0x64, 0x75, 0x2d, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x62, 0x61, 0x69, 0x64, 0x75, 0x72,
442 | 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
443 | }
444 |
445 | var (
446 | file_brpc_meta_proto_rawDescOnce sync.Once
447 | file_brpc_meta_proto_rawDescData = file_brpc_meta_proto_rawDesc
448 | )
449 |
450 | func file_brpc_meta_proto_rawDescGZIP() []byte {
451 | file_brpc_meta_proto_rawDescOnce.Do(func() {
452 | file_brpc_meta_proto_rawDescData = protoimpl.X.CompressGZIP(file_brpc_meta_proto_rawDescData)
453 | })
454 | return file_brpc_meta_proto_rawDescData
455 | }
456 |
457 | var file_brpc_meta_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
458 | var file_brpc_meta_proto_goTypes = []interface{}{
459 | (*RpcMeta)(nil), // 0: RpcMeta
460 | (*Request)(nil), // 1: Request
461 | (*Response)(nil), // 2: Response
462 | (*ChunkInfo)(nil), // 3: ChunkInfo
463 | (*RpcRequestMetaExtField)(nil), // 4: RpcRequestMetaExtField
464 | }
465 | var file_brpc_meta_proto_depIdxs = []int32{
466 | 1, // 0: RpcMeta.request:type_name -> Request
467 | 2, // 1: RpcMeta.response:type_name -> Response
468 | 3, // 2: RpcMeta.chuck_info:type_name -> ChunkInfo
469 | 4, // 3: Request.rpcRequestMetaExt:type_name -> RpcRequestMetaExtField
470 | 4, // [4:4] is the sub-list for method output_type
471 | 4, // [4:4] is the sub-list for method input_type
472 | 4, // [4:4] is the sub-list for extension type_name
473 | 4, // [4:4] is the sub-list for extension extendee
474 | 0, // [0:4] is the sub-list for field type_name
475 | }
476 |
477 | func init() { file_brpc_meta_proto_init() }
478 | func file_brpc_meta_proto_init() {
479 | if File_brpc_meta_proto != nil {
480 | return
481 | }
482 | if !protoimpl.UnsafeEnabled {
483 | file_brpc_meta_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
484 | switch v := v.(*RpcMeta); i {
485 | case 0:
486 | return &v.state
487 | case 1:
488 | return &v.sizeCache
489 | case 2:
490 | return &v.unknownFields
491 | default:
492 | return nil
493 | }
494 | }
495 | file_brpc_meta_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
496 | switch v := v.(*Request); i {
497 | case 0:
498 | return &v.state
499 | case 1:
500 | return &v.sizeCache
501 | case 2:
502 | return &v.unknownFields
503 | default:
504 | return nil
505 | }
506 | }
507 | file_brpc_meta_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
508 | switch v := v.(*Response); i {
509 | case 0:
510 | return &v.state
511 | case 1:
512 | return &v.sizeCache
513 | case 2:
514 | return &v.unknownFields
515 | default:
516 | return nil
517 | }
518 | }
519 | file_brpc_meta_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
520 | switch v := v.(*ChunkInfo); i {
521 | case 0:
522 | return &v.state
523 | case 1:
524 | return &v.sizeCache
525 | case 2:
526 | return &v.unknownFields
527 | default:
528 | return nil
529 | }
530 | }
531 | file_brpc_meta_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
532 | switch v := v.(*RpcRequestMetaExtField); i {
533 | case 0:
534 | return &v.state
535 | case 1:
536 | return &v.sizeCache
537 | case 2:
538 | return &v.unknownFields
539 | default:
540 | return nil
541 | }
542 | }
543 | }
544 | type x struct{}
545 | out := protoimpl.TypeBuilder{
546 | File: protoimpl.DescBuilder{
547 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
548 | RawDescriptor: file_brpc_meta_proto_rawDesc,
549 | NumEnums: 0,
550 | NumMessages: 5,
551 | NumExtensions: 0,
552 | NumServices: 0,
553 | },
554 | GoTypes: file_brpc_meta_proto_goTypes,
555 | DependencyIndexes: file_brpc_meta_proto_depIdxs,
556 | MessageInfos: file_brpc_meta_proto_msgTypes,
557 | }.Build()
558 | File_brpc_meta_proto = out.File
559 | file_brpc_meta_proto_rawDesc = nil
560 | file_brpc_meta_proto_goTypes = nil
561 | file_brpc_meta_proto_depIdxs = nil
562 | }
563 |
--------------------------------------------------------------------------------