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  }