blob: 7ff19127857466dc792427e8f5ef7aabb56d2a02 [file] [log] [blame]
khenaidoo0927c722021-12-15 16:49:32 -05001package grpcreflect
2
3import (
4 "fmt"
5
6 "google.golang.org/grpc"
Abhay Kumar40252eb2025-10-13 13:25:53 +00007 "google.golang.org/grpc/reflection"
khenaidoo0927c722021-12-15 16:49:32 -05008
9 "github.com/jhump/protoreflect/desc"
10)
11
Abhay Kumar40252eb2025-10-13 13:25:53 +000012// 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.
15type GRPCServer = reflection.GRPCServer
16
khenaidoo0927c722021-12-15 16:49:32 -050017// LoadServiceDescriptors loads the service descriptors for all services exposed by the
18// given GRPC server.
Abhay Kumar40252eb2025-10-13 13:25:53 +000019func LoadServiceDescriptors(s GRPCServer) (map[string]*desc.ServiceDescriptor, error) {
khenaidoo0927c722021-12-15 16:49:32 -050020 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.
49func 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}