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

xuetaoli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go-pixiu-samples.git


The following commit(s) were added to refs/heads/main by this push:
     new 099525c  feat(grpc): add gRPC Server Reflection demo for issue #821 
(#120)
099525c is described below

commit 099525caccb0c706475e927dea029899885819dc
Author: Tsukikage <[email protected]>
AuthorDate: Fri Jan 9 19:37:39 2026 +0800

    feat(grpc): add gRPC Server Reflection demo for issue #821 (#120)
    
    * feat(grpc): add gRPC Server Reflection demo for issue #821
    
    Add a complete demo showcasing gRPC Server Reflection support with:
    
    - EchoService with all 4 RPC types (unary, server/client/bidirectional 
streaming)
    - Server with reflection.Register() enabled
    - Three Pixiu config examples (passthrough, reflection, hybrid modes)
    - Client and integration tests
    - Bilingual documentation (EN/CN)
    
    Ref: https://github.com/apache/dubbo-go-pixiu/issues/821
    Ref: https://github.com/apache/dubbo-go-pixiu/pull/849
    
    * fix(grpc): replace deprecated grpc.Dial with grpc.NewClient
    
    grpc.Dial is deprecated since gRPC-Go 1.x, use NewClient instead
    
    * docs: update README and add gRPC reflection demo to integration test
    
    - Add gRPC reflection demo description to README.md and README_CN.md
    - Add grpc/reflection to start_integrate_test.sh for CI integration
    - Unify pixiu config ports to 8881 for reflection and hybrid modes
    - Update go.mod to use pkg/errors as direct dependency
    
    * fix(grpc/reflection): move server.go to server/app/ for Makefile 
compatibility
    
    The integration test Makefile expects Go files in server/app/ directory.
    Move server.go to match the expected structure.
---
 grpc/reflection/server/app/server.go | 182 +++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/grpc/reflection/server/app/server.go 
b/grpc/reflection/server/app/server.go
new file mode 100644
index 0000000..f1a09ad
--- /dev/null
+++ b/grpc/reflection/server/app/server.go
@@ -0,0 +1,182 @@
+/*
+ * 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.
+ */
+
+// Package main implements a gRPC server with Server Reflection enabled.
+// This demonstrates the gRPC Server Reflection feature for dynamic message 
parsing.
+package main
+
+import (
+       "context"
+       "flag"
+       "fmt"
+       "io"
+       "log"
+       "net"
+       "os"
+       "time"
+)
+
+import (
+       "google.golang.org/grpc"
+       "google.golang.org/grpc/reflection"
+)
+
+import (
+       pb "github.com/dubbo-go-pixiu/samples/grpc/reflection/proto"
+)
+
+var (
+       port     = flag.Int("port", 50051, "The server port")
+       serverID = flag.String("server_id", "", "Server identifier for load 
balancing verification")
+)
+
+// echoServer implements the EchoService.
+type echoServer struct {
+       pb.UnimplementedEchoServiceServer
+       serverID string
+}
+
+// Echo returns the message back with additional metadata.
+func (s *echoServer) Echo(ctx context.Context, req *pb.EchoRequest) 
(*pb.EchoResponse, error) {
+       log.Printf("[Echo] Received message: %s", req.Message)
+
+       return &pb.EchoResponse{
+               Message:           req.Message,
+               ServerTimestamp:   time.Now().UnixNano(),
+               ReflectionEnabled: true, // This server has reflection enabled
+               ServerId:          s.serverID,
+               Metadata:          req.Metadata,
+       }, nil
+}
+
+// StreamEcho demonstrates server streaming with reflection support.
+func (s *echoServer) StreamEcho(req *pb.EchoRequest, stream 
pb.EchoService_StreamEchoServer) error {
+       log.Printf("[StreamEcho] Received message: %s", req.Message)
+
+       // Send 5 responses for demonstration
+       for i := 0; i < 5; i++ {
+               resp := &pb.EchoResponse{
+                       Message:           fmt.Sprintf("[%d] %s", i+1, 
req.Message),
+                       ServerTimestamp:   time.Now().UnixNano(),
+                       ReflectionEnabled: true,
+                       ServerId:          s.serverID,
+                       Metadata:          req.Metadata,
+               }
+               if err := stream.Send(resp); err != nil {
+                       return err
+               }
+               time.Sleep(100 * time.Millisecond)
+       }
+       return nil
+}
+
+// ClientStreamEcho demonstrates client streaming with reflection support.
+func (s *echoServer) ClientStreamEcho(stream 
pb.EchoService_ClientStreamEchoServer) error {
+       log.Printf("[ClientStreamEcho] Stream started")
+
+       var messages []string
+       var lastMetadata map[string]string
+
+       for {
+               req, err := stream.Recv()
+               if err == io.EOF {
+                       // Client finished sending, return aggregated response
+                       return stream.SendAndClose(&pb.EchoResponse{
+                               Message:           fmt.Sprintf("Received %d 
messages: %v", len(messages), messages),
+                               ServerTimestamp:   time.Now().UnixNano(),
+                               ReflectionEnabled: true,
+                               ServerId:          s.serverID,
+                               Metadata:          lastMetadata,
+                       })
+               }
+               if err != nil {
+                       return err
+               }
+
+               log.Printf("[ClientStreamEcho] Received: %s", req.Message)
+               messages = append(messages, req.Message)
+               lastMetadata = req.Metadata
+       }
+}
+
+// BidirectionalEcho demonstrates bidirectional streaming.
+func (s *echoServer) BidirectionalEcho(stream 
pb.EchoService_BidirectionalEchoServer) error {
+       log.Printf("[BidirectionalEcho] Stream started")
+
+       for {
+               req, err := stream.Recv()
+               if err == io.EOF {
+                       return nil
+               }
+               if err != nil {
+                       return err
+               }
+
+               log.Printf("[BidirectionalEcho] Received: %s", req.Message)
+
+               resp := &pb.EchoResponse{
+                       Message:           req.Message,
+                       ServerTimestamp:   time.Now().UnixNano(),
+                       ReflectionEnabled: true,
+                       ServerId:          s.serverID,
+                       Metadata:          req.Metadata,
+               }
+               if err := stream.Send(resp); err != nil {
+                       return err
+               }
+       }
+}
+
+func getServerID() string {
+       if *serverID != "" {
+               return *serverID
+       }
+       // Use hostname as default server ID
+       hostname, err := os.Hostname()
+       if err != nil {
+               return "unknown"
+       }
+       return hostname
+}
+
+func main() {
+       flag.Parse()
+
+       lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
+       if err != nil {
+               log.Fatalf("failed to listen: %v", err)
+       }
+
+       // Create gRPC server with default options
+       grpcServer := grpc.NewServer()
+
+       // Register the EchoService
+       pb.RegisterEchoServiceServer(grpcServer, &echoServer{
+               serverID: getServerID(),
+       })
+
+       // IMPORTANT: Enable gRPC Server Reflection
+       // This allows Pixiu to dynamically discover and parse service methods
+       reflection.Register(grpcServer)
+
+       log.Printf("gRPC server with reflection enabled listening on port %d", 
*port)
+       log.Printf("Server ID: %s", getServerID())
+
+       if err := grpcServer.Serve(lis); err != nil {
+               log.Fatalf("failed to serve: %v", err)
+       }
+}

Reply via email to