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