Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📦 NEW: add discover options #752

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions clients/naming_client/discover_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package naming_client

import "github.com/nacos-group/nacos-sdk-go/v2/model"

// 定义DiscoverOptionFunc类型,它是一个函数类型,接收一个discoverOptions指针并对其进行修改
type DiscoverOptionFunc func(*discoverOptions)

// WithGroup 返回一个DiscoverOptionFunc,用来设置发现选项中的group字段
// 参数group: 要设置的组名
func WithGroup(group string) DiscoverOptionFunc {
return func(o *discoverOptions) {
o.group = group
}
}

// WithService 返回一个DiscoverOptionFunc,用来设置发现选项中的service字段
// 参数service: 要设置的服务名
func WithService(service string) DiscoverOptionFunc {
return func(o *discoverOptions) {
o.service = service
}
}

// WithVersion 返回一个DiscoverOptionFunc,用来添加一个版本到发现选项的versions列表中
// 参数version: 要添加的版本号
func WithVersion(version string) DiscoverOptionFunc {
return func(o *discoverOptions) {
if o.versions == nil {
o.versions = []string{}
}
o.versions = append(o.versions, version)
}
}

// WithCluster 返回一个DiscoverOptionFunc,用来添加一个集群名到发现选项的clusters列表中
// 参数cluster: 要添加的集群名
func WithCluster(cluster string) DiscoverOptionFunc {
return func(o *discoverOptions) {
if o.clusters == nil {
o.clusters = []string{}
}
o.clusters = append(o.clusters, cluster)
}
}

// WithChoose 是一个用于设置发现选项中选择函数的 DiscoverOptionFunc 构造函数。
// 参数: choose - 一个实现了 IChooseFunc 接口的选择函数,用于在发现过程中进行选择逻辑的定制。
// 返回值: 返回一个 DiscoverOptionFunc,它是一个函数类型,接受 discoverOptions 指针作为参数,用于配置发现选项。
func WithChoose(choose IChooseFunc) DiscoverOptionFunc {
return func(o *discoverOptions) {
o.choose = choose
}
}

// discoverOptions 定义了发现选项的结构体,包括组名、服务名、集群名和版本号列表
type discoverOptions struct {
group string
service string
clusters []string
versions []string
choose IChooseFunc
}

// CheckMeta 用于检查给定的元数据中的版本信息是否符合预期。
// 参数meta: 一个包含键值对的映射,预期包含一个名为"version"的键。
// 返回值: 返回一个布尔值,表示元数据中的版本是否通过了检查。
func (o *discoverOptions) CheckMeta(meta map[string]string) bool {
// 根据传入的元数据中的版本进行检查
return o.VersionCheck(meta["version"])
}

// VersionCheck 检查给定的版本是否在版本列表中
// 参数ver: 要检查的版本号
// 返回值: 如果给定的版本存在于列表中,则返回true;否则返回false
func (o discoverOptions) VersionCheck(ver string) bool {
if len(o.versions) == 0 {
return true
}
if ver == "" {
return false
}
for _, v := range o.versions {
if v == ver {
return true
}
}
return false
}

// Choose 方法根据给定的实例列表选择一个实例。
// 参数: instances ...model.Instance - 一个或多个 model.Instance 类型的实例。
// 返回值: model.Instance - 选择出的单个实例。
func (o discoverOptions) Choose(instances ...model.Instance) model.Instance {
if o.choose == nil {
return defaultChoose(instances...)
}
return o.choose(instances...)
}

// IChooseFunc 是一个函数类型,用于从多个model.Instance中选择一个。
// 参数instances是可变长度的model.Instance类型切片。
// 返回值是一个model.Instance类型,表示选择的结果。
type IChooseFunc func(instances ...model.Instance) model.Instance

// defaultChoose 是一个默认的选择函数,基于提供的model.Instance实例列表进行选择。
// 参数is是可变长度的model.Instance类型切片。
// 返回值是一个model.Instance类型,表示选择的结果。
func defaultChoose(is ...model.Instance) model.Instance {
return newChooser(is).pick()
}
86 changes: 86 additions & 0 deletions clients/naming_client/discover_options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package naming_client

import (
"testing"

"github.com/nacos-group/nacos-sdk-go/v2/model"
)

func TestWithGroup(t *testing.T) {
o := &discoverOptions{}
WithGroup("testGroup")(o)
if o.group != "testGroup" {
t.Errorf("WithGroup() failed, expected: %s, got: %s", "testGroup", o.group)
}
}

