github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/baseapp/grpcrouter.go (about)

     1  package baseapp
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/grpc/reflection"
     7  	codectypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types"
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    10  
    11  	gogogrpc "github.com/gogo/protobuf/grpc"
    12  	"google.golang.org/grpc"
    13  	"google.golang.org/grpc/encoding"
    14  	"google.golang.org/grpc/encoding/proto"
    15  )
    16  
    17  var protoCodec = encoding.GetCodec(proto.Name)
    18  
    19  // GRPCQueryRouter routes ABCI Query requests to GRPC handlers
    20  type GRPCQueryRouter struct {
    21  	routes            map[string]GRPCQueryHandler
    22  	interfaceRegistry codectypes.InterfaceRegistry
    23  	serviceData       []serviceData
    24  }
    25  
    26  // serviceData represents a gRPC service, along with its handler.
    27  type serviceData struct {
    28  	serviceDesc *grpc.ServiceDesc
    29  	handler     interface{}
    30  }
    31  
    32  var _ gogogrpc.Server = &GRPCQueryRouter{}
    33  
    34  // NewGRPCQueryRouter creates a new GRPCQueryRouter
    35  func NewGRPCQueryRouter() *GRPCQueryRouter {
    36  	return &GRPCQueryRouter{
    37  		routes: map[string]GRPCQueryHandler{},
    38  	}
    39  }
    40  
    41  // GRPCQueryHandler defines a function type which handles ABCI Query requests
    42  // using gRPC
    43  type GRPCQueryHandler = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error)
    44  
    45  // Route returns the GRPCQueryHandler for a given query route path or nil
    46  // if not found
    47  func (qrt *GRPCQueryRouter) Route(path string) GRPCQueryHandler {
    48  	handler, found := qrt.routes[path]
    49  	if !found {
    50  		return nil
    51  	}
    52  	return handler
    53  }
    54  
    55  // RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
    56  // service description, handler is an object which implements that gRPC service/
    57  //
    58  // This functions PANICS:
    59  // - if a protobuf service is registered twice.
    60  func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interface{}) {
    61  	// adds a top-level query handler based on the gRPC service name
    62  	for _, method := range sd.Methods {
    63  		fqName := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
    64  		methodHandler := method.Handler
    65  
    66  		// Check that each service is only registered once. If a service is
    67  		// registered more than once, then we should error. Since we can't
    68  		// return an error (`Server.RegisterService` interface restriction) we
    69  		// panic (at startup).
    70  		_, found := qrt.routes[fqName]
    71  		if found {
    72  			panic(
    73  				fmt.Errorf(
    74  					"gRPC query service %s has already been registered. Please make sure to only register each service once. "+
    75  						"This usually means that there are conflicting modules registering the same gRPC query service",
    76  					fqName,
    77  				),
    78  			)
    79  		}
    80  
    81  		qrt.routes[fqName] = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error) {
    82  			// call the method handler from the service description with the handler object,
    83  			// a wrapped sdk.Context with proto-unmarshaled data from the ABCI request data
    84  			res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), func(i interface{}) error {
    85  				err := protoCodec.Unmarshal(req.Data, i)
    86  				if err != nil {
    87  					return err
    88  				}
    89  				if qrt.interfaceRegistry != nil {
    90  					return codectypes.UnpackInterfaces(i, qrt.interfaceRegistry)
    91  				}
    92  
    93  				return nil
    94  			}, nil)
    95  
    96  			if err != nil {
    97  				return abci.ResponseQuery{}, err
    98  			}
    99  
   100  			// proto marshal the result bytes
   101  			resBytes, err := protoCodec.Marshal(res)
   102  			if err != nil {
   103  				return abci.ResponseQuery{}, err
   104  			}
   105  
   106  			// return the result bytes as the response value
   107  			return abci.ResponseQuery{
   108  				Height: req.Height,
   109  				Value:  resBytes,
   110  			}, nil
   111  		}
   112  	}
   113  	qrt.serviceData = append(qrt.serviceData, serviceData{
   114  		serviceDesc: sd,
   115  		handler:     handler,
   116  	})
   117  }
   118  
   119  // SetInterfaceRegistry sets the interface registry for the router. This will
   120  // also register the interface reflection gRPC service.
   121  func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) {
   122  	qrt.interfaceRegistry = interfaceRegistry
   123  
   124  	// Once we have an interface registry, we can register the interface
   125  	// registry reflection gRPC service.
   126  	reflection.RegisterReflectionServiceServer(
   127  		qrt,
   128  		reflection.NewReflectionServiceServer(interfaceRegistry),
   129  	)
   130  }