cosmos-sdk/runtime/services/reflection.go

75 lines
2.0 KiB
Go

package services
import (
"bytes"
"compress/gzip"
"context"
"io"
"strings"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
"github.com/cosmos/gogoproto/proto"
"golang.org/x/exp/slices"
protov2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
)
// ReflectionService implements the cosmos.reflection.v1 service.
type ReflectionService struct {
reflectionv1.UnimplementedReflectionServiceServer
files *descriptorpb.FileDescriptorSet
}
func NewReflectionService() (*ReflectionService, error) {
fds := &descriptorpb.FileDescriptorSet{}
// load gogo proto file descriptors
allFds := proto.AllFileDescriptors()
haveFileDescriptor := map[string]bool{}
for _, compressedBz := range allFds {
rdr, err := gzip.NewReader(bytes.NewReader(compressedBz))
if err != nil {
return nil, err
}
bz, err := io.ReadAll(rdr)
if err != nil {
return nil, err
}
fd := &descriptorpb.FileDescriptorProto{}
err = protov2.Unmarshal(bz, fd)
if err != nil {
return nil, err
}
fds.File = append(fds.File, fd)
haveFileDescriptor[*fd.Name] = true
}
// load any protoregistry file descriptors not in gogo
protoregistry.GlobalFiles.RangeFiles(func(fileDescriptor protoreflect.FileDescriptor) bool {
if !haveFileDescriptor[fileDescriptor.Path()] {
fds.File = append(fds.File, protodesc.ToFileDescriptorProto(fileDescriptor))
}
return true
})
slices.SortFunc(fds.File, func(x, y *descriptorpb.FileDescriptorProto) int {
return strings.Compare(*x.Name, *y.Name)
})
return &ReflectionService{files: fds}, nil
}
func (r ReflectionService) FileDescriptors(_ context.Context, _ *reflectionv1.FileDescriptorsRequest) (*reflectionv1.FileDescriptorsResponse, error) {
return &reflectionv1.FileDescriptorsResponse{
Files: r.files.File,
}, nil
}
var _ reflectionv1.ReflectionServiceServer = &ReflectionService{}