github.com/jhump/protoreflect@v1.16.0/grpcreflect/server.go (about)

     1  package grpcreflect
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"google.golang.org/grpc"
     7  	"google.golang.org/grpc/reflection"
     8  
     9  	"github.com/jhump/protoreflect/desc"
    10  )
    11  
    12  // GRPCServer is the interface provided by a gRPC server. In addition to being a
    13  // service registrar (for registering services and handlers), it also has an
    14  // accessor for retrieving metadata about all registered services.
    15  type GRPCServer = reflection.GRPCServer
    16  
    17  // LoadServiceDescriptors loads the service descriptors for all services exposed by the
    18  // given GRPC server.
    19  func LoadServiceDescriptors(s GRPCServer) (map[string]*desc.ServiceDescriptor, error) {
    20  	descs := map[string]*desc.ServiceDescriptor{}
    21  	for name, info := range s.GetServiceInfo() {
    22  		file, ok := info.Metadata.(string)
    23  		if !ok {
    24  			return nil, fmt.Errorf("service %q has unexpected metadata: expecting a string; got %v", name, info.Metadata)
    25  		}
    26  		fd, err := desc.LoadFileDescriptor(file)
    27  		if err != nil {
    28  			return nil, err
    29  		}
    30  		d := fd.FindSymbol(name)
    31  		if d == nil {
    32  			return nil, fmt.Errorf("file descriptor for %q has no element named %q", file, name)
    33  		}
    34  		sd, ok := d.(*desc.ServiceDescriptor)
    35  		if !ok {
    36  			return nil, fmt.Errorf("file descriptor for %q has incorrect element named %q: expecting a service descriptor; got %v", file, name, d)
    37  		}
    38  		descs[name] = sd
    39  	}
    40  	return descs, nil
    41  }
    42  
    43  // LoadServiceDescriptor loads a rich descriptor for a given service description
    44  // generated by protoc-gen-go. Generated code contains an unexported symbol with
    45  // a name like "_<Service>_serviceDesc" which is the service's description. It
    46  // is used internally to register a service implementation with a GRPC server.
    47  // But it can also be used by this package to retrieve the rich descriptor for
    48  // the service.
    49  func LoadServiceDescriptor(svc *grpc.ServiceDesc) (*desc.ServiceDescriptor, error) {
    50  	file, ok := svc.Metadata.(string)
    51  	if !ok {
    52  		return nil, fmt.Errorf("service %q has unexpected metadata: expecting a string; got %v", svc.ServiceName, svc.Metadata)
    53  	}
    54  	fd, err := desc.LoadFileDescriptor(file)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	d := fd.FindSymbol(svc.ServiceName)
    59  	if d == nil {
    60  		return nil, fmt.Errorf("file descriptor for %q has no element named %q", file, svc.ServiceName)
    61  	}
    62  	sd, ok := d.(*desc.ServiceDescriptor)
    63  	if !ok {
    64  		return nil, fmt.Errorf("file descriptor for %q has incorrect element named %q: expecting a service descriptor; got %v", file, svc.ServiceName, d)
    65  	}
    66  	return sd, nil
    67  }