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 }