nacos viper remote provider

This commit is contained in:
yoyofx 2021-04-29 19:54:59 +08:00
parent 20220cb36f
commit bcd01f97cc
7 changed files with 290 additions and 0 deletions

74
example/main.go Normal file
View File

@ -0,0 +1,74 @@
package main
import (
"fmt"
"github.com/spf13/viper"
remote "github.com/yoyofxteam/nacos-viper-remote"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
config_viper := viper.New()
runtime_viper := config_viper
runtime_viper.SetConfigFile("./example_config.yaml")
_ = runtime_viper.ReadInConfig()
var option *remote.Option
_ = runtime_viper.Sub("yoyogo.cloud.discovery.metadata").Unmarshal(&option)
remote.SetOptions(option)
//remote.SetOptions(&remote.Option{
// Url: "localhost",
// Port: 80,
// NamespaceId: "public",
// GroupName: "DEFAULT_GROUP",
// Config: remote.Config{ DataId: "config_dev" },
// Auth: nil,
//})
//localSetting := runtime_viper.AllSettings()
remote_viper := viper.New()
err := remote_viper.AddRemoteProvider("nacos", "localhost", "")
remote_viper.SetConfigType("yaml")
err = remote_viper.ReadRemoteConfig()
if err == nil {
err = remote_viper.WatchRemoteConfigOnChannel()
if err == nil {
config_viper = remote_viper
fmt.Println("used remote viper")
}
}
appName := config_viper.GetString("yoyogo.application.name")
fmt.Println(appName)
go func() {
for {
time.Sleep(time.Second * 30) // delay after each request
appName = config_viper.GetString("yoyogo.application.name")
fmt.Println(appName)
}
}()
onExit()
}
func onExit() {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM,
syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
for s := range c {
switch s {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
fmt.Println("Program Exit...", s)
default:
fmt.Println("other signal", s)
}
}
}

20
example_config.yaml Normal file
View File

@ -0,0 +1,20 @@
yoyogo:
application:
name: yoyogo_demo_dev
cloud:
discovery:
cache:
ttl: 30 # seconds
strategy: "round-robin" # round-robin , weight-time , random
type: "nacos"
metadata:
url: "120.53.133.30"
port: 80
namespace: "public"
group: "DEFAULT_GROUP"
configserver:
dataId: "config_dev"
auth:
enable: true
username: "root"
password: "1234"

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module github.com/yoyofxteam/nacos-viper-remote
go 1.14
require (
github.com/spf13/viper v1.7.1
github.com/nacos-group/nacos-sdk-go v1.0.7
)

94
nacos_manager.go Normal file
View File

@ -0,0 +1,94 @@
package nacos_viper_remote
import (
"fmt"
"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/common/logger"
"github.com/nacos-group/nacos-sdk-go/vo"
"github.com/spf13/viper"
"strings"
)
type nacosConfigManager struct {
client config_client.IConfigClient
option *Option
}
func NewNacosConfigManager(option *Option) (*nacosConfigManager, error) {
var serverConfigs []constant.ServerConfig
urls := strings.Split(option.Url, ";")
for _, url := range urls {
serverConfigs = append(serverConfigs, constant.ServerConfig{
ContextPath: "/nacos",
IpAddr: url,
Port: option.Port,
})
}
clientConfig := constant.ClientConfig{
NamespaceId: option.NamespaceId,
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
RotateTime: "1h",
MaxAge: 3,
LogLevel: "info",
}
if option.Auth != nil && option.Auth.Enable {
clientConfig.Username = option.Auth.User
clientConfig.Password = option.Auth.Password
}
client, err := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
if err != nil {
logger.Error(err.Error())
return nil, err
}
manager := &nacosConfigManager{client: client, option: option}
return manager, err
}
func (cm *nacosConfigManager) Get(dataId string) ([]byte, error) {
//get config
content, err := cm.client.GetConfig(vo.ConfigParam{
DataId: cm.option.Config.DataId,
Group: cm.option.GroupName,
})
return []byte(content), err
}
func (cm *nacosConfigManager) Watch(dataId string, stop chan bool) <-chan *viper.RemoteResponse {
resp := make(chan *viper.RemoteResponse)
configParams := vo.ConfigParam{
DataId: cm.option.Config.DataId,
Group: cm.option.GroupName,
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("config changed group:" + group + ", dataId:" + dataId)
resp <- &viper.RemoteResponse{
Value: []byte(data),
Error: nil,
}
},
}
err := cm.client.ListenConfig(configParams)
if err != nil {
return nil
}
go func() {
for {
select {
case <-stop:
_ = cm.client.CancelListenConfig(configParams)
return
}
}
}()
return resp
}

20
nacos_options.go Normal file
View File

@ -0,0 +1,20 @@
package nacos_viper_remote
type Option struct {
Url string `mapstructure:"url"`
Port uint64 `mapstructure:"port"`
NamespaceId string `mapstructure:"namespace"`
GroupName string `mapstructure:"group"`
Config Config `mapstructure:"configserver"`
Auth *Auth `mapstructure:"auth"`
}
type Config struct {
DataId string `mapstructure:"dataId"`
}
type Auth struct {
Enable bool `mapstructure:"enable"`
User string `mapstructure:"username"`
Password string `mapstructure:"password"`
}

8
viper_manager.go Normal file
View File

@ -0,0 +1,8 @@
package nacos_viper_remote
import "github.com/spf13/viper"
type viperConfigManager interface {
Get(key string) ([]byte, error)
Watch(key string, stop chan bool) <-chan *viper.RemoteResponse
}

66
viper_remote.go Normal file
View File

@ -0,0 +1,66 @@
package nacos_viper_remote
import (
"bytes"
"errors"
"github.com/spf13/viper"
"io"
)
var nacosOptions = &Option{}
func SetOptions(option *Option) {
nacosOptions = option
}
type remoteConfigProvider struct {
}
func (rc *remoteConfigProvider) Get(rp viper.RemoteProvider) (io.Reader, error) {
cmt, err := getConfigManager(rp)
if err != nil {
return nil, err
}
var b []byte
switch cm := cmt.(type) {
case viperConfigManager:
b, err = cm.Get(rp.Path())
}
if err != nil {
return nil, err
}
return bytes.NewReader(b), nil
}
func (rc *remoteConfigProvider) Watch(rp viper.RemoteProvider) (io.Reader, error) {
return rc.Get(rp)
}
func (rc *remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
cmt, err := getConfigManager(rp)
if err != nil {
return nil, nil
}
switch cm := cmt.(type) {
case viperConfigManager:
quit := make(chan bool)
viperResponseCh := cm.Watch("dataId", quit)
return viperResponseCh, quit
}
return nil, nil
}
func getConfigManager(rp viper.RemoteProvider) (interface{}, error) {
if rp.Provider() == "nacos" {
return NewNacosConfigManager(nacosOptions)
} else {
return nil, errors.New("The Nacos configuration manager is not supported!")
}
}
func init() {
viper.SupportedRemoteProviders = []string{"nacos"}
viper.RemoteConfig = &remoteConfigProvider{}
}