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  }