## Description This adds support for registering gRPC query server implementations that were generated using pulsar. It should make integration with the ORM easier. This should be backportable. This does not enable support for pulsar msg servers or tx's. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
125 lines
3.8 KiB
Go
125 lines
3.8 KiB
Go
package baseapp
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"google.golang.org/grpc/encoding"
|
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
|
|
|
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
|
|
|
|
gogogrpc "github.com/gogo/protobuf/grpc"
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"google.golang.org/grpc"
|
|
|
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
)
|
|
|
|
// GRPCQueryRouter routes ABCI Query requests to GRPC handlers
|
|
type GRPCQueryRouter struct {
|
|
routes map[string]GRPCQueryHandler
|
|
cdc encoding.Codec
|
|
serviceData []serviceData
|
|
}
|
|
|
|
// serviceData represents a gRPC service, along with its handler.
|
|
type serviceData struct {
|
|
serviceDesc *grpc.ServiceDesc
|
|
handler interface{}
|
|
}
|
|
|
|
var _ gogogrpc.Server = &GRPCQueryRouter{}
|
|
|
|
// NewGRPCQueryRouter creates a new GRPCQueryRouter
|
|
func NewGRPCQueryRouter() *GRPCQueryRouter {
|
|
return &GRPCQueryRouter{
|
|
routes: map[string]GRPCQueryHandler{},
|
|
}
|
|
}
|
|
|
|
// GRPCQueryHandler defines a function type which handles ABCI Query requests
|
|
// using gRPC
|
|
type GRPCQueryHandler = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error)
|
|
|
|
// Route returns the GRPCQueryHandler for a given query route path or nil
|
|
// if not found
|
|
func (qrt *GRPCQueryRouter) Route(path string) GRPCQueryHandler {
|
|
handler, found := qrt.routes[path]
|
|
if !found {
|
|
return nil
|
|
}
|
|
return handler
|
|
}
|
|
|
|
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
|
|
// service description, handler is an object which implements that gRPC service/
|
|
//
|
|
// This functions PANICS:
|
|
// - if a protobuf service is registered twice.
|
|
func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interface{}) {
|
|
// adds a top-level query handler based on the gRPC service name
|
|
for _, method := range sd.Methods {
|
|
fqName := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
|
|
methodHandler := method.Handler
|
|
|
|
// Check that each service is only registered once. If a service is
|
|
// registered more than once, then we should error. Since we can't
|
|
// return an error (`Server.RegisterService` interface restriction) we
|
|
// panic (at startup).
|
|
_, found := qrt.routes[fqName]
|
|
if found {
|
|
panic(
|
|
fmt.Errorf(
|
|
"gRPC query service %s has already been registered. Please make sure to only register each service once. "+
|
|
"This usually means that there are conflicting modules registering the same gRPC query service",
|
|
fqName,
|
|
),
|
|
)
|
|
}
|
|
|
|
qrt.routes[fqName] = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error) {
|
|
// call the method handler from the service description with the handler object,
|
|
// a wrapped sdk.Context with proto-unmarshaled data from the ABCI request data
|
|
res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), func(i interface{}) error {
|
|
return qrt.cdc.Unmarshal(req.Data, i)
|
|
}, nil)
|
|
if err != nil {
|
|
return abci.ResponseQuery{}, err
|
|
}
|
|
|
|
// proto marshal the result bytes
|
|
var resBytes []byte
|
|
resBytes, err = qrt.cdc.Marshal(res)
|
|
if err != nil {
|
|
return abci.ResponseQuery{}, err
|
|
}
|
|
|
|
// return the result bytes as the response value
|
|
return abci.ResponseQuery{
|
|
Height: req.Height,
|
|
Value: resBytes,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
qrt.serviceData = append(qrt.serviceData, serviceData{
|
|
serviceDesc: sd,
|
|
handler: handler,
|
|
})
|
|
}
|
|
|
|
// SetInterfaceRegistry sets the interface registry for the router. This will
|
|
// also register the interface reflection gRPC service.
|
|
func (qrt *GRPCQueryRouter) SetInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) {
|
|
// instantiate the codec
|
|
qrt.cdc = codec.NewProtoCodec(interfaceRegistry).GRPCCodec()
|
|
// Once we have an interface registry, we can register the interface
|
|
// registry reflection gRPC service.
|
|
reflection.RegisterReflectionServiceServer(
|
|
qrt,
|
|
reflection.NewReflectionServiceServer(interfaceRegistry),
|
|
)
|
|
}
|