dubbo.apache.org/dubbo-go/v3@v3.1.1/config_center/nacos/impl.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 nacos 19 20 import ( 21 "strings" 22 "sync" 23 ) 24 25 import ( 26 gxset "github.com/dubbogo/gost/container/set" 27 nacosClient "github.com/dubbogo/gost/database/kv/nacos" 28 "github.com/dubbogo/gost/log/logger" 29 30 constant2 "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 31 "github.com/nacos-group/nacos-sdk-go/v2/vo" 32 33 perrors "github.com/pkg/errors" 34 ) 35 36 import ( 37 "dubbo.apache.org/dubbo-go/v3/common" 38 "dubbo.apache.org/dubbo-go/v3/common/constant" 39 "dubbo.apache.org/dubbo-go/v3/config_center" 40 "dubbo.apache.org/dubbo-go/v3/config_center/parser" 41 ) 42 43 const ( 44 nacosClientName = "nacos config_center" 45 // the number is a little big tricky 46 // it will be used in query which looks up all keys with the target group 47 // now, one key represents one application 48 // so only a group has more than 9999 applications will failed 49 maxKeysNum = 9999 50 ) 51 52 // nacosDynamicConfiguration is the implementation of DynamicConfiguration based on nacos 53 type nacosDynamicConfiguration struct { 54 config_center.BaseDynamicConfiguration 55 url *common.URL 56 rootPath string 57 wg sync.WaitGroup 58 cltLock sync.Mutex 59 done chan struct{} 60 client *nacosClient.NacosConfigClient 61 keyListeners sync.Map 62 parser parser.ConfigurationParser 63 } 64 65 func newNacosDynamicConfiguration(url *common.URL) (*nacosDynamicConfiguration, error) { 66 url.SetParam(constant.NacosNamespaceID, url.GetParam(constant.ConfigNamespaceKey, "")) 67 url.SetParam(constant.NacosUsername, url.Username) 68 url.SetParam(constant.NacosPassword, url.Password) 69 url.SetParam(constant.NacosAccessKey, url.GetParam(constant.ConfigAccessKey, "")) 70 url.SetParam(constant.NacosSecretKey, url.GetParam(constant.ConfigSecretKey, "")) 71 url.SetParam(constant.NacosTimeout, url.GetParam(constant.ConfigTimeoutKey, "")) 72 url.SetParam(constant.NacosGroupKey, url.GetParam(constant.ConfigGroupKey, constant2.DEFAULT_GROUP)) 73 c := &nacosDynamicConfiguration{ 74 url: url, 75 done: make(chan struct{}), 76 } 77 c.GetURL() 78 logger.Infof("[Nacos ConfigCenter] New Nacos ConfigCenter with Configuration: %+v, url = %+v", c, c.GetURL()) 79 err := ValidateNacosClient(c) 80 if err != nil { 81 logger.Errorf("nacos configClient start error ,error message is %v", err) 82 return nil, err 83 } 84 c.wg.Add(1) 85 go HandleClientRestart(c) 86 return c, err 87 } 88 89 // AddListener Add listener 90 func (n *nacosDynamicConfiguration) AddListener(key string, listener config_center.ConfigurationListener, opions ...config_center.Option) { 91 n.addListener(key, listener) 92 } 93 94 // RemoveListener Remove listener 95 func (n *nacosDynamicConfiguration) RemoveListener(key string, listener config_center.ConfigurationListener, opions ...config_center.Option) { 96 n.removeListener(key, listener) 97 } 98 99 // GetProperties nacos distinguishes configuration files based on group and dataId. defalut group = "dubbo" and dataId = key 100 func (n *nacosDynamicConfiguration) GetProperties(key string, opts ...config_center.Option) (string, error) { 101 return n.GetRule(key, opts...) 102 } 103 104 // GetInternalProperty Get properties value by key 105 func (n *nacosDynamicConfiguration) GetInternalProperty(key string, opts ...config_center.Option) (string, error) { 106 return n.GetProperties(key, opts...) 107 } 108 109 // PublishConfig will publish the config with the (key, group, value) pair 110 func (n *nacosDynamicConfiguration) PublishConfig(key string, group string, value string) error { 111 group = n.resolvedGroup(group) 112 ok, err := n.client.Client().PublishConfig(vo.ConfigParam{ 113 DataId: key, 114 Group: group, 115 Content: value, 116 }) 117 if err != nil { 118 return perrors.WithStack(err) 119 } 120 if !ok { 121 return perrors.New("publish config to Nocos failed") 122 } 123 return nil 124 } 125 126 // RemoveConfig will remove the config with the (key, group) pair 127 func (n *nacosDynamicConfiguration) RemoveConfig(key string, group string) error { 128 group = n.resolvedGroup(group) 129 ok, err := n.client.Client().DeleteConfig(vo.ConfigParam{ 130 DataId: key, 131 Group: group, 132 }) 133 if err != nil { 134 return perrors.WithStack(err) 135 } 136 if !ok { 137 return perrors.New("remove config from Nacos failed") 138 } 139 return nil 140 } 141 142 // GetConfigKeysByGroup will return all keys with the group 143 func (n *nacosDynamicConfiguration) GetConfigKeysByGroup(group string) (*gxset.HashSet, error) { 144 group = n.resolvedGroup(group) 145 page, err := n.client.Client().SearchConfig(vo.SearchConfigParam{ 146 Search: "accurate", 147 Group: group, 148 PageNo: 1, 149 // actually it's impossible for user to create 9999 application under one group 150 PageSize: maxKeysNum, 151 }) 152 153 result := gxset.NewSet() 154 if err != nil { 155 return result, perrors.WithMessage(err, "can not find the configClient config") 156 } 157 for _, itm := range page.PageItems { 158 result.Add(itm.DataId) 159 } 160 return result, nil 161 } 162 163 // GetRule Get router rule 164 func (n *nacosDynamicConfiguration) GetRule(key string, opts ...config_center.Option) (string, error) { 165 tmpOpts := &config_center.Options{} 166 for _, opt := range opts { 167 opt(tmpOpts) 168 } 169 resolvedGroup := n.resolvedGroup(tmpOpts.Group) 170 content, err := n.client.Client().GetConfig(vo.ConfigParam{ 171 DataId: key, 172 Group: resolvedGroup, 173 }) 174 if err != nil { 175 return "", perrors.WithStack(err) 176 } else { 177 return content, nil 178 } 179 } 180 181 // Parser Get Parser 182 func (n *nacosDynamicConfiguration) Parser() parser.ConfigurationParser { 183 return n.parser 184 } 185 186 // SetParser Set Parser 187 func (n *nacosDynamicConfiguration) SetParser(p parser.ConfigurationParser) { 188 n.parser = p 189 } 190 191 // NacosClient Get Nacos Client 192 func (n *nacosDynamicConfiguration) NacosClient() *nacosClient.NacosConfigClient { 193 return n.client 194 } 195 196 // SetNacosClient Set Nacos Client 197 func (n *nacosDynamicConfiguration) SetNacosClient(client *nacosClient.NacosConfigClient) { 198 n.cltLock.Lock() 199 n.client = client 200 n.cltLock.Unlock() 201 } 202 203 // WaitGroup for wait group control, zk configClient listener & zk configClient container 204 func (n *nacosDynamicConfiguration) WaitGroup() *sync.WaitGroup { 205 return &n.wg 206 } 207 208 // GetDone For nacos configClient control RestartCallBack() bool 209 func (n *nacosDynamicConfiguration) GetDone() chan struct{} { 210 return n.done 211 } 212 213 // GetURL Get URL 214 func (n *nacosDynamicConfiguration) GetURL() *common.URL { 215 return n.url 216 } 217 218 // Destroy Destroy configuration instance 219 func (n *nacosDynamicConfiguration) Destroy() { 220 close(n.done) 221 n.wg.Wait() 222 n.closeConfigs() 223 } 224 225 // resolvedGroup will regular the group. Now, it will replace the '/' with '-'. 226 // '/' is a special character for nacos 227 func (n *nacosDynamicConfiguration) resolvedGroup(group string) string { 228 if len(group) <= 0 { 229 group = n.url.GetParam(constant.NacosGroupKey, constant2.DEFAULT_GROUP) 230 return group 231 } 232 return strings.ReplaceAll(group, "/", "-") 233 } 234 235 // IsAvailable Get available status 236 func (n *nacosDynamicConfiguration) IsAvailable() bool { 237 select { 238 case <-n.done: 239 return false 240 default: 241 return true 242 } 243 } 244 245 func (n *nacosDynamicConfiguration) closeConfigs() { 246 // Close the old configClient first to close the tmp node 247 n.client.Close() 248 logger.Infof("begin to close provider n configClient") 249 }