package grpcreflect import ( "fmt" "google.golang.org/grpc" "github.com/jhump/protoreflect/desc" ) // LoadServiceDescriptors loads the service descriptors for all services exposed by the // given GRPC server. func LoadServiceDescriptors(s *grpc.Server) (map[string]*desc.ServiceDescriptor, error) { descs := map[string]*desc.ServiceDescriptor{} for name, info := range s.GetServiceInfo() { file, ok := info.Metadata.(string) if !ok { return nil, fmt.Errorf("service %q has unexpected metadata: expecting a string; got %v", name, info.Metadata) } fd, err := desc.LoadFileDescriptor(file) if err != nil { return nil, err } d := fd.FindSymbol(name) if d == nil { return nil, fmt.Errorf("file descriptor for %q has no element named %q", file, name) } sd, ok := d.(*desc.ServiceDescriptor) if !ok { return nil, fmt.Errorf("file descriptor for %q has incorrect element named %q: expecting a service descriptor; got %v", file, name, d) } descs[name] = sd } return descs, nil } // LoadServiceDescriptor loads a rich descriptor for a given service description // generated by protoc-gen-go. Generated code contains an unexported symbol with // a name like "__serviceDesc" which is the service's description. It // is used internally to register a service implementation with a GRPC server. // But it can also be used by this package to retrieve the rich descriptor for // the service. func LoadServiceDescriptor(svc *grpc.ServiceDesc) (*desc.ServiceDescriptor, error) { file, ok := svc.Metadata.(string) if !ok { return nil, fmt.Errorf("service %q has unexpected metadata: expecting a string; got %v", svc.ServiceName, svc.Metadata) } fd, err := desc.LoadFileDescriptor(file) if err != nil { return nil, err } d := fd.FindSymbol(svc.ServiceName) if d == nil { return nil, fmt.Errorf("file descriptor for %q has no element named %q", file, svc.ServiceName) } sd, ok := d.(*desc.ServiceDescriptor) if !ok { return nil, fmt.Errorf("file descriptor for %q has incorrect element named %q: expecting a service descriptor; got %v", file, svc.ServiceName, d) } return sd, nil }