dubbo.apache.org/dubbo-go/v3@v3.1.1/common/metadata_info.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package common
    19  
    20  import (
    21  	"fmt"
    22  	"hash/crc32"
    23  	"net/url"
    24  	"sort"
    25  	"strings"
    26  )
    27  
    28  import (
    29  	gxset "github.com/dubbogo/gost/container/set"
    30  )
    31  
    32  import (
    33  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    34  )
    35  
    36  var IncludeKeys = gxset.NewSet(
    37  	constant.ApplicationKey,
    38  	constant.GroupKey,
    39  	constant.TimestampKey,
    40  	constant.SerializationKey,
    41  	constant.ClusterKey,
    42  	constant.LoadbalanceKey,
    43  	constant.PathKey,
    44  	constant.TimeoutKey,
    45  	constant.TokenKey,
    46  	constant.VersionKey,
    47  	constant.WarmupKey,
    48  	constant.WeightKey,
    49  	constant.ReleaseKey)
    50  
    51  // MetadataInfo the metadata information of instance
    52  type MetadataInfo struct {
    53  	Reported bool                    `json:"-"`
    54  	App      string                  `json:"app,omitempty"`
    55  	Revision string                  `json:"revision,omitempty"`
    56  	Services map[string]*ServiceInfo `json:"services,omitempty"`
    57  }
    58  
    59  // nolint
    60  func NewMetadataInfWithApp(app string) *MetadataInfo {
    61  	return NewMetadataInfo(app, "", make(map[string]*ServiceInfo))
    62  }
    63  
    64  // nolint
    65  func NewMetadataInfo(app string, revision string, services map[string]*ServiceInfo) *MetadataInfo {
    66  	return &MetadataInfo{
    67  		App:      app,
    68  		Revision: revision,
    69  		Services: services,
    70  		Reported: false,
    71  	}
    72  }
    73  
    74  // nolint
    75  func (mi *MetadataInfo) JavaClassName() string {
    76  	return "org.apache.dubbo.metadata.MetadataInfo"
    77  }
    78  
    79  // CalAndGetRevision is different from Dubbo because golang doesn't support overload
    80  // so that we should use interface + method name as identifier and ignore the method params
    81  // in my opinion, it's enough because Dubbo actually ignore the URL params.
    82  // please refer org.apache.dubbo.common.URL#toParameterString(java.lang.String...)
    83  func (mi *MetadataInfo) CalAndGetRevision() string {
    84  	if mi.Revision != "" && mi.Reported {
    85  		return mi.Revision
    86  	}
    87  	if len(mi.Services) == 0 {
    88  		return "0"
    89  	}
    90  	candidates := make([]string, 0, 8)
    91  
    92  	for _, s := range mi.Services {
    93  		iface := s.URL.GetParam(constant.InterfaceKey, "")
    94  		ms := s.URL.Methods
    95  		if len(ms) == 0 {
    96  			candidates = append(candidates, iface)
    97  		} else {
    98  			for _, m := range ms {
    99  				// methods are part of candidates
   100  				candidates = append(candidates, iface+constant.KeySeparator+m)
   101  			}
   102  		}
   103  
   104  		// append URL params if we need it
   105  	}
   106  	sort.Strings(candidates)
   107  
   108  	// it's nearly impossible to be overflow
   109  	res := uint64(0)
   110  	for _, c := range candidates {
   111  		res += uint64(crc32.ChecksumIEEE([]byte(c)))
   112  	}
   113  	mi.Revision = fmt.Sprint(res)
   114  	return mi.Revision
   115  
   116  }
   117  
   118  // nolint
   119  func (mi *MetadataInfo) HasReported() bool {
   120  	return mi.Reported
   121  }
   122  
   123  // nolint
   124  func (mi *MetadataInfo) MarkReported() {
   125  	mi.Reported = true
   126  }
   127  
   128  // nolint
   129  func (mi *MetadataInfo) AddService(service *ServiceInfo) {
   130  	if service == nil {
   131  		return
   132  	}
   133  	mi.Services[service.GetMatchKey()] = service
   134  }
   135  
   136  // nolint
   137  func (mi *MetadataInfo) RemoveService(service *ServiceInfo) {
   138  	if service == nil {
   139  		return
   140  	}
   141  	delete(mi.Services, service.MatchKey)
   142  }
   143  
   144  // ServiceInfo the information of service
   145  type ServiceInfo struct {
   146  	Name     string            `json:"name,omitempty"`
   147  	Group    string            `json:"group,omitempty"`
   148  	Version  string            `json:"version,omitempty"`
   149  	Protocol string            `json:"protocol,omitempty"`
   150  	Path     string            `json:"path,omitempty"`
   151  	Params   map[string]string `json:"params,omitempty"`
   152  
   153  	ServiceKey string `json:"-"`
   154  	MatchKey   string `json:"-"`
   155  	URL        *URL   `json:"-"`
   156  }
   157  
   158  // nolint
   159  func NewServiceInfoWithURL(url *URL) *ServiceInfo {
   160  	service := NewServiceInfo(url.Service(), url.Group(), url.Version(), url.Protocol, url.Path, nil)
   161  	service.URL = url
   162  	// TODO includeKeys load dynamic
   163  	p := make(map[string]string, 8)
   164  	for _, keyInter := range IncludeKeys.Values() {
   165  		key := keyInter.(string)
   166  		value := url.GetParam(key, "")
   167  		if len(value) != 0 {
   168  			p[key] = value
   169  		}
   170  		for _, method := range url.Methods {
   171  			value = url.GetMethodParam(method, key, "")
   172  			if len(value) != 0 {
   173  				p[method+"."+key] = value
   174  			}
   175  		}
   176  	}
   177  	service.Params = p
   178  	return service
   179  }
   180  
   181  // nolint
   182  func NewServiceInfo(name, group, version, protocol, path string, params map[string]string) *ServiceInfo {
   183  	serviceKey := ServiceKey(name, group, version)
   184  	matchKey := MatchKey(serviceKey, protocol)
   185  	return &ServiceInfo{
   186  		Name:       name,
   187  		Group:      group,
   188  		Version:    version,
   189  		Protocol:   protocol,
   190  		Path:       strings.TrimPrefix(path, "/"),
   191  		Params:     params,
   192  		ServiceKey: serviceKey,
   193  		MatchKey:   matchKey,
   194  	}
   195  }
   196  
   197  // nolint
   198  func (si *ServiceInfo) JavaClassName() string {
   199  	return "org.apache.dubbo.metadata.MetadataInfo$ServiceInfo"
   200  }
   201  
   202  // nolint
   203  func (si *ServiceInfo) GetMethods() []string {
   204  	if si.Params[constant.MethodsKey] != "" {
   205  		s := si.Params[constant.MethodsKey]
   206  		return strings.Split(s, ",")
   207  	}
   208  	methods := make([]string, 0, 8)
   209  	for k, _ := range si.Params {
   210  		ms := strings.Index(k, ".")
   211  		if ms > 0 {
   212  			methods = append(methods, k[0:ms])
   213  		}
   214  	}
   215  	return methods
   216  }
   217  
   218  // nolint
   219  func (si *ServiceInfo) GetParams() url.Values {
   220  	v := url.Values{}
   221  	for k, p := range si.Params {
   222  		ms := strings.Index(k, ".")
   223  		if ms > 0 {
   224  			v.Set("methods."+k, p)
   225  		} else {
   226  			v.Set(k, p)
   227  		}
   228  	}
   229  	return v
   230  }
   231  
   232  // nolint
   233  func (si *ServiceInfo) GetMatchKey() string {
   234  	if si.MatchKey != "" {
   235  		return si.MatchKey
   236  	}
   237  	serviceKey := si.GetServiceKey()
   238  	si.MatchKey = MatchKey(serviceKey, si.Protocol)
   239  	return si.MatchKey
   240  }
   241  
   242  // nolint
   243  func (si *ServiceInfo) GetServiceKey() string {
   244  	if si.ServiceKey != "" {
   245  		return si.ServiceKey
   246  	}
   247  	si.ServiceKey = ServiceKey(si.Name, si.Group, si.Version)
   248  	return si.ServiceKey
   249  }