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