dubbo.apache.org/dubbo-go/v3@v3.1.1/metadata/report/zookeeper/report.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 zookeeper 19 20 import ( 21 "encoding/json" 22 "strings" 23 ) 24 25 import ( 26 "github.com/dubbogo/go-zookeeper/zk" 27 28 gxset "github.com/dubbogo/gost/container/set" 29 gxzookeeper "github.com/dubbogo/gost/database/kv/zk" 30 "github.com/dubbogo/gost/log/logger" 31 32 perrors "github.com/pkg/errors" 33 ) 34 35 import ( 36 "dubbo.apache.org/dubbo-go/v3/common" 37 "dubbo.apache.org/dubbo-go/v3/common/constant" 38 "dubbo.apache.org/dubbo-go/v3/common/extension" 39 "dubbo.apache.org/dubbo-go/v3/metadata/identifier" 40 "dubbo.apache.org/dubbo-go/v3/metadata/mapping/metadata" 41 "dubbo.apache.org/dubbo-go/v3/metadata/report" 42 "dubbo.apache.org/dubbo-go/v3/metadata/report/factory" 43 "dubbo.apache.org/dubbo-go/v3/registry" 44 "dubbo.apache.org/dubbo-go/v3/remoting/zookeeper" 45 ) 46 47 var emptyStrSlice = make([]string, 0) 48 49 func init() { 50 mf := &zookeeperMetadataReportFactory{} 51 extension.SetMetadataReportFactory("zookeeper", func() factory.MetadataReportFactory { 52 return mf 53 }) 54 } 55 56 // zookeeperMetadataReport is the implementation of 57 // MetadataReport based on zookeeper. 58 type zookeeperMetadataReport struct { 59 client *gxzookeeper.ZookeeperClient 60 rootDir string 61 listener *zookeeper.ZkEventListener 62 cacheListener *CacheListener 63 } 64 65 // GetAppMetadata get metadata info from zookeeper 66 func (m *zookeeperMetadataReport) GetAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier) (*common.MetadataInfo, error) { 67 k := m.rootDir + metadataIdentifier.GetFilePathKey() 68 data, _, err := m.client.GetContent(k) 69 if err != nil { 70 return nil, err 71 } 72 var metadataInfo common.MetadataInfo 73 err = json.Unmarshal(data, &metadataInfo) 74 if err != nil { 75 return nil, err 76 } 77 return &metadataInfo, nil 78 } 79 80 // PublishAppMetadata publish metadata info to zookeeper 81 func (m *zookeeperMetadataReport) PublishAppMetadata(metadataIdentifier *identifier.SubscriberMetadataIdentifier, info *common.MetadataInfo) error { 82 k := m.rootDir + metadataIdentifier.GetFilePathKey() 83 data, err := json.Marshal(info) 84 if err != nil { 85 return err 86 } 87 err = m.client.CreateWithValue(k, data) 88 if perrors.Is(err, zk.ErrNodeExists) { 89 logger.Debugf("Try to create the node data failed. In most cases, it's not a problem. ") 90 return nil 91 } 92 return err 93 } 94 95 // StoreProviderMetadata stores the metadata. 96 func (m *zookeeperMetadataReport) StoreProviderMetadata(providerIdentifier *identifier.MetadataIdentifier, serviceDefinitions string) error { 97 k := m.rootDir + providerIdentifier.GetFilePathKey() 98 err := m.client.CreateWithValue(k, []byte(serviceDefinitions)) 99 if perrors.Is(err, zk.ErrNodeExists) { 100 logger.Debugf("Try to store provider metadata failed. In most cases, it's not a problem. ") 101 return nil 102 } 103 return err 104 } 105 106 // StoreConsumerMetadata stores the metadata. 107 func (m *zookeeperMetadataReport) StoreConsumerMetadata(consumerMetadataIdentifier *identifier.MetadataIdentifier, serviceParameterString string) error { 108 k := m.rootDir + consumerMetadataIdentifier.GetFilePathKey() 109 err := m.client.CreateWithValue(k, []byte(serviceParameterString)) 110 if perrors.Is(err, zk.ErrNodeExists) { 111 logger.Debugf("Try to store consumer metadata failed. In most cases, it's not a problem. ") 112 return nil 113 } 114 return err 115 } 116 117 // SaveServiceMetadata saves the metadata. 118 func (m *zookeeperMetadataReport) SaveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier, url *common.URL) error { 119 k := m.rootDir + metadataIdentifier.GetFilePathKey() 120 return m.client.CreateWithValue(k, []byte(url.String())) 121 } 122 123 // RemoveServiceMetadata removes the metadata. 124 func (m *zookeeperMetadataReport) RemoveServiceMetadata(metadataIdentifier *identifier.ServiceMetadataIdentifier) error { 125 k := m.rootDir + metadataIdentifier.GetFilePathKey() 126 return m.client.Delete(k) 127 } 128 129 // GetExportedURLs gets the urls. 130 func (m *zookeeperMetadataReport) GetExportedURLs(metadataIdentifier *identifier.ServiceMetadataIdentifier) ([]string, error) { 131 k := m.rootDir + metadataIdentifier.GetFilePathKey() 132 v, _, err := m.client.GetContent(k) 133 if err != nil || len(v) == 0 { 134 return emptyStrSlice, err 135 } 136 return []string{string(v)}, nil 137 } 138 139 // SaveSubscribedData saves the urls. 140 func (m *zookeeperMetadataReport) SaveSubscribedData(subscriberMetadataIdentifier *identifier.SubscriberMetadataIdentifier, urls string) error { 141 k := m.rootDir + subscriberMetadataIdentifier.GetFilePathKey() 142 return m.client.CreateWithValue(k, []byte(urls)) 143 } 144 145 // GetSubscribedURLs gets the urls. 146 func (m *zookeeperMetadataReport) GetSubscribedURLs(subscriberMetadataIdentifier *identifier.SubscriberMetadataIdentifier) ([]string, error) { 147 k := m.rootDir + subscriberMetadataIdentifier.GetFilePathKey() 148 v, _, err := m.client.GetContent(k) 149 if err != nil || len(v) == 0 { 150 return emptyStrSlice, err 151 } 152 return []string{string(v)}, nil 153 } 154 155 // GetServiceDefinition gets the service definition. 156 func (m *zookeeperMetadataReport) GetServiceDefinition(metadataIdentifier *identifier.MetadataIdentifier) (string, error) { 157 k := m.rootDir + metadataIdentifier.GetFilePathKey() 158 v, _, err := m.client.GetContent(k) 159 return string(v), err 160 } 161 162 // RegisterServiceAppMapping map the specified Dubbo service interface to current Dubbo app name 163 func (m *zookeeperMetadataReport) RegisterServiceAppMapping(key string, group string, value string) error { 164 path := m.getPath(key, group) 165 v, state, err := m.client.GetContent(path) 166 if err == zk.ErrNoNode { 167 return m.client.CreateWithValue(path, []byte(value)) 168 } else if err != nil { 169 return err 170 } 171 oldValue := string(v) 172 if strings.Contains(oldValue, value) { 173 return nil 174 } 175 value = oldValue + constant.CommaSeparator + value 176 _, err = m.client.SetContent(path, []byte(value), state.Version) 177 return err 178 } 179 180 // GetServiceAppMapping get the app names from the specified Dubbo service interface 181 func (m *zookeeperMetadataReport) GetServiceAppMapping(key string, group string, listener registry.MappingListener) (*gxset.HashSet, error) { 182 path := m.rootDir + group + constant.PathSeparator + key 183 184 // listen to mapping changes first 185 if listener != nil { 186 m.cacheListener.AddListener(path, listener) 187 } 188 189 v, _, err := m.client.GetContent(path) 190 if err != nil { 191 return nil, err 192 } 193 appNames := strings.Split(string(v), constant.CommaSeparator) 194 set := gxset.NewSet() 195 for _, e := range appNames { 196 set.Add(e) 197 } 198 return set, nil 199 } 200 201 // GetConfigKeysByGroup will return all keys with the group 202 func (m *zookeeperMetadataReport) GetConfigKeysByGroup(group string) (*gxset.HashSet, error) { 203 path := m.getPath("", group) 204 result, err := m.client.GetChildren(path) 205 if err != nil { 206 return nil, perrors.WithStack(err) 207 } 208 209 if len(result) == 0 { 210 return nil, perrors.New("could not find keys with group: " + group) 211 } 212 set := gxset.NewSet() 213 for _, e := range result { 214 set.Add(e) 215 } 216 return set, nil 217 } 218 219 func (m *zookeeperMetadataReport) RemoveServiceAppMappingListener(key string, group string) error { 220 return nil 221 } 222 223 func (m *zookeeperMetadataReport) getPath(key string, group string) string { 224 if len(key) == 0 { 225 return m.buildPath(group) 226 } 227 return m.buildPath(group) + constant.PathSeparator + key 228 } 229 230 func (m *zookeeperMetadataReport) buildPath(group string) string { 231 if len(group) == 0 { 232 group = metadata.DefaultGroup 233 } 234 return m.rootDir + group 235 } 236 237 type zookeeperMetadataReportFactory struct{} 238 239 // nolint 240 func (mf *zookeeperMetadataReportFactory) CreateMetadataReport(url *common.URL) report.MetadataReport { 241 client, err := gxzookeeper.NewZookeeperClient( 242 "zookeeperMetadataReport", 243 strings.Split(url.Location, ","), 244 false, 245 gxzookeeper.WithZkTimeOut(url.GetParamDuration(constant.TimeoutKey, "15s")), 246 ) 247 if err != nil { 248 panic(err) 249 } 250 251 rootDir := url.GetParam(constant.MetadataReportGroupKey, "dubbo") 252 if !strings.HasPrefix(rootDir, constant.PathSeparator) { 253 rootDir = constant.PathSeparator + rootDir 254 } 255 if rootDir != constant.PathSeparator { 256 rootDir = rootDir + constant.PathSeparator 257 } 258 259 reporter := &zookeeperMetadataReport{ 260 client: client, 261 rootDir: rootDir, 262 listener: zookeeper.NewZkEventListener(client), 263 } 264 265 reporter.cacheListener = NewCacheListener(rootDir, reporter.listener) 266 reporter.listener.ListenConfigurationEvent(rootDir+constant.PathSeparator+metadata.DefaultGroup, reporter.cacheListener) 267 return reporter 268 }