This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch release/2.13
in repository https://gitbox.apache.org/repos/asf/apisix.git

commit 7b06f140631dc2122e9201510005aa992527aa52
Author: 罗泽轩 <spacewander...@gmail.com>
AuthorDate: Mon Mar 21 17:27:49 2022 +0800

    refactor: merge grpc_server_example (#6653)
---
 .editorconfig                                     |   5 +
 .gitmodules                                       |   3 -
 .licenserc.yaml                                   |   1 +
 ci/centos7-ci.sh                                  |   6 -
 ci/linux_openresty_common_runner.sh               |   4 -
 t/grpc_server_example                             |   1 -
 t/grpc_server_example/go.mod                      |   9 +
 t/grpc_server_example/go.sum                      |  60 +++
 t/grpc_server_example/main.go                     | 254 ++++++++++
 t/grpc_server_example/proto.pb                    | Bin 0 -> 298 bytes
 t/grpc_server_example/proto/helloworld.pb.go      | 573 ++++++++++++++++++++++
 t/grpc_server_example/proto/helloworld.proto      |  70 +++
 t/grpc_server_example/proto/helloworld_grpc.pb.go | 383 +++++++++++++++
 t/grpc_server_example/proto/import.pb.go          | 203 ++++++++
 t/grpc_server_example/proto/import.proto          |  29 ++
 t/grpc_server_example/proto/src.pb.go             | 162 ++++++
 t/grpc_server_example/proto/src.proto             |  32 ++
 t/grpc_server_example/proto/src_grpc.pb.go        | 101 ++++
 18 files changed, 1882 insertions(+), 14 deletions(-)

diff --git a/.editorconfig b/.editorconfig
index 0096ce7b2..79eed820e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -45,3 +45,8 @@ indent_style = tab
 
 [t/coredns/db.test.local]
 indent_style = unset
+
+[*.pb]
+indent_style = unset
+insert_final_newline = unset
+trim_trailing_whitespace = unset
diff --git a/.gitmodules b/.gitmodules
index 6ad3766a0..beb354b89 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
 [submodule "t/toolkit"]
        path = t/toolkit
        url = https://github.com/api7/test-toolkit.git
-[submodule "t/grpc_server_example"]
-       path = t/grpc_server_example
-       url = https://github.com/api7/grpc_server_example
diff --git a/.licenserc.yaml b/.licenserc.yaml
index d2ce2e61c..58acb3d71 100644
--- a/.licenserc.yaml
+++ b/.licenserc.yaml
@@ -27,6 +27,7 @@ header:
     - '**/*.key'
     - '**/*.crt'
     - '**/*.pem'
+    - '**/*.pb.go'
     - '.github/'
     - 'conf/mime.types'
     # Exclude CI env_file
diff --git a/ci/centos7-ci.sh b/ci/centos7-ci.sh
index f182809d6..1cff4a5f8 100755
--- a/ci/centos7-ci.sh
+++ b/ci/centos7-ci.sh
@@ -56,12 +56,6 @@ install_dependencies() {
     # install and start grpc_server_example
     cd t/grpc_server_example
 
-    # unless pulled recursively, the submodule directory will remain empty. So 
it's better to initialize and set the submodule to the particular commit.
-    if [ ! "$(ls -A . )" ]; then
-        git submodule init
-        git submodule update
-    fi
-
     CGO_ENABLED=0 go build
     ./grpc_server_example \
         -grpc-address :50051 -grpcs-address :50052 -grpcs-mtls-address :50053 \
diff --git a/ci/linux_openresty_common_runner.sh 
b/ci/linux_openresty_common_runner.sh
index 4a76c385a..16579d527 100755
--- a/ci/linux_openresty_common_runner.sh
+++ b/ci/linux_openresty_common_runner.sh
@@ -45,10 +45,6 @@ do_install() {
     # install and start grpc_server_example
     cd t/grpc_server_example
 
-    if [ ! "$(ls -A . )" ]; then # for local development only
-        git submodule init
-        git submodule update
-    fi
     CGO_ENABLED=0 go build
     cd ../../
 
diff --git a/t/grpc_server_example b/t/grpc_server_example
deleted file mode 160000
index 5e74be697..000000000
--- a/t/grpc_server_example
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 5e74be697f24151648be1712fce0ab2fdd0ec964
diff --git a/t/grpc_server_example/go.mod b/t/grpc_server_example/go.mod
new file mode 100644
index 000000000..cccb735e9
--- /dev/null
+++ b/t/grpc_server_example/go.mod
@@ -0,0 +1,9 @@
+module github.com/api7/grpc_server_example
+
+go 1.11
+
+require (
+       github.com/golang/protobuf v1.5.0
+       google.golang.org/grpc v1.32.0
+       google.golang.org/protobuf v1.27.1 // indirect
+)
diff --git a/t/grpc_server_example/go.sum b/t/grpc_server_example/go.sum
new file mode 100644
index 000000000..d150a12f6
--- /dev/null
+++ b/t/grpc_server_example/go.sum
@@ -0,0 +1,60 @@
+cloud.google.com/go v0.26.0/go.mod 
h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/client9/misspell v0.3.4/go.mod 
h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod 
h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod 
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod 
h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod 
h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod 
h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod 
h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod 
h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.5.0 
h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
+github.com/golang/protobuf v1.5.0/go.mod 
h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.2.0/go.mod 
h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.4.0/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod 
h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod 
h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod 
h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod 
h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod 
h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod 
h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a 
h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod 
h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod 
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a 
h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod 
h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod 
h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod 
h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod 
h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 
h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod 
h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod 
h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod 
h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod 
h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 
h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod 
h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/grpc v1.19.0/go.mod 
h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod 
h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod 
h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.32.0 h1:zWTV+LMdc3kaiJMSTOFz2UgSBgx8RNQoTGiZu3fR9S0=
+google.golang.org/grpc v1.32.0/go.mod 
h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod 
h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.27.1 
h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod 
h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod 
h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/t/grpc_server_example/main.go b/t/grpc_server_example/main.go
new file mode 100644
index 000000000..18bda0536
--- /dev/null
+++ b/t/grpc_server_example/main.go
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. 
--go-grpc_opt=paths=source_relative proto/helloworld.proto
+//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. 
--go-grpc_opt=paths=source_relative proto/import.proto
+//go:generate protoc  --include_imports --descriptor_set_out=proto.pb 
--go_out=. --go_opt=paths=source_relative --go-grpc_out=. 
--go-grpc_opt=paths=source_relative proto/src.proto
+
+// Package main implements a server for Greeter service.
+package main
+
+import (
+       "context"
+       "crypto/tls"
+       "crypto/x509"
+       "flag"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "log"
+       "net"
+       "os"
+       "os/signal"
+       "syscall"
+       "time"
+
+       "google.golang.org/grpc"
+       "google.golang.org/grpc/codes"
+       "google.golang.org/grpc/credentials"
+       "google.golang.org/grpc/reflection"
+       "google.golang.org/grpc/status"
+
+       pb "github.com/api7/grpc_server_example/proto"
+)
+
+var (
+       grpcAddr      = ":50051"
+       grpcsAddr     = ":50052"
+       grpcsMtlsAddr string
+
+       crtFilePath = "../t/cert/apisix.crt"
+       keyFilePath = "../t/cert/apisix.key"
+       caFilePath  string
+)
+
+func init() {
+       flag.StringVar(&grpcAddr, "grpc-address", grpcAddr, "address for grpc")
+       flag.StringVar(&grpcsAddr, "grpcs-address", grpcsAddr, "address for 
grpcs")
+       flag.StringVar(&grpcsMtlsAddr, "grpcs-mtls-address", grpcsMtlsAddr, 
"address for grpcs in mTLS")
+       flag.StringVar(&crtFilePath, "crt", crtFilePath, "path to certificate")
+       flag.StringVar(&keyFilePath, "key", keyFilePath, "path to key")
+       flag.StringVar(&caFilePath, "ca", caFilePath, "path to ca")
+}
+
+// server is used to implement helloworld.GreeterServer.
+type server struct {
+       // Embed the unimplemented server
+       pb.UnimplementedGreeterServer
+       pb.UnimplementedTestImportServer
+}
+
+// SayHello implements helloworld.GreeterServer
+func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) 
(*pb.HelloReply, error) {
+       log.Printf("Received: %v", in.Name)
+       log.Printf("Enum Gender: %v", in.GetGender())
+       msg := "Hello " + in.Name
+
+       person := in.GetPerson()
+       if person != nil {
+               if person.GetName() != "" {
+                       msg += fmt.Sprintf(", name: %v", person.GetName())
+               }
+               if person.GetAge() != 0 {
+                       msg += fmt.Sprintf(", age: %v", person.GetAge())
+               }
+       }
+
+       return &pb.HelloReply{
+               Message: msg,
+               Items:   in.GetItems(),
+               Gender:  in.GetGender(),
+       }, nil
+}
+
+func (s *server) SayHelloAfterDelay(ctx context.Context, in *pb.HelloRequest) 
(*pb.HelloReply, error) {
+
+       select {
+       case <-time.After(1 * time.Second):
+               fmt.Println("overslept")
+       case <-ctx.Done():
+               errStr := ctx.Err().Error()
+               if ctx.Err() == context.DeadlineExceeded {
+                       return nil, status.Error(codes.DeadlineExceeded, errStr)
+               }
+       }
+
+       time.Sleep(1 * time.Second)
+
+       log.Printf("Received: %v", in.Name)
+
+       return &pb.HelloReply{Message: "Hello delay " + in.Name}, nil
+}
+
+func (s *server) Plus(ctx context.Context, in *pb.PlusRequest) (*pb.PlusReply, 
error) {
+       log.Printf("Received: %v %v", in.A, in.B)
+       return &pb.PlusReply{Result: in.A + in.B}, nil
+}
+
+// SayHelloServerStream streams HelloReply back to the client.
+func (s *server) SayHelloServerStream(req *pb.HelloRequest, stream 
pb.Greeter_SayHelloServerStreamServer) error {
+       log.Printf("Received server side stream req: %v\n", req)
+
+       // Say Hello 5 times.
+       for i := 0; i < 5; i++ {
+               if err := stream.Send(&pb.HelloReply{
+                       Message: fmt.Sprintf("Hello %s", req.Name),
+               }); err != nil {
+                       return status.Errorf(codes.Unavailable, "Unable to 
stream request back to client: %v", err)
+               }
+       }
+       return nil
+}
+
+// SayHelloClientStream receives a stream of HelloRequest from a client.
+func (s *server) SayHelloClientStream(stream 
pb.Greeter_SayHelloClientStreamServer) error {
+       log.Println("SayHello client side streaming has been initiated.")
+       cache := ""
+       for {
+               req, err := stream.Recv()
+               if err == io.EOF {
+                       return stream.SendAndClose(&pb.HelloReply{Message: 
cache})
+               }
+               if err != nil {
+                       return status.Errorf(codes.Unavailable, "Failed to read 
client stream: %v", err)
+               }
+               cache = fmt.Sprintf("%sHello %s!", cache, req.Name)
+       }
+}
+
+// SayHelloBidirectionalStream establishes a bidirectional stream with the 
client.
+func (s *server) SayHelloBidirectionalStream(stream 
pb.Greeter_SayHelloBidirectionalStreamServer) error {
+       log.Println("SayHello bidirectional streaming has been initiated.")
+
+       for {
+               req, err := stream.Recv()
+               if err == io.EOF {
+                       return stream.Send(&pb.HelloReply{Message: "stream 
ended"})
+               }
+               if err != nil {
+                       return status.Errorf(codes.Unavailable, "Failed to read 
client stream: %v", err)
+               }
+
+               // A small 0.5 sec sleep
+               time.Sleep(500 * time.Millisecond)
+
+               if err := stream.Send(&pb.HelloReply{Message: 
fmt.Sprintf("Hello %s", req.Name)}); err != nil {
+                       return status.Errorf(codes.Unknown, "Failed to stream 
response back to client: %v", err)
+               }
+       }
+}
+
+func (s *server) Run(ctx context.Context, in *pb.Request) (*pb.Response, 
error) {
+       return &pb.Response{Body: in.User.Name + " " + in.Body}, nil
+}
+
+func main() {
+       flag.Parse()
+
+       go func() {
+               lis, err := net.Listen("tcp", grpcAddr)
+               if err != nil {
+                       log.Fatalf("failed to listen: %v", err)
+               }
+               s := grpc.NewServer()
+               reflection.Register(s)
+               pb.RegisterGreeterServer(s, &server{})
+               pb.RegisterTestImportServer(s, &server{})
+               if err := s.Serve(lis); err != nil {
+                       log.Fatalf("failed to serve: %v", err)
+               }
+       }()
+
+       go func() {
+               lis, err := net.Listen("tcp", grpcsAddr)
+               if err != nil {
+                       log.Fatalf("failed to listen: %v", err)
+               }
+
+               c, err := credentials.NewServerTLSFromFile(crtFilePath, 
keyFilePath)
+               if err != nil {
+                       log.Fatalf("credentials.NewServerTLSFromFile err: %v", 
err)
+               }
+               s := grpc.NewServer(grpc.Creds(c))
+               reflection.Register(s)
+               pb.RegisterGreeterServer(s, &server{})
+               if err := s.Serve(lis); err != nil {
+                       log.Fatalf("failed to serve: %v", err)
+               }
+       }()
+
+       if grpcsMtlsAddr != "" {
+               go func() {
+                       lis, err := net.Listen("tcp", grpcsMtlsAddr)
+                       if err != nil {
+                               log.Fatalf("failed to listen: %v", err)
+                       }
+
+                       certificate, err := tls.LoadX509KeyPair(crtFilePath, 
keyFilePath)
+                       if err != nil {
+                               log.Fatalf("could not load server key pair: 
%s", err)
+                       }
+
+                       certPool := x509.NewCertPool()
+                       ca, err := ioutil.ReadFile(caFilePath)
+                       if err != nil {
+                               log.Fatalf("could not read ca certificate: %s", 
err)
+                       }
+
+                       if ok := certPool.AppendCertsFromPEM(ca); !ok {
+                               log.Fatalf("failed to append client certs")
+                       }
+
+                       c := credentials.NewTLS(&tls.Config{
+                               ClientAuth:   tls.RequireAndVerifyClientCert,
+                               Certificates: []tls.Certificate{certificate},
+                               ClientCAs:    certPool,
+                       })
+                       s := grpc.NewServer(grpc.Creds(c))
+                       reflection.Register(s)
+                       pb.RegisterGreeterServer(s, &server{})
+                       if err := s.Serve(lis); err != nil {
+                               log.Fatalf("failed to serve: %v", err)
+                       }
+               }()
+       }
+
+       signals := make(chan os.Signal)
+       signal.Notify(signals, os.Interrupt, syscall.SIGTERM)
+       sig := <-signals
+       log.Printf("get signal %s, exit\n", sig.String())
+}
diff --git a/t/grpc_server_example/proto.pb b/t/grpc_server_example/proto.pb
new file mode 100644
index 000000000..8edcc5c64
Binary files /dev/null and b/t/grpc_server_example/proto.pb differ
diff --git a/t/grpc_server_example/proto/helloworld.pb.go 
b/t/grpc_server_example/proto/helloworld.pb.go
new file mode 100644
index 000000000..9cb209566
--- /dev/null
+++ b/t/grpc_server_example/proto/helloworld.pb.go
@@ -0,0 +1,573 @@
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.27.1
+//     protoc        v3.6.1
+// source: proto/helloworld.proto
+
+package proto
+
+import (
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+       reflect "reflect"
+       sync "sync"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Gender int32
+
+const (
+       Gender_GENDER_UNKNOWN Gender = 0
+       Gender_GENDER_MALE    Gender = 1
+       Gender_GENDER_FEMALE  Gender = 2
+)
+
+// Enum value maps for Gender.
+var (
+       Gender_name = map[int32]string{
+               0: "GENDER_UNKNOWN",
+               1: "GENDER_MALE",
+               2: "GENDER_FEMALE",
+       }
+       Gender_value = map[string]int32{
+               "GENDER_UNKNOWN": 0,
+               "GENDER_MALE":    1,
+               "GENDER_FEMALE":  2,
+       }
+)
+
+func (x Gender) Enum() *Gender {
+       p := new(Gender)
+       *p = x
+       return p
+}
+
+func (x Gender) String() string {
+       return protoimpl.X.EnumStringOf(x.Descriptor(), 
protoreflect.EnumNumber(x))
+}
+
+func (Gender) Descriptor() protoreflect.EnumDescriptor {
+       return file_proto_helloworld_proto_enumTypes[0].Descriptor()
+}
+
+func (Gender) Type() protoreflect.EnumType {
+       return &file_proto_helloworld_proto_enumTypes[0]
+}
+
+func (x Gender) Number() protoreflect.EnumNumber {
+       return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use Gender.Descriptor instead.
+func (Gender) EnumDescriptor() ([]byte, []int) {
+       return file_proto_helloworld_proto_rawDescGZIP(), []int{0}
+}
+
+type Person struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Name string `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
+       Age  int32  `protobuf:"varint,2,opt,name=age,proto3" 
json:"age,omitempty"`
+}
+
+func (x *Person) Reset() {
+       *x = Person{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_helloworld_proto_msgTypes[0]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *Person) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Person) ProtoMessage() {}
+
+func (x *Person) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_helloworld_proto_msgTypes[0]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use Person.ProtoReflect.Descriptor instead.
+func (*Person) Descriptor() ([]byte, []int) {
+       return file_proto_helloworld_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Person) GetName() string {
+       if x != nil {
+               return x.Name
+       }
+       return ""
+}
+
+func (x *Person) GetAge() int32 {
+       if x != nil {
+               return x.Age
+       }
+       return 0
+}
+
+type HelloRequest struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Name   string   `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
+       Items  []string `protobuf:"bytes,2,rep,name=items,proto3" 
json:"items,omitempty"`
+       Gender Gender   
`protobuf:"varint,3,opt,name=gender,proto3,enum=helloworld.Gender" 
json:"gender,omitempty"`
+       Person *Person  `protobuf:"bytes,4,opt,name=person,proto3" 
json:"person,omitempty"`
+}
+
+func (x *HelloRequest) Reset() {
+       *x = HelloRequest{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_helloworld_proto_msgTypes[1]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *HelloRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HelloRequest) ProtoMessage() {}
+
+func (x *HelloRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_helloworld_proto_msgTypes[1]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
+func (*HelloRequest) Descriptor() ([]byte, []int) {
+       return file_proto_helloworld_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *HelloRequest) GetName() string {
+       if x != nil {
+               return x.Name
+       }
+       return ""
+}
+
+func (x *HelloRequest) GetItems() []string {
+       if x != nil {
+               return x.Items
+       }
+       return nil
+}
+
+func (x *HelloRequest) GetGender() Gender {
+       if x != nil {
+               return x.Gender
+       }
+       return Gender_GENDER_UNKNOWN
+}
+
+func (x *HelloRequest) GetPerson() *Person {
+       if x != nil {
+               return x.Person
+       }
+       return nil
+}
+
+type HelloReply struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Message string   `protobuf:"bytes,1,opt,name=message,proto3" 
json:"message,omitempty"`
+       Items   []string `protobuf:"bytes,2,rep,name=items,proto3" 
json:"items,omitempty"`
+       Gender  Gender   
`protobuf:"varint,3,opt,name=gender,proto3,enum=helloworld.Gender" 
json:"gender,omitempty"`
+}
+
+func (x *HelloReply) Reset() {
+       *x = HelloReply{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_helloworld_proto_msgTypes[2]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *HelloReply) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HelloReply) ProtoMessage() {}
+
+func (x *HelloReply) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_helloworld_proto_msgTypes[2]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
+func (*HelloReply) Descriptor() ([]byte, []int) {
+       return file_proto_helloworld_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *HelloReply) GetMessage() string {
+       if x != nil {
+               return x.Message
+       }
+       return ""
+}
+
+func (x *HelloReply) GetItems() []string {
+       if x != nil {
+               return x.Items
+       }
+       return nil
+}
+
+func (x *HelloReply) GetGender() Gender {
+       if x != nil {
+               return x.Gender
+       }
+       return Gender_GENDER_UNKNOWN
+}
+
+type PlusRequest struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       A int64 `protobuf:"varint,1,opt,name=a,proto3" json:"a,omitempty"`
+       B int64 `protobuf:"varint,2,opt,name=b,proto3" json:"b,omitempty"`
+}
+
+func (x *PlusRequest) Reset() {
+       *x = PlusRequest{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_helloworld_proto_msgTypes[3]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *PlusRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlusRequest) ProtoMessage() {}
+
+func (x *PlusRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_helloworld_proto_msgTypes[3]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlusRequest.ProtoReflect.Descriptor instead.
+func (*PlusRequest) Descriptor() ([]byte, []int) {
+       return file_proto_helloworld_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *PlusRequest) GetA() int64 {
+       if x != nil {
+               return x.A
+       }
+       return 0
+}
+
+func (x *PlusRequest) GetB() int64 {
+       if x != nil {
+               return x.B
+       }
+       return 0
+}
+
+type PlusReply struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Result int64 `protobuf:"varint,1,opt,name=result,proto3" 
json:"result,omitempty"`
+}
+
+func (x *PlusReply) Reset() {
+       *x = PlusReply{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_helloworld_proto_msgTypes[4]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *PlusReply) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PlusReply) ProtoMessage() {}
+
+func (x *PlusReply) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_helloworld_proto_msgTypes[4]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use PlusReply.ProtoReflect.Descriptor instead.
+func (*PlusReply) Descriptor() ([]byte, []int) {
+       return file_proto_helloworld_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *PlusReply) GetResult() int64 {
+       if x != nil {
+               return x.Result
+       }
+       return 0
+}
+
+var File_proto_helloworld_proto protoreflect.FileDescriptor
+
+var file_proto_helloworld_proto_rawDesc = []byte{
+       0x0a, 0x16, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x68, 0x65, 0x6c, 0x6c, 
0x6f, 0x77, 0x6f, 0x72,
+       0x6c, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x68, 0x65, 
0x6c, 0x6c, 0x6f, 0x77,
+       0x6f, 0x72, 0x6c, 0x64, 0x22, 0x2e, 0x0a, 0x06, 0x50, 0x65, 0x72, 0x73, 
0x6f, 0x6e, 0x12, 0x12,
+       0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 
0x52, 0x04, 0x6e, 0x61,
+       0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 
0x01, 0x28, 0x05, 0x52,
+       0x03, 0x61, 0x67, 0x65, 0x22, 0x90, 0x01, 0x0a, 0x0c, 0x48, 0x65, 0x6c, 
0x6c, 0x6f, 0x52, 0x65,
+       0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 
0x65, 0x18, 0x01, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 
0x05, 0x69, 0x74, 0x65,
+       0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x69, 0x74, 
0x65, 0x6d, 0x73, 0x12,
+       0x2a, 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 
0x01, 0x28, 0x0e, 0x32,
+       0x12, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 
0x2e, 0x47, 0x65, 0x6e,
+       0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 
0x2a, 0x0a, 0x06, 0x70,
+       0x65, 0x72, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 
0x12, 0x2e, 0x68, 0x65,
+       0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x50, 0x65, 0x72, 
0x73, 0x6f, 0x6e, 0x52,
+       0x06, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x22, 0x68, 0x0a, 0x0a, 0x48, 
0x65, 0x6c, 0x6c, 0x6f,
+       0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 
0x73, 0x61, 0x67, 0x65,
+       0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 
0x61, 0x67, 0x65, 0x12,
+       0x14, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 
0x28, 0x09, 0x52, 0x05,
+       0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x2a, 0x0a, 0x06, 0x67, 0x65, 0x6e, 
0x64, 0x65, 0x72, 0x18,
+       0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 
0x6f, 0x77, 0x6f, 0x72,
+       0x6c, 0x64, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 
0x65, 0x6e, 0x64, 0x65,
+       0x72, 0x22, 0x29, 0x0a, 0x0b, 0x50, 0x6c, 0x75, 0x73, 0x52, 0x65, 0x71, 
0x75, 0x65, 0x73, 0x74,
+       0x12, 0x0c, 0x0a, 0x01, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 
0x01, 0x61, 0x12, 0x0c,
+       0x0a, 0x01, 0x62, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x01, 0x62, 
0x22, 0x23, 0x0a, 0x09,
+       0x50, 0x6c, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x16, 0x0a, 
0x06, 0x72, 0x65, 0x73,
+       0x75, 0x6c, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x72, 
0x65, 0x73, 0x75, 0x6c,
+       0x74, 0x2a, 0x40, 0x0a, 0x06, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 
0x12, 0x0a, 0x0e, 0x47,
+       0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 
0x4e, 0x10, 0x00, 0x12,
+       0x0f, 0x0a, 0x0b, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x4d, 0x41, 
0x4c, 0x45, 0x10, 0x01,
+       0x12, 0x11, 0x0a, 0x0d, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x46, 
0x45, 0x4d, 0x41, 0x4c,
+       0x45, 0x10, 0x02, 0x32, 0xc0, 0x03, 0x0a, 0x07, 0x47, 0x72, 0x65, 0x65, 
0x74, 0x65, 0x72, 0x12,
+       0x3e, 0x0a, 0x08, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 
0x18, 0x2e, 0x68, 0x65,
+       0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 
0x6c, 0x6f, 0x52, 0x65,
+       0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 
0x6f, 0x77, 0x6f, 0x72,
+       0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 
0x79, 0x22, 0x00, 0x12,
+       0x38, 0x0a, 0x04, 0x50, 0x6c, 0x75, 0x73, 0x12, 0x17, 0x2e, 0x68, 0x65, 
0x6c, 0x6c, 0x6f, 0x77,
+       0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x50, 0x6c, 0x75, 0x73, 0x52, 0x65, 0x71, 
0x75, 0x65, 0x73, 0x74,
+       0x1a, 0x15, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 
0x64, 0x2e, 0x50, 0x6c,
+       0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x48, 0x0a, 
0x12, 0x53, 0x61, 0x79,
+       0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x41, 0x66, 0x74, 0x65, 0x72, 0x44, 0x65, 
0x6c, 0x61, 0x79, 0x12,
+       0x18, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 
0x2e, 0x48, 0x65, 0x6c,
+       0x6c, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 
0x68, 0x65, 0x6c, 0x6c,
+       0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 
0x52, 0x65, 0x70, 0x6c,
+       0x79, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x14, 0x53, 0x61, 0x79, 0x48, 0x65, 
0x6c, 0x6c, 0x6f, 0x53,
+       0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 
0x18, 0x2e, 0x68, 0x65,
+       0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 
0x6c, 0x6f, 0x52, 0x65,
+       0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 
0x6f, 0x77, 0x6f, 0x72,
+       0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 
0x79, 0x22, 0x00, 0x30,
+       0x01, 0x12, 0x4c, 0x0a, 0x14, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 
0x6f, 0x43, 0x6c, 0x69,
+       0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 
0x68, 0x65, 0x6c, 0x6c,
+       0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 
0x52, 0x65, 0x71, 0x75,
+       0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 
0x6f, 0x72, 0x6c, 0x64,
+       0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 
0x00, 0x28, 0x01, 0x12,
+       0x55, 0x0a, 0x1b, 0x53, 0x61, 0x79, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x42, 
0x69, 0x64, 0x69, 0x72,
+       0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x53, 0x74, 0x72, 0x65, 
0x61, 0x6d, 0x12, 0x18,
+       0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 
0x48, 0x65, 0x6c, 0x6c,
+       0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x68, 
0x65, 0x6c, 0x6c, 0x6f,
+       0x77, 0x6f, 0x72, 0x6c, 0x64, 0x2e, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 
0x65, 0x70, 0x6c, 0x79,
+       0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 
0x70, 0x72, 0x6f, 0x74,
+       0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+       file_proto_helloworld_proto_rawDescOnce sync.Once
+       file_proto_helloworld_proto_rawDescData = 
file_proto_helloworld_proto_rawDesc
+)
+
+func file_proto_helloworld_proto_rawDescGZIP() []byte {
+       file_proto_helloworld_proto_rawDescOnce.Do(func() {
+               file_proto_helloworld_proto_rawDescData = 
protoimpl.X.CompressGZIP(file_proto_helloworld_proto_rawDescData)
+       })
+       return file_proto_helloworld_proto_rawDescData
+}
+
+var file_proto_helloworld_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_proto_helloworld_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_proto_helloworld_proto_goTypes = []interface{}{
+       (Gender)(0),          // 0: helloworld.Gender
+       (*Person)(nil),       // 1: helloworld.Person
+       (*HelloRequest)(nil), // 2: helloworld.HelloRequest
+       (*HelloReply)(nil),   // 3: helloworld.HelloReply
+       (*PlusRequest)(nil),  // 4: helloworld.PlusRequest
+       (*PlusReply)(nil),    // 5: helloworld.PlusReply
+}
+var file_proto_helloworld_proto_depIdxs = []int32{
+       0, // 0: helloworld.HelloRequest.gender:type_name -> helloworld.Gender
+       1, // 1: helloworld.HelloRequest.person:type_name -> helloworld.Person
+       0, // 2: helloworld.HelloReply.gender:type_name -> helloworld.Gender
+       2, // 3: helloworld.Greeter.SayHello:input_type -> 
helloworld.HelloRequest
+       4, // 4: helloworld.Greeter.Plus:input_type -> helloworld.PlusRequest
+       2, // 5: helloworld.Greeter.SayHelloAfterDelay:input_type -> 
helloworld.HelloRequest
+       2, // 6: helloworld.Greeter.SayHelloServerStream:input_type -> 
helloworld.HelloRequest
+       2, // 7: helloworld.Greeter.SayHelloClientStream:input_type -> 
helloworld.HelloRequest
+       2, // 8: helloworld.Greeter.SayHelloBidirectionalStream:input_type -> 
helloworld.HelloRequest
+       3, // 9: helloworld.Greeter.SayHello:output_type -> 
helloworld.HelloReply
+       5, // 10: helloworld.Greeter.Plus:output_type -> helloworld.PlusReply
+       3, // 11: helloworld.Greeter.SayHelloAfterDelay:output_type -> 
helloworld.HelloReply
+       3, // 12: helloworld.Greeter.SayHelloServerStream:output_type -> 
helloworld.HelloReply
+       3, // 13: helloworld.Greeter.SayHelloClientStream:output_type -> 
helloworld.HelloReply
+       3, // 14: helloworld.Greeter.SayHelloBidirectionalStream:output_type -> 
helloworld.HelloReply
+       9, // [9:15] is the sub-list for method output_type
+       3, // [3:9] is the sub-list for method input_type
+       3, // [3:3] is the sub-list for extension type_name
+       3, // [3:3] is the sub-list for extension extendee
+       0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_proto_helloworld_proto_init() }
+func file_proto_helloworld_proto_init() {
+       if File_proto_helloworld_proto != nil {
+               return
+       }
+       if !protoimpl.UnsafeEnabled {
+               file_proto_helloworld_proto_msgTypes[0].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*Person); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_helloworld_proto_msgTypes[1].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*HelloRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_helloworld_proto_msgTypes[2].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*HelloReply); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_helloworld_proto_msgTypes[3].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*PlusRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_helloworld_proto_msgTypes[4].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*PlusReply); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: file_proto_helloworld_proto_rawDesc,
+                       NumEnums:      1,
+                       NumMessages:   5,
+                       NumExtensions: 0,
+                       NumServices:   1,
+               },
+               GoTypes:           file_proto_helloworld_proto_goTypes,
+               DependencyIndexes: file_proto_helloworld_proto_depIdxs,
+               EnumInfos:         file_proto_helloworld_proto_enumTypes,
+               MessageInfos:      file_proto_helloworld_proto_msgTypes,
+       }.Build()
+       File_proto_helloworld_proto = out.File
+       file_proto_helloworld_proto_rawDesc = nil
+       file_proto_helloworld_proto_goTypes = nil
+       file_proto_helloworld_proto_depIdxs = nil
+}
diff --git a/t/grpc_server_example/proto/helloworld.proto 
b/t/grpc_server_example/proto/helloworld.proto
new file mode 100644
index 000000000..2e18a467c
--- /dev/null
+++ b/t/grpc_server_example/proto/helloworld.proto
@@ -0,0 +1,70 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+syntax = "proto3";
+
+package helloworld;
+option go_package = "./proto";
+
+service Greeter {
+  // Unary RPC.
+  rpc SayHello (HelloRequest) returns (HelloReply) {}
+  rpc Plus (PlusRequest) returns (PlusReply) {}
+  rpc SayHelloAfterDelay (HelloRequest) returns (HelloReply) {}
+
+  // Server side streaming.
+  rpc SayHelloServerStream (HelloRequest) returns (stream HelloReply) {}
+
+  // Client side streaming.
+  rpc SayHelloClientStream (stream HelloRequest) returns (HelloReply) {}
+
+  // Bidirectional streaming.
+  rpc SayHelloBidirectionalStream (stream HelloRequest) returns (stream 
HelloReply) {}
+}
+
+enum Gender {
+    GENDER_UNKNOWN = 0;
+    GENDER_MALE = 1;
+    GENDER_FEMALE = 2;
+}
+
+message Person {
+    string name = 1;
+    int32 age = 2;
+}
+
+message HelloRequest {
+  string name = 1;
+  repeated string items = 2;
+  Gender gender = 3;
+  Person person = 4;
+}
+
+message HelloReply {
+  string message = 1;
+  repeated string items = 2;
+  Gender gender = 3;
+}
+
+message PlusRequest {
+  int64 a = 1;
+  int64 b = 2;
+}
+
+message PlusReply {
+  int64 result = 1;
+}
diff --git a/t/grpc_server_example/proto/helloworld_grpc.pb.go 
b/t/grpc_server_example/proto/helloworld_grpc.pb.go
new file mode 100644
index 000000000..7d6d8ef8b
--- /dev/null
+++ b/t/grpc_server_example/proto/helloworld_grpc.pb.go
@@ -0,0 +1,383 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package proto
+
+import (
+       context "context"
+       grpc "google.golang.org/grpc"
+       codes "google.golang.org/grpc/codes"
+       status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// GreeterClient is the client API for Greeter service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please 
refer to 
https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type GreeterClient interface {
+       // Unary RPC.
+       SayHello(ctx context.Context, in *HelloRequest, opts 
...grpc.CallOption) (*HelloReply, error)
+       Plus(ctx context.Context, in *PlusRequest, opts ...grpc.CallOption) 
(*PlusReply, error)
+       SayHelloAfterDelay(ctx context.Context, in *HelloRequest, opts 
...grpc.CallOption) (*HelloReply, error)
+       // Server side streaming.
+       SayHelloServerStream(ctx context.Context, in *HelloRequest, opts 
...grpc.CallOption) (Greeter_SayHelloServerStreamClient, error)
+       // Client side streaming.
+       SayHelloClientStream(ctx context.Context, opts ...grpc.CallOption) 
(Greeter_SayHelloClientStreamClient, error)
+       // Bidirectional streaming.
+       SayHelloBidirectionalStream(ctx context.Context, opts 
...grpc.CallOption) (Greeter_SayHelloBidirectionalStreamClient, error)
+}
+
+type greeterClient struct {
+       cc grpc.ClientConnInterface
+}
+
+func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
+       return &greeterClient{cc}
+}
+
+func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts 
...grpc.CallOption) (*HelloReply, error) {
+       out := new(HelloReply)
+       err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, 
opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+func (c *greeterClient) Plus(ctx context.Context, in *PlusRequest, opts 
...grpc.CallOption) (*PlusReply, error) {
+       out := new(PlusReply)
+       err := c.cc.Invoke(ctx, "/helloworld.Greeter/Plus", in, out, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+func (c *greeterClient) SayHelloAfterDelay(ctx context.Context, in 
*HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
+       out := new(HelloReply)
+       err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHelloAfterDelay", in, 
out, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+func (c *greeterClient) SayHelloServerStream(ctx context.Context, in 
*HelloRequest, opts ...grpc.CallOption) (Greeter_SayHelloServerStreamClient, 
error) {
+       stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[0], 
"/helloworld.Greeter/SayHelloServerStream", opts...)
+       if err != nil {
+               return nil, err
+       }
+       x := &greeterSayHelloServerStreamClient{stream}
+       if err := x.ClientStream.SendMsg(in); err != nil {
+               return nil, err
+       }
+       if err := x.ClientStream.CloseSend(); err != nil {
+               return nil, err
+       }
+       return x, nil
+}
+
+type Greeter_SayHelloServerStreamClient interface {
+       Recv() (*HelloReply, error)
+       grpc.ClientStream
+}
+
+type greeterSayHelloServerStreamClient struct {
+       grpc.ClientStream
+}
+
+func (x *greeterSayHelloServerStreamClient) Recv() (*HelloReply, error) {
+       m := new(HelloReply)
+       if err := x.ClientStream.RecvMsg(m); err != nil {
+               return nil, err
+       }
+       return m, nil
+}
+
+func (c *greeterClient) SayHelloClientStream(ctx context.Context, opts 
...grpc.CallOption) (Greeter_SayHelloClientStreamClient, error) {
+       stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[1], 
"/helloworld.Greeter/SayHelloClientStream", opts...)
+       if err != nil {
+               return nil, err
+       }
+       x := &greeterSayHelloClientStreamClient{stream}
+       return x, nil
+}
+
+type Greeter_SayHelloClientStreamClient interface {
+       Send(*HelloRequest) error
+       CloseAndRecv() (*HelloReply, error)
+       grpc.ClientStream
+}
+
+type greeterSayHelloClientStreamClient struct {
+       grpc.ClientStream
+}
+
+func (x *greeterSayHelloClientStreamClient) Send(m *HelloRequest) error {
+       return x.ClientStream.SendMsg(m)
+}
+
+func (x *greeterSayHelloClientStreamClient) CloseAndRecv() (*HelloReply, 
error) {
+       if err := x.ClientStream.CloseSend(); err != nil {
+               return nil, err
+       }
+       m := new(HelloReply)
+       if err := x.ClientStream.RecvMsg(m); err != nil {
+               return nil, err
+       }
+       return m, nil
+}
+
+func (c *greeterClient) SayHelloBidirectionalStream(ctx context.Context, opts 
...grpc.CallOption) (Greeter_SayHelloBidirectionalStreamClient, error) {
+       stream, err := c.cc.NewStream(ctx, &Greeter_ServiceDesc.Streams[2], 
"/helloworld.Greeter/SayHelloBidirectionalStream", opts...)
+       if err != nil {
+               return nil, err
+       }
+       x := &greeterSayHelloBidirectionalStreamClient{stream}
+       return x, nil
+}
+
+type Greeter_SayHelloBidirectionalStreamClient interface {
+       Send(*HelloRequest) error
+       Recv() (*HelloReply, error)
+       grpc.ClientStream
+}
+
+type greeterSayHelloBidirectionalStreamClient struct {
+       grpc.ClientStream
+}
+
+func (x *greeterSayHelloBidirectionalStreamClient) Send(m *HelloRequest) error 
{
+       return x.ClientStream.SendMsg(m)
+}
+
+func (x *greeterSayHelloBidirectionalStreamClient) Recv() (*HelloReply, error) 
{
+       m := new(HelloReply)
+       if err := x.ClientStream.RecvMsg(m); err != nil {
+               return nil, err
+       }
+       return m, nil
+}
+
+// GreeterServer is the server API for Greeter service.
+// All implementations must embed UnimplementedGreeterServer
+// for forward compatibility
+type GreeterServer interface {
+       // Unary RPC.
+       SayHello(context.Context, *HelloRequest) (*HelloReply, error)
+       Plus(context.Context, *PlusRequest) (*PlusReply, error)
+       SayHelloAfterDelay(context.Context, *HelloRequest) (*HelloReply, error)
+       // Server side streaming.
+       SayHelloServerStream(*HelloRequest, Greeter_SayHelloServerStreamServer) 
error
+       // Client side streaming.
+       SayHelloClientStream(Greeter_SayHelloClientStreamServer) error
+       // Bidirectional streaming.
+       SayHelloBidirectionalStream(Greeter_SayHelloBidirectionalStreamServer) 
error
+       mustEmbedUnimplementedGreeterServer()
+}
+
+// UnimplementedGreeterServer must be embedded to have forward compatible 
implementations.
+type UnimplementedGreeterServer struct {
+}
+
+func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) 
(*HelloReply, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method SayHello not 
implemented")
+}
+func (UnimplementedGreeterServer) Plus(context.Context, *PlusRequest) 
(*PlusReply, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method Plus not 
implemented")
+}
+func (UnimplementedGreeterServer) SayHelloAfterDelay(context.Context, 
*HelloRequest) (*HelloReply, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method 
SayHelloAfterDelay not implemented")
+}
+func (UnimplementedGreeterServer) SayHelloServerStream(*HelloRequest, 
Greeter_SayHelloServerStreamServer) error {
+       return status.Errorf(codes.Unimplemented, "method SayHelloServerStream 
not implemented")
+}
+func (UnimplementedGreeterServer) 
SayHelloClientStream(Greeter_SayHelloClientStreamServer) error {
+       return status.Errorf(codes.Unimplemented, "method SayHelloClientStream 
not implemented")
+}
+func (UnimplementedGreeterServer) 
SayHelloBidirectionalStream(Greeter_SayHelloBidirectionalStreamServer) error {
+       return status.Errorf(codes.Unimplemented, "method 
SayHelloBidirectionalStream not implemented")
+}
+func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
+
+// UnsafeGreeterServer may be embedded to opt out of forward compatibility for 
this service.
+// Use of this interface is not recommended, as added methods to GreeterServer 
will
+// result in compilation errors.
+type UnsafeGreeterServer interface {
+       mustEmbedUnimplementedGreeterServer()
+}
+
+func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
+       s.RegisterService(&Greeter_ServiceDesc, srv)
+}
+
+func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec 
func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, 
error) {
+       in := new(HelloRequest)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(GreeterServer).SayHello(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/helloworld.Greeter/SayHello",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+func _Greeter_Plus_Handler(srv interface{}, ctx context.Context, dec 
func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, 
error) {
+       in := new(PlusRequest)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(GreeterServer).Plus(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/helloworld.Greeter/Plus",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               return srv.(GreeterServer).Plus(ctx, req.(*PlusRequest))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+func _Greeter_SayHelloAfterDelay_Handler(srv interface{}, ctx context.Context, 
dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) 
(interface{}, error) {
+       in := new(HelloRequest)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(GreeterServer).SayHelloAfterDelay(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/helloworld.Greeter/SayHelloAfterDelay",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               return srv.(GreeterServer).SayHelloAfterDelay(ctx, 
req.(*HelloRequest))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+func _Greeter_SayHelloServerStream_Handler(srv interface{}, stream 
grpc.ServerStream) error {
+       m := new(HelloRequest)
+       if err := stream.RecvMsg(m); err != nil {
+               return err
+       }
+       return srv.(GreeterServer).SayHelloServerStream(m, 
&greeterSayHelloServerStreamServer{stream})
+}
+
+type Greeter_SayHelloServerStreamServer interface {
+       Send(*HelloReply) error
+       grpc.ServerStream
+}
+
+type greeterSayHelloServerStreamServer struct {
+       grpc.ServerStream
+}
+
+func (x *greeterSayHelloServerStreamServer) Send(m *HelloReply) error {
+       return x.ServerStream.SendMsg(m)
+}
+
+func _Greeter_SayHelloClientStream_Handler(srv interface{}, stream 
grpc.ServerStream) error {
+       return 
srv.(GreeterServer).SayHelloClientStream(&greeterSayHelloClientStreamServer{stream})
+}
+
+type Greeter_SayHelloClientStreamServer interface {
+       SendAndClose(*HelloReply) error
+       Recv() (*HelloRequest, error)
+       grpc.ServerStream
+}
+
+type greeterSayHelloClientStreamServer struct {
+       grpc.ServerStream
+}
+
+func (x *greeterSayHelloClientStreamServer) SendAndClose(m *HelloReply) error {
+       return x.ServerStream.SendMsg(m)
+}
+
+func (x *greeterSayHelloClientStreamServer) Recv() (*HelloRequest, error) {
+       m := new(HelloRequest)
+       if err := x.ServerStream.RecvMsg(m); err != nil {
+               return nil, err
+       }
+       return m, nil
+}
+
+func _Greeter_SayHelloBidirectionalStream_Handler(srv interface{}, stream 
grpc.ServerStream) error {
+       return 
srv.(GreeterServer).SayHelloBidirectionalStream(&greeterSayHelloBidirectionalStreamServer{stream})
+}
+
+type Greeter_SayHelloBidirectionalStreamServer interface {
+       Send(*HelloReply) error
+       Recv() (*HelloRequest, error)
+       grpc.ServerStream
+}
+
+type greeterSayHelloBidirectionalStreamServer struct {
+       grpc.ServerStream
+}
+
+func (x *greeterSayHelloBidirectionalStreamServer) Send(m *HelloReply) error {
+       return x.ServerStream.SendMsg(m)
+}
+
+func (x *greeterSayHelloBidirectionalStreamServer) Recv() (*HelloRequest, 
error) {
+       m := new(HelloRequest)
+       if err := x.ServerStream.RecvMsg(m); err != nil {
+               return nil, err
+       }
+       return m, nil
+}
+
+// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Greeter_ServiceDesc = grpc.ServiceDesc{
+       ServiceName: "helloworld.Greeter",
+       HandlerType: (*GreeterServer)(nil),
+       Methods: []grpc.MethodDesc{
+               {
+                       MethodName: "SayHello",
+                       Handler:    _Greeter_SayHello_Handler,
+               },
+               {
+                       MethodName: "Plus",
+                       Handler:    _Greeter_Plus_Handler,
+               },
+               {
+                       MethodName: "SayHelloAfterDelay",
+                       Handler:    _Greeter_SayHelloAfterDelay_Handler,
+               },
+       },
+       Streams: []grpc.StreamDesc{
+               {
+                       StreamName:    "SayHelloServerStream",
+                       Handler:       _Greeter_SayHelloServerStream_Handler,
+                       ServerStreams: true,
+               },
+               {
+                       StreamName:    "SayHelloClientStream",
+                       Handler:       _Greeter_SayHelloClientStream_Handler,
+                       ClientStreams: true,
+               },
+               {
+                       StreamName:    "SayHelloBidirectionalStream",
+                       Handler:       
_Greeter_SayHelloBidirectionalStream_Handler,
+                       ServerStreams: true,
+                       ClientStreams: true,
+               },
+       },
+       Metadata: "proto/helloworld.proto",
+}
diff --git a/t/grpc_server_example/proto/import.pb.go 
b/t/grpc_server_example/proto/import.pb.go
new file mode 100644
index 000000000..28fabf3f3
--- /dev/null
+++ b/t/grpc_server_example/proto/import.pb.go
@@ -0,0 +1,203 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.27.1
+//     protoc        v3.6.1
+// source: proto/import.proto
+
+package proto
+
+import (
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+       reflect "reflect"
+       sync "sync"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type User struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Name string `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
+}
+
+func (x *User) Reset() {
+       *x = User{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_import_proto_msgTypes[0]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *User) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*User) ProtoMessage() {}
+
+func (x *User) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_import_proto_msgTypes[0]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use User.ProtoReflect.Descriptor instead.
+func (*User) Descriptor() ([]byte, []int) {
+       return file_proto_import_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *User) GetName() string {
+       if x != nil {
+               return x.Name
+       }
+       return ""
+}
+
+type Response struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Body string `protobuf:"bytes,1,opt,name=body,proto3" 
json:"body,omitempty"`
+}
+
+func (x *Response) Reset() {
+       *x = Response{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_import_proto_msgTypes[1]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *Response) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Response) ProtoMessage() {}
+
+func (x *Response) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_import_proto_msgTypes[1]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use Response.ProtoReflect.Descriptor instead.
+func (*Response) Descriptor() ([]byte, []int) {
+       return file_proto_import_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Response) GetBody() string {
+       if x != nil {
+               return x.Body
+       }
+       return ""
+}
+
+var File_proto_import_proto protoreflect.FileDescriptor
+
+var file_proto_import_proto_rawDesc = []byte{
+       0x0a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6d, 0x70, 0x6f, 
0x72, 0x74, 0x2e, 0x70,
+       0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x70, 0x6b, 0x67, 0x22, 0x1a, 0x0a, 
0x04, 0x55, 0x73, 0x65,
+       0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x1e, 0x0a, 0x08, 0x52, 0x65, 0x73, 
0x70, 0x6f, 0x6e, 0x73,
+       0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 
0x01, 0x28, 0x09, 0x52,
+       0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x70, 
0x72, 0x6f, 0x74, 0x6f,
+       0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+       file_proto_import_proto_rawDescOnce sync.Once
+       file_proto_import_proto_rawDescData = file_proto_import_proto_rawDesc
+)
+
+func file_proto_import_proto_rawDescGZIP() []byte {
+       file_proto_import_proto_rawDescOnce.Do(func() {
+               file_proto_import_proto_rawDescData = 
protoimpl.X.CompressGZIP(file_proto_import_proto_rawDescData)
+       })
+       return file_proto_import_proto_rawDescData
+}
+
+var file_proto_import_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_proto_import_proto_goTypes = []interface{}{
+       (*User)(nil),     // 0: pkg.User
+       (*Response)(nil), // 1: pkg.Response
+}
+var file_proto_import_proto_depIdxs = []int32{
+       0, // [0:0] is the sub-list for method output_type
+       0, // [0:0] is the sub-list for method input_type
+       0, // [0:0] is the sub-list for extension type_name
+       0, // [0:0] is the sub-list for extension extendee
+       0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_proto_import_proto_init() }
+func file_proto_import_proto_init() {
+       if File_proto_import_proto != nil {
+               return
+       }
+       if !protoimpl.UnsafeEnabled {
+               file_proto_import_proto_msgTypes[0].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*User); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_import_proto_msgTypes[1].Exporter = func(v 
interface{}, i int) interface{} {
+                       switch v := v.(*Response); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: file_proto_import_proto_rawDesc,
+                       NumEnums:      0,
+                       NumMessages:   2,
+                       NumExtensions: 0,
+                       NumServices:   0,
+               },
+               GoTypes:           file_proto_import_proto_goTypes,
+               DependencyIndexes: file_proto_import_proto_depIdxs,
+               MessageInfos:      file_proto_import_proto_msgTypes,
+       }.Build()
+       File_proto_import_proto = out.File
+       file_proto_import_proto_rawDesc = nil
+       file_proto_import_proto_goTypes = nil
+       file_proto_import_proto_depIdxs = nil
+}
diff --git a/t/grpc_server_example/proto/import.proto 
b/t/grpc_server_example/proto/import.proto
new file mode 100644
index 000000000..b76505953
--- /dev/null
+++ b/t/grpc_server_example/proto/import.proto
@@ -0,0 +1,29 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+syntax = "proto3";
+
+package pkg;
+option go_package = "./proto";
+
+message User {
+    string name = 1;
+}
+
+message Response {
+  string body = 1;
+}
diff --git a/t/grpc_server_example/proto/src.pb.go 
b/t/grpc_server_example/proto/src.pb.go
new file mode 100644
index 000000000..8e6a32ae3
--- /dev/null
+++ b/t/grpc_server_example/proto/src.pb.go
@@ -0,0 +1,162 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.27.1
+//     protoc        v3.6.1
+// source: proto/src.proto
+
+package proto
+
+import (
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+       reflect "reflect"
+       sync "sync"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Request struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       User *User  `protobuf:"bytes,1,opt,name=user,proto3" 
json:"user,omitempty"`
+       Body string `protobuf:"bytes,2,opt,name=body,proto3" 
json:"body,omitempty"`
+}
+
+func (x *Request) Reset() {
+       *x = Request{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_src_proto_msgTypes[0]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *Request) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Request) ProtoMessage() {}
+
+func (x *Request) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_src_proto_msgTypes[0]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use Request.ProtoReflect.Descriptor instead.
+func (*Request) Descriptor() ([]byte, []int) {
+       return file_proto_src_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Request) GetUser() *User {
+       if x != nil {
+               return x.User
+       }
+       return nil
+}
+
+func (x *Request) GetBody() string {
+       if x != nil {
+               return x.Body
+       }
+       return ""
+}
+
+var File_proto_src_proto protoreflect.FileDescriptor
+
+var file_proto_src_proto_rawDesc = []byte{
+       0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x72, 0x63, 0x2e, 
0x70, 0x72, 0x6f, 0x74,
+       0x6f, 0x12, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 
0x64, 0x1a, 0x12, 0x70,
+       0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x2e, 
0x70, 0x72, 0x6f, 0x74,
+       0x6f, 0x22, 0x3c, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 
0x12, 0x1d, 0x0a, 0x04,
+       0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 
0x2e, 0x70, 0x6b, 0x67,
+       0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 
0x12, 0x0a, 0x04, 0x62,
+       0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 
0x6f, 0x64, 0x79, 0x32,
+       0x39, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 
0x74, 0x12, 0x2b, 0x0a,
+       0x03, 0x52, 0x75, 0x6e, 0x12, 0x13, 0x2e, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 
0x77, 0x6f, 0x72, 0x6c,
+       0x64, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0d, 0x2e, 
0x70, 0x6b, 0x67, 0x2e,
+       0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x09, 
0x5a, 0x07, 0x2e, 0x2f,
+       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 
0x33,
+}
+
+var (
+       file_proto_src_proto_rawDescOnce sync.Once
+       file_proto_src_proto_rawDescData = file_proto_src_proto_rawDesc
+)
+
+func file_proto_src_proto_rawDescGZIP() []byte {
+       file_proto_src_proto_rawDescOnce.Do(func() {
+               file_proto_src_proto_rawDescData = 
protoimpl.X.CompressGZIP(file_proto_src_proto_rawDescData)
+       })
+       return file_proto_src_proto_rawDescData
+}
+
+var file_proto_src_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_proto_src_proto_goTypes = []interface{}{
+       (*Request)(nil),  // 0: helloworld.Request
+       (*User)(nil),     // 1: pkg.User
+       (*Response)(nil), // 2: pkg.Response
+}
+var file_proto_src_proto_depIdxs = []int32{
+       1, // 0: helloworld.Request.user:type_name -> pkg.User
+       0, // 1: helloworld.TestImport.Run:input_type -> helloworld.Request
+       2, // 2: helloworld.TestImport.Run:output_type -> pkg.Response
+       2, // [2:3] is the sub-list for method output_type
+       1, // [1:2] is the sub-list for method input_type
+       1, // [1:1] is the sub-list for extension type_name
+       1, // [1:1] is the sub-list for extension extendee
+       0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_proto_src_proto_init() }
+func file_proto_src_proto_init() {
+       if File_proto_src_proto != nil {
+               return
+       }
+       file_proto_import_proto_init()
+       if !protoimpl.UnsafeEnabled {
+               file_proto_src_proto_msgTypes[0].Exporter = func(v interface{}, 
i int) interface{} {
+                       switch v := v.(*Request); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: file_proto_src_proto_rawDesc,
+                       NumEnums:      0,
+                       NumMessages:   1,
+                       NumExtensions: 0,
+                       NumServices:   1,
+               },
+               GoTypes:           file_proto_src_proto_goTypes,
+               DependencyIndexes: file_proto_src_proto_depIdxs,
+               MessageInfos:      file_proto_src_proto_msgTypes,
+       }.Build()
+       File_proto_src_proto = out.File
+       file_proto_src_proto_rawDesc = nil
+       file_proto_src_proto_goTypes = nil
+       file_proto_src_proto_depIdxs = nil
+}
diff --git a/t/grpc_server_example/proto/src.proto 
b/t/grpc_server_example/proto/src.proto
new file mode 100644
index 000000000..11d9b6609
--- /dev/null
+++ b/t/grpc_server_example/proto/src.proto
@@ -0,0 +1,32 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+syntax = "proto3";
+
+package helloworld;
+option go_package = "./proto";
+
+import "proto/import.proto";
+
+service TestImport {
+  rpc Run (Request) returns (pkg.Response) {}
+}
+
+message Request {
+  pkg.User user = 1;
+  string body = 2;
+}
diff --git a/t/grpc_server_example/proto/src_grpc.pb.go 
b/t/grpc_server_example/proto/src_grpc.pb.go
new file mode 100644
index 000000000..01fe1502d
--- /dev/null
+++ b/t/grpc_server_example/proto/src_grpc.pb.go
@@ -0,0 +1,101 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+
+package proto
+
+import (
+       context "context"
+       grpc "google.golang.org/grpc"
+       codes "google.golang.org/grpc/codes"
+       status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// TestImportClient is the client API for TestImport service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please 
refer to 
https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type TestImportClient interface {
+       Run(ctx context.Context, in *Request, opts ...grpc.CallOption) 
(*Response, error)
+}
+
+type testImportClient struct {
+       cc grpc.ClientConnInterface
+}
+
+func NewTestImportClient(cc grpc.ClientConnInterface) TestImportClient {
+       return &testImportClient{cc}
+}
+
+func (c *testImportClient) Run(ctx context.Context, in *Request, opts 
...grpc.CallOption) (*Response, error) {
+       out := new(Response)
+       err := c.cc.Invoke(ctx, "/helloworld.TestImport/Run", in, out, opts...)
+       if err != nil {
+               return nil, err
+       }
+       return out, nil
+}
+
+// TestImportServer is the server API for TestImport service.
+// All implementations must embed UnimplementedTestImportServer
+// for forward compatibility
+type TestImportServer interface {
+       Run(context.Context, *Request) (*Response, error)
+       mustEmbedUnimplementedTestImportServer()
+}
+
+// UnimplementedTestImportServer must be embedded to have forward compatible 
implementations.
+type UnimplementedTestImportServer struct {
+}
+
+func (UnimplementedTestImportServer) Run(context.Context, *Request) 
(*Response, error) {
+       return nil, status.Errorf(codes.Unimplemented, "method Run not 
implemented")
+}
+func (UnimplementedTestImportServer) mustEmbedUnimplementedTestImportServer() 
{}
+
+// UnsafeTestImportServer may be embedded to opt out of forward compatibility 
for this service.
+// Use of this interface is not recommended, as added methods to 
TestImportServer will
+// result in compilation errors.
+type UnsafeTestImportServer interface {
+       mustEmbedUnimplementedTestImportServer()
+}
+
+func RegisterTestImportServer(s grpc.ServiceRegistrar, srv TestImportServer) {
+       s.RegisterService(&TestImport_ServiceDesc, srv)
+}
+
+func _TestImport_Run_Handler(srv interface{}, ctx context.Context, dec 
func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, 
error) {
+       in := new(Request)
+       if err := dec(in); err != nil {
+               return nil, err
+       }
+       if interceptor == nil {
+               return srv.(TestImportServer).Run(ctx, in)
+       }
+       info := &grpc.UnaryServerInfo{
+               Server:     srv,
+               FullMethod: "/helloworld.TestImport/Run",
+       }
+       handler := func(ctx context.Context, req interface{}) (interface{}, 
error) {
+               return srv.(TestImportServer).Run(ctx, req.(*Request))
+       }
+       return interceptor(ctx, in, info, handler)
+}
+
+// TestImport_ServiceDesc is the grpc.ServiceDesc for TestImport service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var TestImport_ServiceDesc = grpc.ServiceDesc{
+       ServiceName: "helloworld.TestImport",
+       HandlerType: (*TestImportServer)(nil),
+       Methods: []grpc.MethodDesc{
+               {
+                       MethodName: "Run",
+                       Handler:    _TestImport_Run_Handler,
+               },
+       },
+       Streams:  []grpc.StreamDesc{},
+       Metadata: "proto/src.proto",
+}

Reply via email to