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 }