github.com/Big-big-orange/protoreflect@v0.0.0-20240408141420-285cedfdf6a4/grpcreflect/client.go (about)

     1  package grpcreflect
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  	"reflect"
     9  	"runtime"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/golang/protobuf/proto"
    14  	"google.golang.org/grpc"
    15  	"google.golang.org/grpc/codes"
    16  	refv1 "google.golang.org/grpc/reflection/grpc_reflection_v1"
    17  	refv1alpha "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
    18  	"google.golang.org/grpc/status"
    19  	"google.golang.org/protobuf/types/descriptorpb"
    20  
    21  	"github.com/Big-big-orange/protoreflect/desc"
    22  	"github.com/Big-big-orange/protoreflect/internal"
    23  )
    24  
    25  // If we try the v1 reflection API and get back "not implemented", we'll wait
    26  // this long before trying v1 again. This allows a long-lived client to
    27  // dynamically switch from v1alpha to v1 if the underlying server is updated
    28  // to support it. But it also prevents every stream request from always trying
    29  // v1 first: if we try it and see it fail, we shouldn't continually retry it
    30  // if we expect it will fail again.
    31  const durationBetweenV1Attempts = time.Hour
    32  
    33  // elementNotFoundError is the error returned by reflective operations where the
    34  // server does not recognize a given file name, symbol name, or extension.
    35  type elementNotFoundError struct {
    36  	name    string
    37  	kind    elementKind
    38  	symType symbolType // only used when kind == elementKindSymbol
    39  	tag     int32      // only used when kind == elementKindExtension
    40  
    41  	// only errors with a kind of elementKindFile will have a cause, which means
    42  	// the named file count not be resolved because of a dependency that could
    43  	// not be found where cause describes the missing dependency
    44  	cause *elementNotFoundError
    45  }
    46  
    47  type elementKind int
    48  
    49  const (
    50  	elementKindSymbol elementKind = iota
    51  	elementKindFile
    52  	elementKindExtension
    53  )
    54  
    55  type symbolType string
    56  
    57  const (
    58  	symbolTypeService = "Service"
    59  	symbolTypeMessage = "Message"
    60  	symbolTypeEnum    = "Enum"
    61  	symbolTypeUnknown = "Symbol"
    62  )
    63  
    64  func symbolNotFound(symbol string, symType symbolType, cause *elementNotFoundError) error {
    65  	return &elementNotFoundError{name: symbol, symType: symType, kind: elementKindSymbol, cause: cause}
    66  }
    67  
    68  func extensionNotFound(extendee string, tag int32, cause *elementNotFoundError) error {
    69  	return &elementNotFoundError{name: extendee, tag: tag, kind: elementKindExtension, cause: cause}
    70  }
    71  
    72  func fileNotFound(file string, cause *elementNotFoundError) error {
    73  	return &elementNotFoundError{name: file, kind: elementKindFile, cause: cause}
    74  }
    75  
    76  func (e *elementNotFoundError) Error() string {
    77  	first := true
    78  	var b bytes.Buffer
    79  	for ; e != nil; e = e.cause {
    80  		if first {
    81  			first = false
    82  		} else {
    83  			fmt.Fprint(&b, "\ncaused by: ")
    84  		}
    85  		switch e.kind {
    86  		case elementKindSymbol:
    87  			fmt.Fprintf(&b, "%s not found: %s", e.symType, e.name)
    88  		case elementKindExtension:
    89  			fmt.Fprintf(&b, "Extension not found: tag %d for %s", e.tag, e.name)
    90  		default:
    91  			fmt.Fprintf(&b, "File not found: %s", e.name)
    92  		}
    93  	}
    94  	return b.String()
    95  }
    96  
    97  // IsElementNotFoundError determines if the given error indicates that a file
    98  // name, symbol name, or extension field was could not be found by the server.
    99  func IsElementNotFoundError(err error) bool {
   100  	_, ok := err.(*elementNotFoundError)
   101  	return ok
   102  }
   103  
   104  // ProtocolError is an error returned when the server sends a response of the
   105  // wrong type.
   106  type ProtocolError struct {
   107  	missingType reflect.Type
   108  }
   109  
   110  func (p ProtocolError) Error() string {
   111  	return fmt.Sprintf("Protocol error: response was missing %v", p.missingType)
   112  }
   113  
   114  type extDesc struct {
   115  	extendedMessageName string
   116  	extensionNumber     int32
   117  }
   118  
   119  // Client is a client connection to a server for performing reflection calls
   120  // and resolving remote symbols.
   121  type Client struct {
   122  	ctx         context.Context
   123  	now         func() time.Time
   124  	stubV1      refv1.ServerReflectionClient
   125  	stubV1Alpha refv1alpha.ServerReflectionClient
   126  
   127  	connMu      sync.Mutex
   128  	cancel      context.CancelFunc
   129  	stream      refv1alpha.ServerReflection_ServerReflectionInfoClient
   130  	useV1Alpha  bool
   131  	lastTriedV1 time.Time
   132  
   133  	cacheMu          sync.RWMutex
   134  	protosByName     map[string]*descriptorpb.FileDescriptorProto
   135  	filesByName      map[string]*desc.FileDescriptor
   136  	filesBySymbol    map[string]*desc.FileDescriptor
   137  	filesByExtension map[extDesc]*desc.FileDescriptor
   138  }
   139  
   140  // NewClient creates a new Client with the given root context and using the
   141  // given RPC stub for talking to the server.
   142  //
   143  // Deprecated: Use NewClientV1Alpha if you are intentionally pinning the
   144  // v1alpha version of the reflection service. Otherwise, use NewClientAuto
   145  // instead.
   146  func NewClient(ctx context.Context, stub refv1alpha.ServerReflectionClient) *Client {
   147  	return NewClientV1Alpha(ctx, stub)
   148  }
   149  
   150  // NewClientV1Alpha creates a new Client using the v1alpha version of reflection
   151  // with the given root context and using the given RPC stub for talking to the
   152  // server.
   153  func NewClientV1Alpha(ctx context.Context, stub refv1alpha.ServerReflectionClient) *Client {
   154  	return newClient(ctx, nil, stub)
   155  }
   156  
   157  func newClient(ctx context.Context, stubv1 refv1.ServerReflectionClient, stubv1alpha refv1alpha.ServerReflectionClient) *Client {
   158  	cr := &Client{
   159  		ctx:              ctx,
   160  		now:              time.Now,
   161  		stubV1:           stubv1,
   162  		stubV1Alpha:      stubv1alpha,
   163  		protosByName:     map[string]*descriptorpb.FileDescriptorProto{},
   164  		filesByName:      map[string]*desc.FileDescriptor{},
   165  		filesBySymbol:    map[string]*desc.FileDescriptor{},
   166  		filesByExtension: map[extDesc]*desc.FileDescriptor{},
   167  	}
   168  	// don't leak a grpc stream
   169  	runtime.SetFinalizer(cr, (*Client).Reset)
   170  	return cr
   171  }
   172  
   173  // NewClientAuto creates a new Client that will use either v1 or v1alpha version
   174  // of reflection (based on what the server supports) with the given root context
   175  // and using the given client connection.
   176  //
   177  // It will first the v1 version of the reflection service. If it gets back an
   178  // "Unimplemented" error, it will fall back to using the v1alpha version. It
   179  // will remember which version the server supports for any subsequent operations
   180  // that need to re-invoke the streaming RPC. But, if it's a very long-lived
   181  // client, it will periodically retry the v1 version (in case the server is
   182  // updated to support it also). The period for these retries is every hour.
   183  func NewClientAuto(ctx context.Context, cc grpc.ClientConnInterface) *Client {
   184  	stubv1 := refv1.NewServerReflectionClient(cc)
   185  	stubv1alpha := refv1alpha.NewServerReflectionClient(cc)
   186  	return newClient(ctx, stubv1, stubv1alpha)
   187  }
   188  
   189  // TODO: We should also have a NewClientV1. However that should not refer to internal
   190  // generated code. So it will have to wait until the grpc-go team fixes this issue:
   191  //  https://github.com/grpc/grpc-go/issues/5684
   192  
   193  // FileByFilename asks the server for a file descriptor for the proto file with
   194  // the given name.
   195  func (cr *Client) FileByFilename(filename string) (*desc.FileDescriptor, error) {
   196  	// hit the cache first
   197  	cr.cacheMu.RLock()
   198  	if fd, ok := cr.filesByName[filename]; ok {
   199  		cr.cacheMu.RUnlock()
   200  		return fd, nil
   201  	}
   202  	fdp, ok := cr.protosByName[filename]
   203  	cr.cacheMu.RUnlock()
   204  	// not there? see if we've downloaded the proto
   205  	if ok {
   206  		return cr.descriptorFromProto(fdp)
   207  	}
   208  
   209  	req := &refv1alpha.ServerReflectionRequest{
   210  		MessageRequest: &refv1alpha.ServerReflectionRequest_FileByFilename{
   211  			FileByFilename: filename,
   212  		},
   213  	}
   214  	accept := func(fd *desc.FileDescriptor) bool {
   215  		return fd.GetName() == filename
   216  	}
   217  
   218  	fd, err := cr.getAndCacheFileDescriptors(req, filename, "", accept)
   219  	if isNotFound(err) {
   220  		// file not found? see if we can look up via alternate name
   221  		if alternate, ok := internal.StdFileAliases[filename]; ok {
   222  			req := &refv1alpha.ServerReflectionRequest{
   223  				MessageRequest: &refv1alpha.ServerReflectionRequest_FileByFilename{
   224  					FileByFilename: alternate,
   225  				},
   226  			}
   227  			fd, err = cr.getAndCacheFileDescriptors(req, alternate, filename, accept)
   228  			if isNotFound(err) {
   229  				err = fileNotFound(filename, nil)
   230  			}
   231  		} else {
   232  			err = fileNotFound(filename, nil)
   233  		}
   234  	} else if e, ok := err.(*elementNotFoundError); ok {
   235  		err = fileNotFound(filename, e)
   236  	}
   237  	return fd, err
   238  }
   239  
   240  // FileContainingSymbol asks the server for a file descriptor for the proto file
   241  // that declares the given fully-qualified symbol.
   242  func (cr *Client) FileContainingSymbol(symbol string) (*desc.FileDescriptor, error) {
   243  	// hit the cache first
   244  	cr.cacheMu.RLock()
   245  	fd, ok := cr.filesBySymbol[symbol]
   246  	cr.cacheMu.RUnlock()
   247  	if ok {
   248  		return fd, nil
   249  	}
   250  
   251  	req := &refv1alpha.ServerReflectionRequest{
   252  		MessageRequest: &refv1alpha.ServerReflectionRequest_FileContainingSymbol{
   253  			FileContainingSymbol: symbol,
   254  		},
   255  	}
   256  	accept := func(fd *desc.FileDescriptor) bool {
   257  		return fd.FindSymbol(symbol) != nil
   258  	}
   259  	fd, err := cr.getAndCacheFileDescriptors(req, "", "", accept)
   260  	if isNotFound(err) {
   261  		err = symbolNotFound(symbol, symbolTypeUnknown, nil)
   262  	} else if e, ok := err.(*elementNotFoundError); ok {
   263  		err = symbolNotFound(symbol, symbolTypeUnknown, e)
   264  	}
   265  	return fd, err
   266  }
   267  
   268  // FileContainingExtension asks the server for a file descriptor for the proto
   269  // file that declares an extension with the given number for the given
   270  // fully-qualified message name.
   271  func (cr *Client) FileContainingExtension(extendedMessageName string, extensionNumber int32) (*desc.FileDescriptor, error) {
   272  	// hit the cache first
   273  	cr.cacheMu.RLock()
   274  	fd, ok := cr.filesByExtension[extDesc{extendedMessageName, extensionNumber}]
   275  	cr.cacheMu.RUnlock()
   276  	if ok {
   277  		return fd, nil
   278  	}
   279  
   280  	req := &refv1alpha.ServerReflectionRequest{
   281  		MessageRequest: &refv1alpha.ServerReflectionRequest_FileContainingExtension{
   282  			FileContainingExtension: &refv1alpha.ExtensionRequest{
   283  				ContainingType:  extendedMessageName,
   284  				ExtensionNumber: extensionNumber,
   285  			},
   286  		},
   287  	}
   288  	accept := func(fd *desc.FileDescriptor) bool {
   289  		return fd.FindExtension(extendedMessageName, extensionNumber) != nil
   290  	}
   291  	fd, err := cr.getAndCacheFileDescriptors(req, "", "", accept)
   292  	if isNotFound(err) {
   293  		err = extensionNotFound(extendedMessageName, extensionNumber, nil)
   294  	} else if e, ok := err.(*elementNotFoundError); ok {
   295  		err = extensionNotFound(extendedMessageName, extensionNumber, e)
   296  	}
   297  	return fd, err
   298  }
   299  
   300  func (cr *Client) getAndCacheFileDescriptors(req *refv1alpha.ServerReflectionRequest, expectedName, alias string, accept func(*desc.FileDescriptor) bool) (*desc.FileDescriptor, error) {
   301  	resp, err := cr.send(req)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	fdResp := resp.GetFileDescriptorResponse()
   307  	if fdResp == nil {
   308  		return nil, &ProtocolError{reflect.TypeOf(fdResp).Elem()}
   309  	}
   310  
   311  	// Response can contain the result file descriptor, but also its transitive
   312  	// deps. Furthermore, protocol states that subsequent requests do not need
   313  	// to send transitive deps that have been sent in prior responses. So we
   314  	// need to cache all file descriptors and then return the first one (which
   315  	// should be the answer). If we're looking for a file by name, we can be
   316  	// smarter and make sure to grab one by name instead of just grabbing the
   317  	// first one.
   318  	var fds []*descriptorpb.FileDescriptorProto
   319  	for _, fdBytes := range fdResp.FileDescriptorProto {
   320  		fd := &descriptorpb.FileDescriptorProto{}
   321  		if err = proto.Unmarshal(fdBytes, fd); err != nil {
   322  			return nil, err
   323  		}
   324  
   325  		if expectedName != "" && alias != "" && expectedName != alias && fd.GetName() == expectedName {
   326  			// we found a file was aliased, so we need to update the proto to reflect that
   327  			fd.Name = proto.String(alias)
   328  		}
   329  
   330  		cr.cacheMu.Lock()
   331  		// store in cache of raw descriptor protos, but don't overwrite existing protos
   332  		if existingFd, ok := cr.protosByName[fd.GetName()]; ok {
   333  			fd = existingFd
   334  		} else {
   335  			cr.protosByName[fd.GetName()] = fd
   336  		}
   337  		cr.cacheMu.Unlock()
   338  
   339  		fds = append(fds, fd)
   340  	}
   341  
   342  	// find the right result from the files returned
   343  	for _, fd := range fds {
   344  		result, err := cr.descriptorFromProto(fd)
   345  		if err != nil {
   346  			return nil, err
   347  		}
   348  		if accept(result) {
   349  			return result, nil
   350  		}
   351  	}
   352  
   353  	return nil, status.Errorf(codes.NotFound, "response does not include expected file")
   354  }
   355  
   356  func (cr *Client) descriptorFromProto(fd *descriptorpb.FileDescriptorProto) (*desc.FileDescriptor, error) {
   357  	deps := make([]*desc.FileDescriptor, len(fd.GetDependency()))
   358  	for i, depName := range fd.GetDependency() {
   359  		if dep, err := cr.FileByFilename(depName); err != nil {
   360  			return nil, err
   361  		} else {
   362  			deps[i] = dep
   363  		}
   364  	}
   365  	d, err := desc.CreateFileDescriptor(fd, deps...)
   366  	if err != nil {
   367  		return nil, err
   368  	}
   369  	d = cr.cacheFile(d)
   370  	return d, nil
   371  }
   372  
   373  func (cr *Client) cacheFile(fd *desc.FileDescriptor) *desc.FileDescriptor {
   374  	cr.cacheMu.Lock()
   375  	defer cr.cacheMu.Unlock()
   376  
   377  	// cache file descriptor by name, but don't overwrite existing entry
   378  	// (existing entry could come from concurrent caller)
   379  	if existingFd, ok := cr.filesByName[fd.GetName()]; ok {
   380  		return existingFd
   381  	}
   382  	cr.filesByName[fd.GetName()] = fd
   383  
   384  	// also cache by symbols and extensions
   385  	for _, m := range fd.GetMessageTypes() {
   386  		cr.cacheMessageLocked(fd, m)
   387  	}
   388  	for _, e := range fd.GetEnumTypes() {
   389  		cr.filesBySymbol[e.GetFullyQualifiedName()] = fd
   390  		for _, v := range e.GetValues() {
   391  			cr.filesBySymbol[v.GetFullyQualifiedName()] = fd
   392  		}
   393  	}
   394  	for _, e := range fd.GetExtensions() {
   395  		cr.filesBySymbol[e.GetFullyQualifiedName()] = fd
   396  		cr.filesByExtension[extDesc{e.GetOwner().GetFullyQualifiedName(), e.GetNumber()}] = fd
   397  	}
   398  	for _, s := range fd.GetServices() {
   399  		cr.filesBySymbol[s.GetFullyQualifiedName()] = fd
   400  		for _, m := range s.GetMethods() {
   401  			cr.filesBySymbol[m.GetFullyQualifiedName()] = fd
   402  		}
   403  	}
   404  
   405  	return fd
   406  }
   407  
   408  func (cr *Client) cacheMessageLocked(fd *desc.FileDescriptor, md *desc.MessageDescriptor) {
   409  	cr.filesBySymbol[md.GetFullyQualifiedName()] = fd
   410  	for _, f := range md.GetFields() {
   411  		cr.filesBySymbol[f.GetFullyQualifiedName()] = fd
   412  	}
   413  	for _, o := range md.GetOneOfs() {
   414  		cr.filesBySymbol[o.GetFullyQualifiedName()] = fd
   415  	}
   416  	for _, e := range md.GetNestedEnumTypes() {
   417  		cr.filesBySymbol[e.GetFullyQualifiedName()] = fd
   418  		for _, v := range e.GetValues() {
   419  			cr.filesBySymbol[v.GetFullyQualifiedName()] = fd
   420  		}
   421  	}
   422  	for _, e := range md.GetNestedExtensions() {
   423  		cr.filesBySymbol[e.GetFullyQualifiedName()] = fd
   424  		cr.filesByExtension[extDesc{e.GetOwner().GetFullyQualifiedName(), e.GetNumber()}] = fd
   425  	}
   426  	for _, m := range md.GetNestedMessageTypes() {
   427  		cr.cacheMessageLocked(fd, m) // recurse
   428  	}
   429  }
   430  
   431  // AllExtensionNumbersForType asks the server for all known extension numbers
   432  // for the given fully-qualified message name.
   433  func (cr *Client) AllExtensionNumbersForType(extendedMessageName string) ([]int32, error) {
   434  	req := &refv1alpha.ServerReflectionRequest{
   435  		MessageRequest: &refv1alpha.ServerReflectionRequest_AllExtensionNumbersOfType{
   436  			AllExtensionNumbersOfType: extendedMessageName,
   437  		},
   438  	}
   439  	resp, err := cr.send(req)
   440  	if err != nil {
   441  		if isNotFound(err) {
   442  			return nil, symbolNotFound(extendedMessageName, symbolTypeMessage, nil)
   443  		}
   444  		return nil, err
   445  	}
   446  
   447  	extResp := resp.GetAllExtensionNumbersResponse()
   448  	if extResp == nil {
   449  		return nil, &ProtocolError{reflect.TypeOf(extResp).Elem()}
   450  	}
   451  	return extResp.ExtensionNumber, nil
   452  }
   453  
   454  // ListServices asks the server for the fully-qualified names of all exposed
   455  // services.
   456  func (cr *Client) ListServices() ([]string, error) {
   457  	req := &refv1alpha.ServerReflectionRequest{
   458  		MessageRequest: &refv1alpha.ServerReflectionRequest_ListServices{
   459  			// proto doesn't indicate any purpose for this value and server impl
   460  			// doesn't actually use it...
   461  			ListServices: "*",
   462  		},
   463  	}
   464  	resp, err := cr.send(req)
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  
   469  	listResp := resp.GetListServicesResponse()
   470  	if listResp == nil {
   471  		return nil, &ProtocolError{reflect.TypeOf(listResp).Elem()}
   472  	}
   473  	serviceNames := make([]string, len(listResp.Service))
   474  	for i, s := range listResp.Service {
   475  		serviceNames[i] = s.Name
   476  	}
   477  	return serviceNames, nil
   478  }
   479  
   480  func (cr *Client) send(req *refv1alpha.ServerReflectionRequest) (*refv1alpha.ServerReflectionResponse, error) {
   481  	// we allow one immediate retry, in case we have a stale stream
   482  	// (e.g. closed by server)
   483  	resp, err := cr.doSend(req)
   484  	if err != nil {
   485  		return nil, err
   486  	}
   487  
   488  	// convert error response messages into errors
   489  	errResp := resp.GetErrorResponse()
   490  	if errResp != nil {
   491  		return nil, status.Errorf(codes.Code(errResp.ErrorCode), "%s", errResp.ErrorMessage)
   492  	}
   493  
   494  	return resp, nil
   495  }
   496  
   497  func isNotFound(err error) bool {
   498  	if err == nil {
   499  		return false
   500  	}
   501  	s, ok := status.FromError(err)
   502  	return ok && s.Code() == codes.NotFound
   503  }
   504  
   505  func (cr *Client) doSend(req *refv1alpha.ServerReflectionRequest) (*refv1alpha.ServerReflectionResponse, error) {
   506  	// TODO: Streams are thread-safe, so we shouldn't need to lock. But without locking, we'll need more machinery
   507  	// (goroutines and channels) to ensure that responses are correctly correlated with their requests and thus
   508  	// delivered in correct oder.
   509  	cr.connMu.Lock()
   510  	defer cr.connMu.Unlock()
   511  	return cr.doSendLocked(0, nil, req)
   512  }
   513  
   514  func (cr *Client) doSendLocked(attemptCount int, prevErr error, req *refv1alpha.ServerReflectionRequest) (*refv1alpha.ServerReflectionResponse, error) {
   515  	if attemptCount >= 3 && prevErr != nil {
   516  		return nil, prevErr
   517  	}
   518  	if (status.Code(prevErr) == codes.Unimplemented ||
   519  		status.Code(prevErr) == codes.Unavailable) &&
   520  		cr.useV1() {
   521  		// If v1 is unimplemented, fallback to v1alpha.
   522  		// We also fallback on unavailable because some servers have been
   523  		// observed to close the connection/cancel the stream, w/out sending
   524  		// back status or headers, when the service name is not known. When
   525  		// this happens, the RPC status code is unavailable.
   526  		// See https://github.com/fullstorydev/grpcurl/issues/434
   527  		cr.useV1Alpha = true
   528  		cr.lastTriedV1 = cr.now()
   529  	}
   530  	attemptCount++
   531  
   532  	if err := cr.initStreamLocked(); err != nil {
   533  		return nil, err
   534  	}
   535  
   536  	if err := cr.stream.Send(req); err != nil {
   537  		if err == io.EOF {
   538  			// if send returns EOF, must call Recv to get real underlying error
   539  			_, err = cr.stream.Recv()
   540  		}
   541  		cr.resetLocked()
   542  		return cr.doSendLocked(attemptCount, err, req)
   543  	}
   544  
   545  	resp, err := cr.stream.Recv()
   546  	if err != nil {
   547  		cr.resetLocked()
   548  		return cr.doSendLocked(attemptCount, err, req)
   549  	}
   550  	return resp, nil
   551  }
   552  
   553  func (cr *Client) initStreamLocked() error {
   554  	if cr.stream != nil {
   555  		return nil
   556  	}
   557  	var newCtx context.Context
   558  	newCtx, cr.cancel = context.WithCancel(cr.ctx)
   559  	if cr.useV1Alpha == true && cr.now().Sub(cr.lastTriedV1) > durationBetweenV1Attempts {
   560  		// we're due for periodic retry of v1
   561  		cr.useV1Alpha = false
   562  	}
   563  	if cr.useV1() {
   564  		// try the v1 API
   565  		streamv1, err := cr.stubV1.ServerReflectionInfo(newCtx)
   566  		if err == nil {
   567  			cr.stream = adaptStreamFromV1{streamv1}
   568  			return nil
   569  		}
   570  		if status.Code(err) != codes.Unimplemented {
   571  			return err
   572  		}
   573  		// oh well, fall through below to try v1alpha and update state
   574  		// so we skip straight to v1alpha next time
   575  		cr.useV1Alpha = true
   576  		cr.lastTriedV1 = cr.now()
   577  	}
   578  	var err error
   579  	cr.stream, err = cr.stubV1Alpha.ServerReflectionInfo(newCtx)
   580  	return err
   581  }
   582  
   583  func (cr *Client) useV1() bool {
   584  	return !cr.useV1Alpha && cr.stubV1 != nil
   585  }
   586  
   587  // Reset ensures that any active stream with the server is closed, releasing any
   588  // resources.
   589  func (cr *Client) Reset() {
   590  	cr.connMu.Lock()
   591  	defer cr.connMu.Unlock()
   592  	cr.resetLocked()
   593  }
   594  
   595  func (cr *Client) resetLocked() {
   596  	if cr.stream != nil {
   597  		cr.stream.CloseSend()
   598  		for {
   599  			// drain the stream, this covers io.EOF too
   600  			if _, err := cr.stream.Recv(); err != nil {
   601  				break
   602  			}
   603  		}
   604  		cr.stream = nil
   605  	}
   606  	if cr.cancel != nil {
   607  		cr.cancel()
   608  		cr.cancel = nil
   609  	}
   610  }
   611  
   612  // ResolveService asks the server to resolve the given fully-qualified service
   613  // name into a service descriptor.
   614  func (cr *Client) ResolveService(serviceName string) (*desc.ServiceDescriptor, error) {
   615  	file, err := cr.FileContainingSymbol(serviceName)
   616  	if err != nil {
   617  		return nil, setSymbolType(err, serviceName, symbolTypeService)
   618  	}
   619  	d := file.FindSymbol(serviceName)
   620  	if d == nil {
   621  		return nil, symbolNotFound(serviceName, symbolTypeService, nil)
   622  	}
   623  	if s, ok := d.(*desc.ServiceDescriptor); ok {
   624  		return s, nil
   625  	} else {
   626  		return nil, symbolNotFound(serviceName, symbolTypeService, nil)
   627  	}
   628  }
   629  
   630  // ResolveMessage asks the server to resolve the given fully-qualified message
   631  // name into a message descriptor.
   632  func (cr *Client) ResolveMessage(messageName string) (*desc.MessageDescriptor, error) {
   633  	file, err := cr.FileContainingSymbol(messageName)
   634  	if err != nil {
   635  		return nil, setSymbolType(err, messageName, symbolTypeMessage)
   636  	}
   637  	d := file.FindSymbol(messageName)
   638  	if d == nil {
   639  		return nil, symbolNotFound(messageName, symbolTypeMessage, nil)
   640  	}
   641  	if s, ok := d.(*desc.MessageDescriptor); ok {
   642  		return s, nil
   643  	} else {
   644  		return nil, symbolNotFound(messageName, symbolTypeMessage, nil)
   645  	}
   646  }
   647  
   648  // ResolveEnum asks the server to resolve the given fully-qualified enum name
   649  // into an enum descriptor.
   650  func (cr *Client) ResolveEnum(enumName string) (*desc.EnumDescriptor, error) {
   651  	file, err := cr.FileContainingSymbol(enumName)
   652  	if err != nil {
   653  		return nil, setSymbolType(err, enumName, symbolTypeEnum)
   654  	}
   655  	d := file.FindSymbol(enumName)
   656  	if d == nil {
   657  		return nil, symbolNotFound(enumName, symbolTypeEnum, nil)
   658  	}
   659  	if s, ok := d.(*desc.EnumDescriptor); ok {
   660  		return s, nil
   661  	} else {
   662  		return nil, symbolNotFound(enumName, symbolTypeEnum, nil)
   663  	}
   664  }
   665  
   666  func setSymbolType(err error, name string, symType symbolType) error {
   667  	if e, ok := err.(*elementNotFoundError); ok {
   668  		if e.kind == elementKindSymbol && e.name == name && e.symType == symbolTypeUnknown {
   669  			e.symType = symType
   670  		}
   671  	}
   672  	return err
   673  }
   674  
   675  // ResolveEnumValues asks the server to resolve the given fully-qualified enum
   676  // name into a map of names to numbers that represents the enum's values.
   677  func (cr *Client) ResolveEnumValues(enumName string) (map[string]int32, error) {
   678  	enumDesc, err := cr.ResolveEnum(enumName)
   679  	if err != nil {
   680  		return nil, err
   681  	}
   682  	vals := map[string]int32{}
   683  	for _, valDesc := range enumDesc.GetValues() {
   684  		vals[valDesc.GetName()] = valDesc.GetNumber()
   685  	}
   686  	return vals, nil
   687  }
   688  
   689  // ResolveExtension asks the server to resolve the given extension number and
   690  // fully-qualified message name into a field descriptor.
   691  func (cr *Client) ResolveExtension(extendedType string, extensionNumber int32) (*desc.FieldDescriptor, error) {
   692  	file, err := cr.FileContainingExtension(extendedType, extensionNumber)
   693  	if err != nil {
   694  		return nil, err
   695  	}
   696  	d := findExtension(extendedType, extensionNumber, fileDescriptorExtensions{file})
   697  	if d == nil {
   698  		return nil, extensionNotFound(extendedType, extensionNumber, nil)
   699  	} else {
   700  		return d, nil
   701  	}
   702  }
   703  
   704  func findExtension(extendedType string, extensionNumber int32, scope extensionScope) *desc.FieldDescriptor {
   705  	// search extensions in this scope
   706  	for _, ext := range scope.extensions() {
   707  		if ext.GetNumber() == extensionNumber && ext.GetOwner().GetFullyQualifiedName() == extendedType {
   708  			return ext
   709  		}
   710  	}
   711  
   712  	// if not found, search nested scopes
   713  	for _, nested := range scope.nestedScopes() {
   714  		ext := findExtension(extendedType, extensionNumber, nested)
   715  		if ext != nil {
   716  			return ext
   717  		}
   718  	}
   719  
   720  	return nil
   721  }
   722  
   723  type extensionScope interface {
   724  	extensions() []*desc.FieldDescriptor
   725  	nestedScopes() []extensionScope
   726  }
   727  
   728  // fileDescriptorExtensions implements extensionHolder interface on top of
   729  // FileDescriptorProto
   730  type fileDescriptorExtensions struct {
   731  	proto *desc.FileDescriptor
   732  }
   733  
   734  func (fde fileDescriptorExtensions) extensions() []*desc.FieldDescriptor {
   735  	return fde.proto.GetExtensions()
   736  }
   737  
   738  func (fde fileDescriptorExtensions) nestedScopes() []extensionScope {
   739  	scopes := make([]extensionScope, len(fde.proto.GetMessageTypes()))
   740  	for i, m := range fde.proto.GetMessageTypes() {
   741  		scopes[i] = msgDescriptorExtensions{m}
   742  	}
   743  	return scopes
   744  }
   745  
   746  // msgDescriptorExtensions implements extensionHolder interface on top of
   747  // DescriptorProto
   748  type msgDescriptorExtensions struct {
   749  	proto *desc.MessageDescriptor
   750  }
   751  
   752  func (mde msgDescriptorExtensions) extensions() []*desc.FieldDescriptor {
   753  	return mde.proto.GetNestedExtensions()
   754  }
   755  
   756  func (mde msgDescriptorExtensions) nestedScopes() []extensionScope {
   757  	scopes := make([]extensionScope, len(mde.proto.GetNestedMessageTypes()))
   758  	for i, m := range mde.proto.GetNestedMessageTypes() {
   759  		scopes[i] = msgDescriptorExtensions{m}
   760  	}
   761  	return scopes
   762  }
   763  
   764  type adaptStreamFromV1 struct {
   765  	refv1.ServerReflection_ServerReflectionInfoClient
   766  }
   767  
   768  func (a adaptStreamFromV1) Send(request *refv1alpha.ServerReflectionRequest) error {
   769  	v1req := toV1Request(request)
   770  	return a.ServerReflection_ServerReflectionInfoClient.Send(v1req)
   771  }
   772  
   773  func (a adaptStreamFromV1) Recv() (*refv1alpha.ServerReflectionResponse, error) {
   774  	v1resp, err := a.ServerReflection_ServerReflectionInfoClient.Recv()
   775  	if err != nil {
   776  		return nil, err
   777  	}
   778  	return toV1AlphaResponse(v1resp), nil
   779  }