func TestWithService(t *testing.T) {
o := &discoverOptions{}
WithService("testService")(o)
if o.service != "testService" {
t.Errorf("WithService() failed, expected: %s, got: %s", "testService", o.service)
}
}

func TestWithVersion(t *testing.T) {
o := &discoverOptions{}
WithVersion("v1")(o)
if len(o.versions) != 1 || o.versions[0] != "v1" {
t.Errorf("WithVersion() failed, expected: %s, got: %v", "v1", o.versions)
}
}

func TestWithCluster(t *testing.T) {
o := &discoverOptions{}
WithCluster("testCluster")(o)
if len(o.clusters) != 1 || o.clusters[0] != "testCluster" {
t.Errorf("WithCluster() failed, expected: %s, got: %v", "testCluster", o.clusters)
}
}

func TestWithChoose(t *testing.T) {
o := &discoverOptions{}
choose := func(instances ...model.Instance) model.Instance {
return instances[0]
}
WithChoose(choose)(o)
if o.choose == nil {
t.Errorf("WithChoose() failed, expected: not nil, got: nil")
}
}

func TestCheckMeta(t *testing.T) {
o := &discoverOptions{
versions: []string{"v1", "v2"},
}
if !o.CheckMeta(map[string]string{"version": "v1"}) {
t.Errorf("CheckMeta() failed, expected: true, got: false")
}
if o.CheckMeta(map[string]string{"version": "v3"}) {
t.Errorf("CheckMeta() failed, expected: false, got: true")
}
}

func TestVersionCheck(t *testing.T) {
o := discoverOptions{
versions: []string{"v1", "v2"},
}
if !o.VersionCheck("v1") {
t.Errorf("VersionCheck() failed, expected: true, got: false")
}
if o.VersionCheck("v3") {
t.Errorf("VersionCheck() failed, expected: false, got: true")
}
}

func TestChoose(t *testing.T) {
o := discoverOptions{}
instances := []model.Instance{
{InstanceId: "1", Weight: 1, Metadata: map[string]string{"version": "v1"}},
{InstanceId: "2", Weight: 2, Metadata: map[string]string{"version": "v2"}},
}
selectedInstance := o.Choose(instances...)
if selectedInstance.InstanceId == "" {
t.Errorf("Choose() failed, expected: not nil, got: nil")
}
}
59 changes: 59 additions & 0 deletions clients/naming_client/naming_client_discover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package naming_client

import (
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)

// Discover 用于获取服务实例列表。
// options: 可选配置项函数的集合,用于定制发现行为。
// 返回值: 返回符合筛选条件的服务实例列表和可能发生的错误。
func (sc *NamingClient) Discover(options ...DiscoverOptionFunc) ([]model.Instance, error) {
opts := &discoverOptions{}
for _, opt := range options {
opt(opts)
}
return sc.discover(opts)
}

// DiscoverOne 用于获取单个服务实例。
// options: 可选配置项函数的集合,用于定制发现行为。
// 返回值: 返回符合条件的单个服务实例和可能发生的错误。如果没有找到符合条件的实例,将返回一个空的实例和错误信息。
func (sc *NamingClient) DiscoverOne(options ...DiscoverOptionFunc) (model.Instance, error) {
opts := &discoverOptions{}
for _, opt := range options {
opt(opts)
}
instances, err := sc.discover(opts)
if err != nil {
return model.Instance{}, err
}
instance := opts.Choose(instances...)
return instance, nil
}

// discover 是Discover和DiscoverOne方法的内部实现。
// opts: 包含所有经过DiscoverOptionFunc处理的配置选项。
// 返回值: 返回过滤后的服务实例列表和可能发生的错误。
func (sc *NamingClient) discover(opts *discoverOptions) ([]model.Instance, error) {
// 从Nacos服务注册中心选择符合条件的实例
instances, err := sc.SelectInstances(vo.SelectInstancesParam{
GroupName: opts.group,
ServiceName: opts.service,
Clusters: opts.clusters,
HealthyOnly: true,
})
if err != nil {
return nil, err
}

// 筛选出满足Metadata条件的实例
newInstances := []model.Instance{}
for _, instance := range instances {
if !opts.CheckMeta(instance.Metadata) {
continue
}
newInstances = append(newInstances, instance)
}
return newInstances, nil
}
Loading