dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/event/service_revision_customizer.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 event
    19  
    20  import (
    21  	"fmt"
    22  	"hash/crc32"
    23  	"sort"
    24  )
    25  
    26  import (
    27  	"github.com/dubbogo/gost/log/logger"
    28  )
    29  
    30  import (
    31  	"dubbo.apache.org/dubbo-go/v3/common"
    32  	"dubbo.apache.org/dubbo-go/v3/common/constant"
    33  	"dubbo.apache.org/dubbo-go/v3/common/extension"
    34  	"dubbo.apache.org/dubbo-go/v3/metadata/service/local"
    35  	"dubbo.apache.org/dubbo-go/v3/registry"
    36  )
    37  
    38  const defaultRevision = "N/A"
    39  
    40  func init() {
    41  	extension.AddCustomizers(&exportedServicesRevisionMetadataCustomizer{})
    42  	extension.AddCustomizers(&subscribedServicesRevisionMetadataCustomizer{})
    43  }
    44  
    45  type exportedServicesRevisionMetadataCustomizer struct{}
    46  
    47  // GetPriority will return 1 so that it will be invoked in front of user defining Customizer
    48  func (e *exportedServicesRevisionMetadataCustomizer) GetPriority() int {
    49  	return 1
    50  }
    51  
    52  // Customize calculate the revision for exported urls and then put it into instance metadata
    53  func (e *exportedServicesRevisionMetadataCustomizer) Customize(instance registry.ServiceInstance) {
    54  	ms, err := local.GetLocalMetadataService()
    55  	if err != nil {
    56  		logger.Errorf("could not get metadata service", err)
    57  		return
    58  	}
    59  
    60  	urls, err := ms.GetExportedURLs(constant.AnyValue, constant.AnyValue, constant.AnyValue, constant.AnyValue)
    61  	if err != nil {
    62  		logger.Errorf("could not find the exported url", err)
    63  	}
    64  
    65  	revision := resolveRevision(urls)
    66  	if len(revision) == 0 {
    67  		revision = defaultRevision
    68  	}
    69  	instance.GetMetadata()[constant.ExportedServicesRevisionPropertyName] = revision
    70  }
    71  
    72  type subscribedServicesRevisionMetadataCustomizer struct{}
    73  
    74  // GetPriority will return 2 so that it will be invoked in front of user defining Customizer
    75  func (e *subscribedServicesRevisionMetadataCustomizer) GetPriority() int {
    76  	return 2
    77  }
    78  
    79  // Customize calculate the revision for subscribed urls and then put it into instance metadata
    80  func (e *subscribedServicesRevisionMetadataCustomizer) Customize(instance registry.ServiceInstance) {
    81  	ms, err := local.GetLocalMetadataService()
    82  	if err != nil {
    83  		logger.Errorf("could not get metadata service", err)
    84  		return
    85  	}
    86  
    87  	urls, err := ms.GetSubscribedURLs()
    88  	if err != nil {
    89  		logger.Errorf("could not find the subscribed url", err)
    90  	}
    91  
    92  	revision := resolveRevision(urls)
    93  	if len(revision) == 0 {
    94  		revision = defaultRevision
    95  	}
    96  	instance.GetMetadata()[constant.SubscribedServicesRevisionPropertyName] = revision
    97  }
    98  
    99  // resolveRevision is different from Dubbo because golang doesn't support overload
   100  // so that we could use interface + method name as identifier and ignore the method params
   101  // per my understanding, it's enough because Dubbo actually ignore the url params.
   102  // please refer org.apache.dubbo.common.URL#toParameterString(java.lang.String...)
   103  func resolveRevision(urls []*common.URL) string {
   104  	if len(urls) == 0 {
   105  		return "0"
   106  	}
   107  	candidates := make([]string, 0, len(urls))
   108  
   109  	for _, u := range urls {
   110  		sk := u.GetParam(constant.InterfaceKey, "")
   111  
   112  		if len(u.Methods) == 0 {
   113  			candidates = append(candidates, sk)
   114  		} else {
   115  			for _, m := range u.Methods {
   116  				// methods are part of candidates
   117  				candidates = append(candidates, sk+constant.KeySeparator+m)
   118  			}
   119  		}
   120  
   121  		// append url params if we need it
   122  	}
   123  	sort.Strings(candidates)
   124  
   125  	// it's nearly impossible to be overflow
   126  	res := uint64(0)
   127  	for _, c := range candidates {
   128  		res += uint64(crc32.ChecksumIEEE([]byte(c)))
   129  	}
   130  	return fmt.Sprint(res)
   131  }