github.com/phpstudyer/protoreflect@v1.7.2/dynamic/msgregistry/message_registry.go (about)

     1  package msgregistry
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/golang/protobuf/jsonpb"
    10  	"github.com/golang/protobuf/proto"
    11  	"github.com/golang/protobuf/protoc-gen-go/descriptor"
    12  	"github.com/golang/protobuf/ptypes"
    13  	"github.com/golang/protobuf/ptypes/any"
    14  	"github.com/golang/protobuf/ptypes/wrappers"
    15  	"google.golang.org/genproto/protobuf/api"
    16  	"google.golang.org/genproto/protobuf/ptype"
    17  	"google.golang.org/genproto/protobuf/source_context"
    18  
    19  	"github.com/phpstudyer/protoreflect/desc"
    20  	"github.com/phpstudyer/protoreflect/dynamic"
    21  )
    22  
    23  const googleApisDomain = "type.googleapis.com"
    24  
    25  // MessageRegistry is a registry that maps URLs to message types. It allows for marshalling
    26  // and unmarshalling Any types to and from dynamic messages.
    27  type MessageRegistry struct {
    28  	resolver       typeResolver
    29  	mf             *dynamic.MessageFactory
    30  	er             *dynamic.ExtensionRegistry
    31  	mu             sync.RWMutex
    32  	types          map[string]desc.Descriptor
    33  	baseUrls       map[string]string
    34  	defaultBaseUrl string
    35  }
    36  
    37  // NewMessageRegistryWithDefaults is a registry that includes all "default" message types,
    38  // which are those that are statically linked into the current program (e.g. registered by
    39  // protoc-generated code via proto.RegisterType). Note that it cannot resolve "default" enum
    40  // types since those don't actually get registered by protoc-generated code the same way.
    41  // Any types explicitly added to the registry will override any default message types with
    42  // the same URL.
    43  func NewMessageRegistryWithDefaults() *MessageRegistry {
    44  	mf := dynamic.NewMessageFactoryWithDefaults()
    45  	return &MessageRegistry{
    46  		mf: mf,
    47  		er: mf.GetExtensionRegistry(),
    48  	}
    49  }
    50  
    51  // WithFetcher sets the TypeFetcher that this registry uses to resolve unknown URLs. If no fetcher
    52  // is configured for the registry then unknown URLs cannot be resolved. Known URLs are those for
    53  // explicitly registered types and, if the registry includes "default" types, those for statically
    54  // linked message types. This method is not thread-safe and is intended to be used for one-time
    55  // initialization of the registry, before it is published for use by other threads.
    56  func (r *MessageRegistry) WithFetcher(fetcher TypeFetcher) *MessageRegistry {
    57  	r.resolver = typeResolver{fetcher: fetcher, mr: r}
    58  	return r
    59  }
    60  
    61  // WithMessageFactory sets the MessageFactory used to instantiate any messages.
    62  // This method is not thread-safe and is intended to be used for one-time
    63  // initialization of the registry, before it is published for use by other threads.
    64  func (r *MessageRegistry) WithMessageFactory(mf *dynamic.MessageFactory) *MessageRegistry {
    65  	r.mf = mf
    66  	if mf == nil {
    67  		r.er = nil
    68  	} else {
    69  		r.er = mf.GetExtensionRegistry()
    70  	}
    71  	return r
    72  }
    73  
    74  // WithDefaultBaseUrl sets the default base URL used when constructing type URLs for
    75  // marshalling messages as Any types and converting descriptors to well-known type
    76  // descriptions (ptypes). If unspecified, the default base URL will be "type.googleapis.com".
    77  // This method is not thread-safe and is intended to be used for one-time initialization
    78  // of the registry, before it is published for use by other threads.
    79  func (r *MessageRegistry) WithDefaultBaseUrl(baseUrl string) *MessageRegistry {
    80  	baseUrl = stripTrailingSlash(baseUrl)
    81  	r.defaultBaseUrl = baseUrl
    82  	return r
    83  }
    84  
    85  func stripTrailingSlash(url string) string {
    86  	if url[len(url)-1] == '/' {
    87  		return url[:len(url)-1]
    88  	}
    89  	return url
    90  }
    91  
    92  // AddMessage adds the given URL and associated message descriptor to the registry.
    93  func (r *MessageRegistry) AddMessage(url string, md *desc.MessageDescriptor) error {
    94  	url = ensureScheme(url)
    95  	baseUrl := strings.TrimSuffix(url, "/"+md.GetFullyQualifiedName())
    96  	if url == baseUrl {
    97  		return fmt.Errorf("URL %s is invalid: it should end with path element %s", url, md.GetFullyQualifiedName())
    98  	}
    99  	r.mu.Lock()
   100  	defer r.mu.Unlock()
   101  	if r.types == nil {
   102  		r.types = map[string]desc.Descriptor{}
   103  	}
   104  	r.types[url] = md
   105  	if r.baseUrls == nil {
   106  		r.baseUrls = map[string]string{}
   107  	}
   108  	r.baseUrls[md.GetFullyQualifiedName()] = baseUrl
   109  	return nil
   110  }
   111  
   112  // AddEnum adds the given URL and associated enum descriptor to the registry.
   113  func (r *MessageRegistry) AddEnum(url string, ed *desc.EnumDescriptor) error {
   114  	url = ensureScheme(url)
   115  	baseUrl := strings.TrimSuffix(url, "/"+ed.GetFullyQualifiedName())
   116  	if url == baseUrl {
   117  		return fmt.Errorf("URL %s is invalid: it should end with path element %s", url, ed.GetFullyQualifiedName())
   118  	}
   119  	r.mu.Lock()
   120  	defer r.mu.Unlock()
   121  	if r.types == nil {
   122  		r.types = map[string]desc.Descriptor{}
   123  	}
   124  	r.types[url] = ed
   125  	if r.baseUrls == nil {
   126  		r.baseUrls = map[string]string{}
   127  	}
   128  	r.baseUrls[ed.GetFullyQualifiedName()] = baseUrl
   129  	return nil
   130  }
   131  
   132  // AddFile adds to the registry all message and enum types in the given file. The URL for each type
   133  // is derived using the given base URL as "baseURL/fully.qualified.type.name".
   134  func (r *MessageRegistry) AddFile(baseUrl string, fd *desc.FileDescriptor) {
   135  	baseUrl = stripTrailingSlash(ensureScheme(baseUrl))
   136  	r.mu.Lock()
   137  	defer r.mu.Unlock()
   138  	if r.types == nil {
   139  		r.types = map[string]desc.Descriptor{}
   140  	}
   141  	if r.baseUrls == nil {
   142  		r.baseUrls = map[string]string{}
   143  	}
   144  	r.addEnumTypesLocked(baseUrl, fd.GetEnumTypes())
   145  	r.addMessageTypesLocked(baseUrl, fd.GetMessageTypes())
   146  }
   147  
   148  func (r *MessageRegistry) addEnumTypesLocked(baseUrl string, enums []*desc.EnumDescriptor) {
   149  	for _, ed := range enums {
   150  		url := fmt.Sprintf("%s/%s", baseUrl, ed.GetFullyQualifiedName())
   151  		r.types[url] = ed
   152  		r.baseUrls[ed.GetFullyQualifiedName()] = baseUrl
   153  	}
   154  }
   155  
   156  func (r *MessageRegistry) addMessageTypesLocked(baseUrl string, msgs []*desc.MessageDescriptor) {
   157  	for _, md := range msgs {
   158  		url := fmt.Sprintf("%s/%s", baseUrl, md.GetFullyQualifiedName())
   159  		r.types[url] = md
   160  		r.baseUrls[md.GetFullyQualifiedName()] = baseUrl
   161  		r.addEnumTypesLocked(baseUrl, md.GetNestedEnumTypes())
   162  		r.addMessageTypesLocked(baseUrl, md.GetNestedMessageTypes())
   163  	}
   164  }
   165  
   166  // FindMessageTypeByUrl finds a message descriptor for the type at the given URL. It may
   167  // return nil if the registry is empty and cannot resolve unknown URLs. If an error occurs
   168  // while resolving the URL, it is returned.
   169  func (r *MessageRegistry) FindMessageTypeByUrl(url string) (*desc.MessageDescriptor, error) {
   170  	md, err := r.getRegisteredMessageTypeByUrl(url)
   171  	if err != nil {
   172  		return nil, err
   173  	} else if md != nil {
   174  		return md, err
   175  	}
   176  
   177  	if r.resolver.fetcher == nil {
   178  		return nil, nil
   179  	}
   180  	return r.resolver.resolveUrlToMessageDescriptor(url)
   181  }
   182  
   183  func (r *MessageRegistry) getRegisteredMessageTypeByUrl(url string) (*desc.MessageDescriptor, error) {
   184  	if r != nil {
   185  		r.mu.RLock()
   186  		m := r.types[ensureScheme(url)]
   187  		r.mu.RUnlock()
   188  		if m != nil {
   189  			if md, ok := m.(*desc.MessageDescriptor); ok {
   190  				return md, nil
   191  			} else {
   192  				return nil, fmt.Errorf("type for URL %v is the wrong type: wanted message, got enum", url)
   193  			}
   194  		}
   195  	}
   196  
   197  	var ktr *dynamic.KnownTypeRegistry
   198  	if r != nil {
   199  		ktr = r.mf.GetKnownTypeRegistry()
   200  	}
   201  	msgType := ktr.GetKnownType(typeName(url))
   202  	if msgType == nil {
   203  		return nil, nil
   204  	}
   205  	return desc.LoadMessageDescriptorForType(msgType)
   206  }
   207  
   208  // FindEnumTypeByUrl finds an enum descriptor for the type at the given URL. It may return nil
   209  // if the registry is empty and cannot resolve unknown URLs. If an error occurs while resolving
   210  // the URL, it is returned.
   211  func (r *MessageRegistry) FindEnumTypeByUrl(url string) (*desc.EnumDescriptor, error) {
   212  	ed, err := r.getRegisteredEnumTypeByUrl(url)
   213  	if err != nil {
   214  		return nil, err
   215  	} else if ed != nil {
   216  		return ed, err
   217  	}
   218  
   219  	if r.resolver.fetcher == nil {
   220  		return nil, nil
   221  	}
   222  	if ed, err := r.resolver.resolveUrlToEnumDescriptor(url); err != nil {
   223  		return nil, err
   224  	} else {
   225  		return ed, nil
   226  	}
   227  }
   228  
   229  func (r *MessageRegistry) getRegisteredEnumTypeByUrl(url string) (*desc.EnumDescriptor, error) {
   230  	if r == nil {
   231  		return nil, nil
   232  	}
   233  	r.mu.RLock()
   234  	m := r.types[ensureScheme(url)]
   235  	r.mu.RUnlock()
   236  	if m != nil {
   237  		if ed, ok := m.(*desc.EnumDescriptor); ok {
   238  			return ed, nil
   239  		} else {
   240  			return nil, fmt.Errorf("type for URL %v is the wrong type: wanted enum, got message", url)
   241  		}
   242  	}
   243  	return nil, nil
   244  }
   245  
   246  // ResolveApiIntoServiceDescriptor constructs a service descriptor that describes the given API.
   247  // If any of the service's request or response type URLs cannot be resolved by this registry, a
   248  // nil descriptor is returned.
   249  func (r *MessageRegistry) ResolveApiIntoServiceDescriptor(a *api.Api) (*desc.ServiceDescriptor, error) {
   250  	if r == nil {
   251  		return nil, nil
   252  	}
   253  
   254  	msgs := map[string]*desc.MessageDescriptor{}
   255  	unresolved := map[string]struct{}{}
   256  	for _, m := range a.Methods {
   257  		// request type
   258  		md, err := r.getRegisteredMessageTypeByUrl(m.RequestTypeUrl)
   259  		if err != nil {
   260  			return nil, err
   261  		} else if md == nil {
   262  			if r.resolver.fetcher == nil {
   263  				return nil, nil
   264  			}
   265  			unresolved[m.RequestTypeUrl] = struct{}{}
   266  		} else {
   267  			msgs[m.RequestTypeUrl] = md
   268  		}
   269  		// and response type
   270  		md, err = r.getRegisteredMessageTypeByUrl(m.ResponseTypeUrl)
   271  		if err != nil {
   272  			return nil, err
   273  		} else if md == nil {
   274  			if r.resolver.fetcher == nil {
   275  				return nil, nil
   276  			}
   277  			unresolved[m.ResponseTypeUrl] = struct{}{}
   278  		} else {
   279  			msgs[m.ResponseTypeUrl] = md
   280  		}
   281  	}
   282  
   283  	if len(unresolved) > 0 {
   284  		unresolvedSlice := make([]string, 0, len(unresolved))
   285  		for k := range unresolved {
   286  			unresolvedSlice = append(unresolvedSlice, k)
   287  		}
   288  		mp, err := r.resolver.resolveUrlsToMessageDescriptors(unresolvedSlice...)
   289  		if err != nil {
   290  			return nil, err
   291  		}
   292  		for u, md := range mp {
   293  			msgs[u] = md
   294  		}
   295  	}
   296  
   297  	var fileName string
   298  	if a.SourceContext != nil && a.SourceContext.FileName != "" {
   299  		fileName = a.SourceContext.FileName
   300  	} else {
   301  		fileName = "--unknown--.proto"
   302  	}
   303  
   304  	// now we add all types we care about to a typeTrie and use that to generate file descriptors
   305  	files := map[string]*fileEntry{}
   306  	fe := &fileEntry{}
   307  	fe.proto3 = a.Syntax == ptype.Syntax_SYNTAX_PROTO3
   308  	files[fileName] = fe
   309  	fe.types.addType(a.Name, createServiceDescriptor(a, r))
   310  	added := newNameTracker()
   311  	for _, md := range msgs {
   312  		addDescriptors(fileName, files, md, msgs, added)
   313  	}
   314  
   315  	// build resulting file descriptor(s) and return the final service descriptor
   316  	fileDescriptors, err := toFileDescriptors(files, (*typeTrie).rewriteDescriptor)
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  	return fileDescriptors[fileName].FindService(a.Name), nil
   321  }
   322  
   323  // UnmarshalAny will unmarshal the value embedded in the given Any value. This will use this
   324  // registry to resolve the given value's type URL. Use this instead of ptypes.UnmarshalAny for
   325  // cases where the type might not be statically linked into the current program.
   326  func (r *MessageRegistry) UnmarshalAny(any *any.Any) (proto.Message, error) {
   327  	return r.unmarshalAny(any, r.FindMessageTypeByUrl)
   328  }
   329  
   330  func (r *MessageRegistry) unmarshalAny(any *any.Any, fetch func(string) (*desc.MessageDescriptor, error)) (proto.Message, error) {
   331  	name, err := ptypes.AnyMessageName(any)
   332  	if err != nil {
   333  		return nil, err
   334  	}
   335  
   336  	var msg proto.Message
   337  
   338  	var mf *dynamic.MessageFactory
   339  	var ktr *dynamic.KnownTypeRegistry
   340  	if r != nil {
   341  		mf = r.mf
   342  		ktr = r.mf.GetKnownTypeRegistry()
   343  	}
   344  	if msg = ktr.CreateIfKnown(name); msg == nil {
   345  		if md, err := fetch(any.TypeUrl); err != nil {
   346  			return nil, err
   347  		} else if md == nil {
   348  			return nil, fmt.Errorf("unknown message type: %s", any.TypeUrl)
   349  		} else {
   350  			msg = mf.NewDynamicMessage(md)
   351  		}
   352  	}
   353  
   354  	err = proto.Unmarshal(any.Value, msg)
   355  	if err != nil {
   356  		return nil, err
   357  	} else {
   358  		return msg, nil
   359  	}
   360  }
   361  
   362  // AddBaseUrlForElement adds a base URL for the given package or fully-qualified type name.
   363  // This is used to construct type URLs for message types. If a given type has an associated
   364  // base URL, it is used. Otherwise, the base URL for the type's package is used. If that is
   365  // also absent, the registry's default base URL is used.
   366  func (r *MessageRegistry) AddBaseUrlForElement(baseUrl, packageOrTypeName string) {
   367  	if baseUrl[len(baseUrl)-1] == '/' {
   368  		baseUrl = baseUrl[:len(baseUrl)-1]
   369  	}
   370  	r.mu.Lock()
   371  	defer r.mu.Unlock()
   372  	if r.baseUrls == nil {
   373  		r.baseUrls = map[string]string{}
   374  	}
   375  	r.baseUrls[packageOrTypeName] = baseUrl
   376  }
   377  
   378  // MarshalAny wraps the given message in an Any value.
   379  func (r *MessageRegistry) MarshalAny(m proto.Message) (*any.Any, error) {
   380  	var md *desc.MessageDescriptor
   381  	if dm, ok := m.(*dynamic.Message); ok {
   382  		md = dm.GetMessageDescriptor()
   383  	} else {
   384  		var err error
   385  		md, err = desc.LoadMessageDescriptorForMessage(m)
   386  		if err != nil {
   387  			return nil, err
   388  		}
   389  	}
   390  
   391  	if b, err := proto.Marshal(m); err != nil {
   392  		return nil, err
   393  	} else {
   394  		return &any.Any{TypeUrl: r.ComputeUrl(md), Value: b}, nil
   395  	}
   396  }
   397  
   398  // MessageAsPType converts the given message descriptor into a ptype.Type. Registered
   399  // base URLs are used to compute type URLs for any fields that have message or enum
   400  // types.
   401  func (r *MessageRegistry) MessageAsPType(md *desc.MessageDescriptor) *ptype.Type {
   402  	fs := md.GetFields()
   403  	fields := make([]*ptype.Field, len(fs))
   404  	for i, f := range fs {
   405  		fields[i] = r.fieldAsPType(f)
   406  	}
   407  	oos := md.GetOneOfs()
   408  	oneOfs := make([]string, len(oos))
   409  	for i, oo := range oos {
   410  		oneOfs[i] = oo.GetName()
   411  	}
   412  	return &ptype.Type{
   413  		Name:          md.GetFullyQualifiedName(),
   414  		Fields:        fields,
   415  		Oneofs:        oneOfs,
   416  		Options:       r.options(md.GetOptions()),
   417  		Syntax:        syntax(md.GetFile()),
   418  		SourceContext: &source_context.SourceContext{FileName: md.GetFile().GetName()},
   419  	}
   420  }
   421  
   422  func (r *MessageRegistry) fieldAsPType(fd *desc.FieldDescriptor) *ptype.Field {
   423  	opts := r.options(fd.GetOptions())
   424  	// remove the "packed" option as that is represented via separate field in ptype.Field
   425  	for i, o := range opts {
   426  		if o.Name == "packed" {
   427  			opts = append(opts[:i], opts[i+1:]...)
   428  			break
   429  		}
   430  	}
   431  
   432  	var oneOf int32
   433  	if fd.AsFieldDescriptorProto().OneofIndex != nil {
   434  		oneOf = fd.AsFieldDescriptorProto().GetOneofIndex() + 1
   435  	}
   436  
   437  	var card ptype.Field_Cardinality
   438  	switch fd.GetLabel() {
   439  	case descriptor.FieldDescriptorProto_LABEL_OPTIONAL:
   440  		card = ptype.Field_CARDINALITY_OPTIONAL
   441  	case descriptor.FieldDescriptorProto_LABEL_REPEATED:
   442  		card = ptype.Field_CARDINALITY_REPEATED
   443  	case descriptor.FieldDescriptorProto_LABEL_REQUIRED:
   444  		card = ptype.Field_CARDINALITY_REQUIRED
   445  	}
   446  
   447  	var url string
   448  	var kind ptype.Field_Kind
   449  	switch fd.GetType() {
   450  	case descriptor.FieldDescriptorProto_TYPE_ENUM:
   451  		kind = ptype.Field_TYPE_ENUM
   452  		url = r.ComputeUrl(fd.GetEnumType())
   453  	case descriptor.FieldDescriptorProto_TYPE_GROUP:
   454  		kind = ptype.Field_TYPE_GROUP
   455  		url = r.ComputeUrl(fd.GetMessageType())
   456  	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
   457  		kind = ptype.Field_TYPE_MESSAGE
   458  		url = r.ComputeUrl(fd.GetMessageType())
   459  	case descriptor.FieldDescriptorProto_TYPE_BYTES:
   460  		kind = ptype.Field_TYPE_BYTES
   461  	case descriptor.FieldDescriptorProto_TYPE_STRING:
   462  		kind = ptype.Field_TYPE_STRING
   463  	case descriptor.FieldDescriptorProto_TYPE_BOOL:
   464  		kind = ptype.Field_TYPE_BOOL
   465  	case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
   466  		kind = ptype.Field_TYPE_DOUBLE
   467  	case descriptor.FieldDescriptorProto_TYPE_FLOAT:
   468  		kind = ptype.Field_TYPE_FLOAT
   469  	case descriptor.FieldDescriptorProto_TYPE_FIXED32:
   470  		kind = ptype.Field_TYPE_FIXED32
   471  	case descriptor.FieldDescriptorProto_TYPE_FIXED64:
   472  		kind = ptype.Field_TYPE_FIXED64
   473  	case descriptor.FieldDescriptorProto_TYPE_INT32:
   474  		kind = ptype.Field_TYPE_INT32
   475  	case descriptor.FieldDescriptorProto_TYPE_INT64:
   476  		kind = ptype.Field_TYPE_INT64
   477  	case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
   478  		kind = ptype.Field_TYPE_SFIXED32
   479  	case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
   480  		kind = ptype.Field_TYPE_SFIXED64
   481  	case descriptor.FieldDescriptorProto_TYPE_SINT32:
   482  		kind = ptype.Field_TYPE_SINT32
   483  	case descriptor.FieldDescriptorProto_TYPE_SINT64:
   484  		kind = ptype.Field_TYPE_SINT64
   485  	case descriptor.FieldDescriptorProto_TYPE_UINT32:
   486  		kind = ptype.Field_TYPE_UINT32
   487  	case descriptor.FieldDescriptorProto_TYPE_UINT64:
   488  		kind = ptype.Field_TYPE_UINT64
   489  	}
   490  
   491  	return &ptype.Field{
   492  		Name:         fd.GetName(),
   493  		Number:       fd.GetNumber(),
   494  		JsonName:     fd.AsFieldDescriptorProto().GetJsonName(),
   495  		OneofIndex:   oneOf,
   496  		DefaultValue: fd.AsFieldDescriptorProto().GetDefaultValue(),
   497  		Options:      opts,
   498  		Packed:       fd.GetFieldOptions().GetPacked(),
   499  		TypeUrl:      url,
   500  		Cardinality:  card,
   501  		Kind:         kind,
   502  	}
   503  }
   504  
   505  // EnumAsPType converts the given enum descriptor into a ptype.Enum.
   506  func (r *MessageRegistry) EnumAsPType(ed *desc.EnumDescriptor) *ptype.Enum {
   507  	vs := ed.GetValues()
   508  	vals := make([]*ptype.EnumValue, len(vs))
   509  	for i, v := range vs {
   510  		vals[i] = r.enumValueAsPType(v)
   511  	}
   512  	return &ptype.Enum{
   513  		Name:          ed.GetFullyQualifiedName(),
   514  		Enumvalue:     vals,
   515  		Options:       r.options(ed.GetOptions()),
   516  		Syntax:        syntax(ed.GetFile()),
   517  		SourceContext: &source_context.SourceContext{FileName: ed.GetFile().GetName()},
   518  	}
   519  }
   520  
   521  func (r *MessageRegistry) enumValueAsPType(vd *desc.EnumValueDescriptor) *ptype.EnumValue {
   522  	return &ptype.EnumValue{
   523  		Name:    vd.GetName(),
   524  		Number:  vd.GetNumber(),
   525  		Options: r.options(vd.GetOptions()),
   526  	}
   527  }
   528  
   529  // ServiceAsApi converts the given service descriptor into a ptype API description.
   530  func (r *MessageRegistry) ServiceAsApi(sd *desc.ServiceDescriptor) *api.Api {
   531  	ms := sd.GetMethods()
   532  	methods := make([]*api.Method, len(ms))
   533  	for i, m := range ms {
   534  		methods[i] = r.methodAsApi(m)
   535  	}
   536  	return &api.Api{
   537  		Name:          sd.GetFullyQualifiedName(),
   538  		Methods:       methods,
   539  		Options:       r.options(sd.GetOptions()),
   540  		Syntax:        syntax(sd.GetFile()),
   541  		SourceContext: &source_context.SourceContext{FileName: sd.GetFile().GetName()},
   542  	}
   543  }
   544  
   545  func (r *MessageRegistry) methodAsApi(md *desc.MethodDescriptor) *api.Method {
   546  	return &api.Method{
   547  		Name:              md.GetName(),
   548  		RequestStreaming:  md.IsClientStreaming(),
   549  		ResponseStreaming: md.IsServerStreaming(),
   550  		RequestTypeUrl:    r.ComputeUrl(md.GetInputType()),
   551  		ResponseTypeUrl:   r.ComputeUrl(md.GetOutputType()),
   552  		Options:           r.options(md.GetOptions()),
   553  		Syntax:            syntax(md.GetFile()),
   554  	}
   555  }
   556  
   557  func (r *MessageRegistry) options(options proto.Message) []*ptype.Option {
   558  	rv := reflect.ValueOf(options)
   559  	if rv.Kind() == reflect.Ptr {
   560  		if rv.IsNil() {
   561  			return nil
   562  		}
   563  		rv = rv.Elem()
   564  	}
   565  	var opts []*ptype.Option
   566  	for _, p := range proto.GetProperties(rv.Type()).Prop {
   567  		if p.Tag == 0 {
   568  			continue
   569  		}
   570  		o := r.option(p.OrigName, rv.FieldByName(p.Name))
   571  		if o != nil {
   572  			opts = append(opts, o...)
   573  		}
   574  	}
   575  	for _, ext := range proto.RegisteredExtensions(options) {
   576  		if proto.HasExtension(options, ext) {
   577  			v, err := proto.GetExtension(options, ext)
   578  			if err == nil && v != nil {
   579  				o := r.option(ext.Name, reflect.ValueOf(v))
   580  				if o != nil {
   581  					opts = append(opts, o...)
   582  				}
   583  			}
   584  		}
   585  	}
   586  	return opts
   587  }
   588  
   589  var typeOfBytes = reflect.TypeOf([]byte(nil))
   590  
   591  func (r *MessageRegistry) option(name string, value reflect.Value) []*ptype.Option {
   592  	if value.Kind() == reflect.Slice && value.Type() != typeOfBytes {
   593  		// repeated field
   594  		ret := make([]*ptype.Option, value.Len())
   595  		j := 0
   596  		for i := 0; i < value.Len(); i++ {
   597  			opt := r.singleOption(name, value.Index(i))
   598  			if opt != nil {
   599  				ret[j] = opt
   600  				j++
   601  			}
   602  		}
   603  		return ret[:j]
   604  	} else {
   605  		opt := r.singleOption(name, value)
   606  		if opt != nil {
   607  			return []*ptype.Option{opt}
   608  		}
   609  		return nil
   610  	}
   611  }
   612  
   613  func (r *MessageRegistry) singleOption(name string, value reflect.Value) *ptype.Option {
   614  	pm := wrap(value)
   615  	if pm == nil {
   616  		return nil
   617  	}
   618  	a, err := r.MarshalAny(pm)
   619  	if err != nil {
   620  		return nil
   621  	}
   622  	return &ptype.Option{
   623  		Name:  name,
   624  		Value: a,
   625  	}
   626  }
   627  
   628  func wrap(v reflect.Value) proto.Message {
   629  	if pm, ok := v.Interface().(proto.Message); ok {
   630  		return pm
   631  	}
   632  	if !v.IsValid() {
   633  		return nil
   634  	}
   635  	if v.Kind() == reflect.Ptr {
   636  		if v.IsNil() {
   637  			return nil
   638  		}
   639  		v = v.Elem()
   640  	}
   641  	switch v.Kind() {
   642  	case reflect.Bool:
   643  		return &wrappers.BoolValue{Value: v.Bool()}
   644  	case reflect.Slice:
   645  		if v.Type() != typeOfBytes {
   646  			panic(fmt.Sprintf("cannot convert/wrap %T as proto", v.Type()))
   647  		}
   648  		return &wrappers.BytesValue{Value: v.Bytes()}
   649  	case reflect.String:
   650  		return &wrappers.StringValue{Value: v.String()}
   651  	case reflect.Float32:
   652  		return &wrappers.FloatValue{Value: float32(v.Float())}
   653  	case reflect.Float64:
   654  		return &wrappers.DoubleValue{Value: v.Float()}
   655  	case reflect.Int32:
   656  		return &wrappers.Int32Value{Value: int32(v.Int())}
   657  	case reflect.Int64:
   658  		return &wrappers.Int64Value{Value: v.Int()}
   659  	case reflect.Uint32:
   660  		return &wrappers.UInt32Value{Value: uint32(v.Uint())}
   661  	case reflect.Uint64:
   662  		return &wrappers.UInt64Value{Value: v.Uint()}
   663  	default:
   664  		panic(fmt.Sprintf("cannot convert/wrap %T as proto", v.Type()))
   665  	}
   666  }
   667  
   668  func syntax(fd *desc.FileDescriptor) ptype.Syntax {
   669  	if fd.IsProto3() {
   670  		return ptype.Syntax_SYNTAX_PROTO3
   671  	} else {
   672  		return ptype.Syntax_SYNTAX_PROTO2
   673  	}
   674  }
   675  
   676  // ComputeUrl computes a type URL for element described by the given descriptor.
   677  // The given descriptor must be an enum or message descriptor. This will use any
   678  // registered URLs and base URLs to determine the appropriate URL for the given
   679  // type.
   680  //
   681  // Deprecated: This method is deprecated due to its use of non-idiomatic naming.
   682  // Use ComputeURL instead.
   683  func (r *MessageRegistry) ComputeUrl(d desc.Descriptor) string {
   684  	return r.ComputeURL(d)
   685  }
   686  
   687  // ComputeURL computes a type URL string for the element described by the given
   688  // descriptor. The given descriptor must be an enum or message descriptor. This
   689  // will use any registered URLs and base URLs to determine the appropriate URL
   690  // for the given type.
   691  func (r *MessageRegistry) ComputeURL(d desc.Descriptor) string {
   692  	name, pkg := d.GetFullyQualifiedName(), d.GetFile().GetPackage()
   693  	r.mu.RLock()
   694  	baseUrl := r.baseUrls[name]
   695  	if baseUrl == "" {
   696  		// lookup domain for the package
   697  		baseUrl = r.baseUrls[pkg]
   698  	}
   699  	r.mu.RUnlock()
   700  
   701  	if baseUrl == "" {
   702  		baseUrl = r.defaultBaseUrl
   703  		if baseUrl == "" {
   704  			baseUrl = googleApisDomain
   705  		}
   706  	}
   707  
   708  	return fmt.Sprintf("%s/%s", baseUrl, name)
   709  }
   710  
   711  // Resolve resolves the given type URL into an instance of a message. This
   712  // implements the jsonpb.AnyResolver interface, for use with marshaling and
   713  // unmarshaling Any messages to/from JSON.
   714  func (r *MessageRegistry) Resolve(typeUrl string) (proto.Message, error) {
   715  	md, err := r.FindMessageTypeByUrl(typeUrl)
   716  	if err != nil {
   717  		return nil, err
   718  	}
   719  	if md == nil {
   720  		return nil, fmt.Errorf("unknown message type: %s", typeUrl)
   721  	}
   722  	return r.mf.NewMessage(md), nil
   723  }
   724  
   725  var _ jsonpb.AnyResolver = (*MessageRegistry)(nil)