From 39f5bfeebb1f2179de0129985eb219a0ff3a7efa Mon Sep 17 00:00:00 2001
From: LaurenceLiZhixin <382673304@qq.com>
Date: Tue, 26 Jan 2021 16:51:16 +0800
Subject: [PATCH] feat: add config api

---
 config/config_api.go      | 471 ++++++++++++++++++++++++++++++++++++++
 config/config_api_test.go | 158 +++++++++++++
 2 files changed, 629 insertions(+)
 create mode 100644 config/config_api.go
 create mode 100644 config/config_api_test.go

diff --git a/config/config_api.go b/config/config_api.go
new file mode 100644
index 000000000..15db1d80d
--- /dev/null
+++ b/config/config_api.go
@@ -0,0 +1,471 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package config
+
+import (
+	"context"
+	"time"
+)
+
+//////////////////////////////////// default registry config
+const defaultZKAddr = "127.0.0.1:2181"
+const defaultConsulAddr = "127.0.0.1:8500"
+const defaultNacosAddr = "127.0.0.1:8848"
+const defaultRegistryTimeout = "3s"
+
+func NewDefaultRegistryConfig(protocol string) *RegistryConfig {
+	switch protocol {
+	case "zookeeper":
+		return &RegistryConfig{
+			Protocol:   protocol,
+			Address:    defaultZKAddr,
+			TimeoutStr: defaultRegistryTimeout,
+		}
+	case "consul":
+		return &RegistryConfig{
+			Protocol:   protocol,
+			Address:    defaultConsulAddr,
+			TimeoutStr: defaultRegistryTimeout,
+		}
+	case "nacos":
+		return &RegistryConfig{
+			Protocol:   protocol,
+			Address:    defaultNacosAddr,
+			TimeoutStr: defaultRegistryTimeout,
+		}
+	default:
+		return &RegistryConfig{
+			Protocol: protocol,
+		}
+	}
+}
+
+///////////////////////////////////// registry config api
+type RegistryConfigOpt func(config *RegistryConfig) *RegistryConfig
+
+func NewRegistryConfig(opts ...RegistryConfigOpt) *RegistryConfig {
+	newRegistryConfig := NewDefaultRegistryConfig("none")
+	for _, v := range opts {
+		newRegistryConfig = v(newRegistryConfig)
+	}
+	return newRegistryConfig
+}
+
+func WithRegistryProtocol(regProtocol string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Protocol = regProtocol
+		return config
+	}
+}
+
+func WithRegistryAddress(addr string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Address = addr
+		return config
+	}
+}
+
+func WithRegistryTimeOut(timeout string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.TimeoutStr = timeout
+		return config
+	}
+}
+
+func WithRegistryGroup(group string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Group = group
+		return config
+	}
+}
+
+func WithRegistryTTL(ttl string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.TTL = ttl
+		return config
+	}
+}
+
+func WithRegistryUserName(userName string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Username = userName
+		return config
+	}
+}
+
+func WithRegistryPassword(psw string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Password = psw
+		return config
+	}
+}
+
+func WithRegistrySimplified(simplified bool) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Simplified = simplified
+		return config
+	}
+}
+
+func WithRegistryPreferred(preferred bool) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Preferred = preferred
+		return config
+	}
+}
+
+func WithRegistryWeight(weight int64) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Weight = weight
+		return config
+	}
+}
+
+func WithRegistryParams(params map[string]string) RegistryConfigOpt {
+	return func(config *RegistryConfig) *RegistryConfig {
+		config.Params = params
+		return config
+	}
+}
+
+///////////////////////////////////// consumer config api
+type ConsumerConfigOpt func(config *ConsumerConfig) *ConsumerConfig
+
+func NewDefaultConsumerConfig() *ConsumerConfig {
+	check := true
+	newConsumerConfig := &ConsumerConfig{
+		BaseConfig:     BaseConfig{},
+		Registries:     make(map[string]*RegistryConfig, 8),
+		References:     make(map[string]*ReferenceConfig, 8),
+		ConnectTimeout: 3 * time.Second,
+		RequestTimeout: 3 * time.Second,
+		Check:          &check,
+	}
+	return newConsumerConfig
+}
+
+func NewConsumerConfig(opts ...ConsumerConfigOpt) *ConsumerConfig {
+	newConfig := NewDefaultConsumerConfig()
+	for _, v := range opts {
+		v(newConfig)
+	}
+	return newConfig
+}
+func WithConsumerAppConfig(appConfig *ApplicationConfig) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		config.ApplicationConfig = appConfig
+		return config
+	}
+}
+
+func WithConsumerRegistryConfig(registryKey string, regConfig *RegistryConfig) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		config.Registries[registryKey] = regConfig
+		return config
+	}
+}
+
+func WithConsumerReferenceConfig(referenceKey string, refConfig *ReferenceConfig) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		config.References[referenceKey] = refConfig
+		return config
+	}
+}
+
+func WithConsumerConnTimeout(timeout time.Duration) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		config.ConnectTimeout = timeout
+		return config
+	}
+}
+
+func WithConsumerRequestTimeout(timeout time.Duration) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		config.RequestTimeout = timeout
+		return config
+	}
+}
+
+func WithConsumerConfigCenterConfig(configCenterConfig *ConfigCenterConfig) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		config.ConfigCenterConfig = configCenterConfig
+		return config
+	}
+}
+
+func WithConsumerConfigCheck(check bool) ConsumerConfigOpt {
+	return func(config *ConsumerConfig) *ConsumerConfig {
+		*config.Check = check
+		return config
+	}
+}
+
+//////////////////////////////////// reference config api
+type ReferenceConfigOpt func(config *ReferenceConfig) *ReferenceConfig
+
+func NewDefaultReferenceConfig() *ReferenceConfig {
+	newReferenceConfig := NewReferenceConfig("", context.Background())
+	newReferenceConfig.Methods = make([]*MethodConfig, 0, 8)
+	newReferenceConfig.Params = make(map[string]string, 8)
+	return newReferenceConfig
+}
+
+func NewReferenceConfigByAPI(opts ...ReferenceConfigOpt) *ReferenceConfig {
+	newreferenceConfig := NewDefaultReferenceConfig()
+	for _, v := range opts {
+		v(newreferenceConfig)
+	}
+	return newreferenceConfig
+}
+
+func WithReferenceRegistry(registry string) ReferenceConfigOpt {
+	return func(config *ReferenceConfig) *ReferenceConfig {
+		config.Registry = registry
+		return config
+	}
+}
+func WithReferenceProtocol(protocol string) ReferenceConfigOpt {
+	return func(config *ReferenceConfig) *ReferenceConfig {
+		config.Protocol = protocol
+		return config
+	}
+}
+func WithReferenceInterface(interfaceName string) ReferenceConfigOpt {
+	return func(config *ReferenceConfig) *ReferenceConfig {
+		config.InterfaceName = interfaceName
+		return config
+	}
+}
+func WithReferenceCluster(cluster string) ReferenceConfigOpt {
+	return func(config *ReferenceConfig) *ReferenceConfig {
+		config.Cluster = cluster
+		return config
+	}
+}
+func WithReferenceMethod(methodName, retries, lb string) ReferenceConfigOpt {
+	return func(config *ReferenceConfig) *ReferenceConfig {
+		config.Methods = append(config.Methods, &MethodConfig{
+			Name:        methodName,
+			Retries:     retries,
+			LoadBalance: lb,
+		})
+		return config
+	}
+}
+
+///////////////////////////////////// provider config api
+type ProviderConfigOpt func(config *ProviderConfig) *ProviderConfig
+
+func NewDefaultProviderConfig() *ProviderConfig {
+	newConsumerConfig := &ProviderConfig{
+		BaseConfig: BaseConfig{
+			ApplicationConfig: &ApplicationConfig{
+				Name:         "dubbo",
+				Module:       "module",
+				Organization: "dubbo_org",
+				Owner:        "dubbo",
+			},
+		},
+		Services:   make(map[string]*ServiceConfig),
+		Registries: make(map[string]*RegistryConfig, 8),
+		Protocols:  make(map[string]*ProtocolConfig, 8),
+	}
+	return newConsumerConfig
+}
+
+func NewProviderConfig(opts ...ProviderConfigOpt) *ProviderConfig {
+	newConfig := NewDefaultProviderConfig()
+	for _, v := range opts {
+		v(newConfig)
+	}
+	return newConfig
+}
+
+func WithPrividerRegistryConfig(regConfig *RegistryConfig) ProviderConfigOpt {
+	return func(config *ProviderConfig) *ProviderConfig {
+		config.Registries[regConfig.Protocol] = regConfig
+		return config
+	}
+}
+
+func WithProviderAppConfig(appConfig *ApplicationConfig) ProviderConfigOpt {
+	return func(config *ProviderConfig) *ProviderConfig {
+		config.ApplicationConfig = appConfig
+		return config
+	}
+}
+
+func WithProviderServices(serviceName string, serviceConfig *ServiceConfig) ProviderConfigOpt {
+	return func(config *ProviderConfig) *ProviderConfig {
+		config.Services[serviceName] = serviceConfig
+		return config
+	}
+}
+
+func WithProviderProtocol(protocolKey, protocol, port string) ProviderConfigOpt {
+	return func(config *ProviderConfig) *ProviderConfig {
+		config.Protocols[protocolKey] = &ProtocolConfig{
+			Name: protocol,
+			Port: port,
+		}
+		return config
+	}
+}
+
+func WithProviderRegistry(registryKey string, registryConfig *RegistryConfig) ProviderConfigOpt {
+	return func(config *ProviderConfig) *ProviderConfig {
+		config.Registries[registryKey] = registryConfig
+		return config
+	}
+}
+
+/////////////////////////////////////// service config api
+type ServiceConfigOpt func(config *ServiceConfig) *ServiceConfig
+
+func NewDefaultServiceConfig() *ServiceConfig {
+	newServiceConfig := NewServiceConfig("", context.Background())
+	newServiceConfig.Params = make(map[string]string)
+	newServiceConfig.Methods = make([]*MethodConfig, 0, 8)
+	return newServiceConfig
+}
+
+// NewServiceConfigByAPI is named as api, because there is NewServiceConfig func already declared
+func NewServiceConfigByAPI(opts ...ServiceConfigOpt) *ServiceConfig {
+	defaultServiceConfig := NewDefaultServiceConfig()
+	for _, v := range opts {
+		v(defaultServiceConfig)
+	}
+	return defaultServiceConfig
+}
+
+func WithServiceRegistry(registry string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.Registry = registry
+		return config
+	}
+}
+
+func WithServiceProtocol(protocol string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.Protocol = protocol
+		return config
+	}
+}
+func WithServiceInterface(interfaceName string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.InterfaceName = interfaceName
+		return config
+	}
+}
+func WithServiceLoadBalance(lb string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.Loadbalance = lb
+		return config
+	}
+}
+
+func WithServiceWarmUpTime(warmUp string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.Warmup = warmUp
+		return config
+	}
+}
+
+func WithServiceCluster(cluster string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.Cluster = cluster
+		return config
+	}
+}
+
+func WithServiceMethod(name, retries, lb string) ServiceConfigOpt {
+	return func(config *ServiceConfig) *ServiceConfig {
+		config.Methods = append(config.Methods, &MethodConfig{
+			Name:        name,
+			Retries:     retries,
+			LoadBalance: lb,
+		})
+		return config
+	}
+}
+
+///////////////////////////////////////// Application config api
+type ApplicationConfigOpt func(config *ApplicationConfig) *ApplicationConfig
+
+func NewDefaultApplicationConfig() *ApplicationConfig {
+	newAppConfig := &ApplicationConfig{
+		Name:         "dubbo.io",
+		Module:       "sample",
+		Organization: "dubbo.io",
+		Owner:        "dubbogo",
+		Version:      "0.0.1",
+		Environment:  "dev",
+	}
+	return newAppConfig
+}
+
+// NewApplicationConfig is named as api, because there is NewServiceConfig func already declared
+func NewApplicationConfig(opts ...ApplicationConfigOpt) *ApplicationConfig {
+	defaultServiceConfig := NewDefaultApplicationConfig()
+	for _, v := range opts {
+		v(defaultServiceConfig)
+	}
+	return defaultServiceConfig
+}
+
+func WithAppName(name string) ApplicationConfigOpt {
+	return func(config *ApplicationConfig) *ApplicationConfig {
+		config.Name = name
+		return config
+	}
+}
+
+func WithAppModule(module string) ApplicationConfigOpt {
+	return func(config *ApplicationConfig) *ApplicationConfig {
+		config.Module = module
+		return config
+	}
+}
+
+func WithAppOrganization(org string) ApplicationConfigOpt {
+	return func(config *ApplicationConfig) *ApplicationConfig {
+		config.Organization = org
+		return config
+	}
+}
+
+func WithAppOwner(owner string) ApplicationConfigOpt {
+	return func(config *ApplicationConfig) *ApplicationConfig {
+		config.Owner = owner
+		return config
+	}
+}
+
+func WithAppVersion(version string) ApplicationConfigOpt {
+	return func(config *ApplicationConfig) *ApplicationConfig {
+		config.Version = version
+		return config
+	}
+}
+
+func WithAppEnvironment(env string) ApplicationConfigOpt {
+	return func(config *ApplicationConfig) *ApplicationConfig {
+		config.Environment = env
+		return config
+	}
+}
diff --git a/config/config_api_test.go b/config/config_api_test.go
new file mode 100644
index 000000000..5e6d5f529
--- /dev/null
+++ b/config/config_api_test.go
@@ -0,0 +1,158 @@
+package config
+
+import (
+	"github.com/stretchr/testify/assert"
+	"strconv"
+	"testing"
+	"time"
+)
+
+func TestNewDefaultServiceConfig(t *testing.T) {
+	serviceConfig := NewServiceConfigByAPI(
+		WithServiceCluster("test-cluster"),
+		WithServiceInterface("test-interface"),
+		WithServiceLoadBalance("test-loadbalance"),
+		WithServiceMethod("test-method1", "test-retries1", "test-lb1"),
+		WithServiceMethod("test-method2", "test-retries2", "test-lb2"),
+		WithServiceMethod("test-method3", "test-retries3", "test-lb3"),
+		WithServiceProtocol("test-protocol"),
+		WithServiceRegistry("test-registry"),
+		WithServiceWarmUpTime("test-warmup"),
+	)
+	assert.Equal(t, serviceConfig.Cluster, "test-cluster")
+	assert.Equal(t, serviceConfig.InterfaceName, "test-interface")
+	assert.Equal(t, serviceConfig.Loadbalance, "test-loadbalance")
+	for i, v := range serviceConfig.Methods {
+		backFix := strconv.Itoa(i + 1)
+		assert.Equal(t, v.Name, "test-method"+backFix)
+		assert.Equal(t, v.Retries, "test-retries"+backFix)
+		assert.Equal(t, v.LoadBalance, "test-lb"+backFix)
+	}
+	assert.Equal(t, serviceConfig.Protocol, "test-protocol")
+	assert.Equal(t, serviceConfig.Registry, "test-registry")
+	assert.Equal(t, serviceConfig.Warmup, "test-warmup")
+}
+
+func TestNewReferenceConfigByAPI(t *testing.T) {
+	refConfig := NewReferenceConfigByAPI(
+		WithReferenceCluster("test-cluster"),
+		WithReferenceInterface("test-interface"),
+		WithReferenceMethod("test-method1", "test-retries1", "test-lb1"),
+		WithReferenceMethod("test-method2", "test-retries2", "test-lb2"),
+		WithReferenceMethod("test-method3", "test-retries3", "test-lb3"),
+		WithReferenceProtocol("test-protocol"),
+		WithReferenceRegistry("test-registry"),
+	)
+	assert.Equal(t, refConfig.Cluster, "test-cluster")
+	assert.Equal(t, refConfig.InterfaceName, "test-interface")
+	for i, v := range refConfig.Methods {
+		backFix := strconv.Itoa(i + 1)
+		assert.Equal(t, v.Name, "test-method"+backFix)
+		assert.Equal(t, v.Retries, "test-retries"+backFix)
+		assert.Equal(t, v.LoadBalance, "test-lb"+backFix)
+	}
+	assert.Equal(t, refConfig.Protocol, "test-protocol")
+	assert.Equal(t, refConfig.Registry, "test-registry")
+}
+
+func TestNewRegistryConfig(t *testing.T) {
+	regConfig := NewRegistryConfig(
+		WithRegistryTimeOut("test-timeout"),
+		WithRegistryProtocol("test-protocol"),
+		WithRegistryGroup("test-group"),
+		WithRegistryAddress("test-address"),
+		WithRegistrySimplified(true),
+		WithRegistryUserName("test-username"),
+		WithRegistryPassword("test-password"),
+	)
+	assert.Equal(t, regConfig.TimeoutStr, "test-timeout")
+	assert.Equal(t, regConfig.Protocol, "test-protocol")
+	assert.Equal(t, regConfig.Group, "test-group")
+	assert.Equal(t, regConfig.Address, "test-address")
+	assert.Equal(t, regConfig.Simplified, true)
+	assert.Equal(t, regConfig.Username, "test-username")
+	assert.Equal(t, regConfig.Password, "test-password")
+}
+
+func TestNewConsumerConfig(t *testing.T) {
+	referConfig := NewReferenceConfigByAPI(
+		WithReferenceCluster("test-cluster"),
+		WithReferenceInterface("test-interface"),
+		WithReferenceMethod("test-method1", "test-retries1", "test-lb1"),
+		WithReferenceMethod("test-method2", "test-retries2", "test-lb2"),
+		WithReferenceMethod("test-method3", "test-retries3", "test-lb3"),
+		WithReferenceProtocol("test-protocol"),
+		WithReferenceRegistry("test-registry"),
+	)
+	defaultZKRegistry := NewDefaultRegistryConfig("zookeeper")
+	assert.Equal(t, defaultZKRegistry.Address, defaultZKAddr)
+	assert.Equal(t, defaultZKRegistry.Protocol, "zookeeper")
+	assert.Equal(t, defaultZKRegistry.TimeoutStr, defaultRegistryTimeout)
+
+	consumerConfig := NewConsumerConfig(
+		WithConsumerConfigCheck(true),
+		WithConsumerConnTimeout(time.Minute),
+		WithConsumerRequestTimeout(time.Hour),
+		WithConsumerReferenceConfig("UserProvider", referConfig),
+		WithConsumerRegistryConfig("demoZK", defaultZKRegistry),
+	)
+
+	assert.Equal(t, *consumerConfig.Check, true)
+	assert.Equal(t, consumerConfig.ConnectTimeout, time.Minute)
+	assert.Equal(t, consumerConfig.RequestTimeout, time.Hour)
+	assert.Equal(t, consumerConfig.Registries["demoZK"], defaultZKRegistry)
+	assert.Equal(t, consumerConfig.References["UserProvider"], referConfig)
+}
+
+func TestNewProviderConfig(t *testing.T) {
+	serviceConfig := NewServiceConfigByAPI(
+		WithServiceCluster("test-cluster"),
+		WithServiceInterface("test-interface"),
+		WithServiceLoadBalance("test-loadbalance"),
+		WithServiceMethod("test-method1", "test-retries1", "test-lb1"),
+		WithServiceMethod("test-method2", "test-retries2", "test-lb2"),
+		WithServiceMethod("test-method3", "test-retries3", "test-lb3"),
+		WithServiceProtocol("test-protocol"),
+		WithServiceRegistry("test-registry"),
+		WithServiceWarmUpTime("test-warmup"),
+	)
+
+	defaultConsulRegistry := NewDefaultRegistryConfig("consul")
+	assert.Equal(t, defaultConsulRegistry.Address, defaultConsulAddr)
+	assert.Equal(t, defaultConsulRegistry.Protocol, "consul")
+	assert.Equal(t, defaultConsulRegistry.TimeoutStr, defaultRegistryTimeout)
+
+	defaultNacosRegistry := NewDefaultRegistryConfig("nacos")
+	assert.Equal(t, defaultNacosRegistry.Address, defaultNacosAddr)
+	assert.Equal(t, defaultNacosRegistry.Protocol, "nacos")
+	assert.Equal(t, defaultNacosRegistry.TimeoutStr, defaultRegistryTimeout)
+
+	providerConfig := NewProviderConfig(
+		WithProviderServices("UserProvider", serviceConfig),
+		WithProviderProtocol("dubbo", "dubbo", "20000"),
+		WithProviderRegistry("demoConsul", defaultConsulRegistry),
+		WithProviderRegistry("demoNacos", defaultNacosRegistry),
+	)
+
+	assert.NotNil(t, providerConfig.Services)
+	for k, v := range providerConfig.Services {
+		assert.Equal(t, k, "UserProvider")
+		assert.Equal(t, v, serviceConfig)
+	}
+	assert.NotNil(t, providerConfig.Registries)
+	i := 0
+	for k, v := range providerConfig.Registries {
+		if i == 0 {
+			assert.Equal(t, k, "demoConsul")
+			assert.Equal(t, v, defaultConsulRegistry)
+			i++
+		} else {
+			assert.Equal(t, k, "demoNacos")
+			assert.Equal(t, v, defaultNacosRegistry)
+		}
+	}
+
+	assert.NotNil(t, providerConfig.Protocols)
+	assert.Equal(t, providerConfig.Protocols["dubbo"].Name, "dubbo")
+	assert.Equal(t, providerConfig.Protocols["dubbo"].Port, "20000")
+}
-- 
GitLab