configcenter/nacos_load.go (109 lines of code) (raw):
/*
* 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 configcenter
import (
"sync"
)
import (
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/clients/config_client"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/vo"
"github.com/pkg/errors"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/logger"
"github.com/apache/dubbo-go-pixiu/pkg/model"
)
// Constants for configuration keys.
const (
KeyDataId = "dataId"
KeyGroup = "group"
KeyContent = "content"
KeyTag = "tag"
KeyAppName = "appName"
KeyTenant = "tenant"
)
// Constants for Nacos configuration.
const (
DataId = "pixiu.yaml"
Group = "DEFAULT_GROUP"
Namespace = "dubbo-go-pixiu"
IpAddr = "localhost"
ContextPath = "/nacos"
Port = 8848
Scheme = "http"
)
// NacosConfig represents the Nacos configuration client and its state.
type NacosConfig struct {
client config_client.IConfigClient
remoteConfig *model.Bootstrap
mu sync.Mutex
}
// NewNacosConfig creates a new NacosConfig instance.
// It returns an error if no Nacos server is configured or if the client cannot be created.
func NewNacosConfig(boot *model.Bootstrap) (ConfigClient, error) {
if len(boot.Nacos.ServerConfigs) == 0 {
return nil, errors.New("no Nacos server configured")
}
nacosClient, err := getNacosConfigClient(boot)
if err != nil {
return nil, err
}
return &NacosConfig{
client: nacosClient,
}, nil
}
// getNacosConfigClient initializes and returns a Nacos config client.
func getNacosConfigClient(boot *model.Bootstrap) (config_client.IConfigClient, error) {
var serverConfigs []constant.ServerConfig
for _, serverConfig := range boot.Nacos.ServerConfigs {
serverConfigs = append(serverConfigs, constant.ServerConfig{
Port: serverConfig.Port,
IpAddr: serverConfig.IpAddr,
})
}
clientConfig := constant.ClientConfig{
NamespaceId: boot.Nacos.ClientConfig.NamespaceId,
TimeoutMs: boot.Nacos.ClientConfig.TimeoutMs,
NotLoadCacheAtStart: boot.Nacos.ClientConfig.NotLoadCacheAtStart,
LogDir: boot.Nacos.ClientConfig.LogDir,
CacheDir: boot.Nacos.ClientConfig.CacheDir,
LogLevel: boot.Nacos.ClientConfig.LogLevel,
}
clientParam := vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
}
return clients.NewConfigClient(clientParam)
}
// LoadConfig retrieves the configuration from Nacos based on the provided parameters.
func (n *NacosConfig) LoadConfig(param map[string]any) (string, error) {
return n.client.GetConfig(vo.ConfigParam{
DataId: getOrDefault(param[KeyDataId].(string), DataId),
Group: getOrDefault(param[KeyGroup].(string), Group),
})
}
// getOrDefault returns the target value if it is not empty; otherwise, it returns the fallback value.
func getOrDefault(target, fallback string) string {
if len(target) == 0 {
return fallback
}
return target
}
// ListenConfig listens for configuration changes in Nacos.
func (n *NacosConfig) ListenConfig(param map[string]any) error {
return n.client.ListenConfig(vo.ConfigParam{
DataId: getOrDefault(param[KeyDataId].(string), DataId),
Group: getOrDefault(param[KeyGroup].(string), Group),
OnChange: n.onChange,
})
}
// onChange is the callback function triggered when the configuration changes in Nacos.
func (n *NacosConfig) onChange(namespace, group, dataId, data string) {
if len(data) == 0 {
logger.Errorf("Nacos listen callback data is nil. Namespace: %s, Group: %s, DataId: %s", namespace, group, dataId)
return
}
n.mu.Lock()
defer n.mu.Unlock()
var boot model.Bootstrap
if err := Parsers[".yml"]([]byte(data), &boot); err != nil {
logger.Errorf("Failed to parse the configuration loaded from the remote. Error: %v", err)
return
}
n.remoteConfig = &boot
}
// ViewConfig returns the current remote configuration.
func (n *NacosConfig) ViewConfig() *model.Bootstrap {
n.mu.Lock()
defer n.mu.Unlock()
return n.remoteConfig
}