|
|
package yml_config
|
|
|
|
|
|
import (
|
|
|
"github.com/fsnotify/fsnotify"
|
|
|
"github.com/spf13/viper"
|
|
|
"go.uber.org/zap"
|
|
|
"goskeleton/app/core/container"
|
|
|
"goskeleton/app/global/my_errors"
|
|
|
"goskeleton/app/global/variable"
|
|
|
"goskeleton/app/utils/yml_config/ymlconfig_interf"
|
|
|
"log"
|
|
|
"sync"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
// 由于 vipver 包本身对于文件的变化事件有一个bug,相关事件会被回调两次
|
|
|
// 常年未彻底解决,相关的 issue 清单:https://github.com/spf13/viper/issues?q=OnConfigChange
|
|
|
// 设置一个内部全局变量,记录配置文件变化时的时间点,如果两次回调事件事件差小于1秒,我们认为是第二次回调事件,而不是人工修改配置文件
|
|
|
// 这样就避免了 viper 包的这个bug
|
|
|
|
|
|
var lastChangeTime time.Time
|
|
|
var containerFactory = container.CreateContainersFactory()
|
|
|
|
|
|
func init() {
|
|
|
lastChangeTime = time.Now()
|
|
|
}
|
|
|
|
|
|
// CreateYamlFactory 创建一个yaml配置文件工厂
|
|
|
// 参数设置为可变参数的文件名,这样参数就可以不需要传递,如果传递了多个,我们只取第一个参数作为配置文件名
|
|
|
func CreateYamlFactory(fileName ...string) ymlconfig_interf.YmlConfigInterf {
|
|
|
|
|
|
yamlConfig := viper.New()
|
|
|
// 配置文件所在目录
|
|
|
yamlConfig.AddConfigPath(variable.BasePath + "/config")
|
|
|
// 需要读取的文件名,默认为:config
|
|
|
if len(fileName) == 0 {
|
|
|
yamlConfig.SetConfigName("config")
|
|
|
} else {
|
|
|
yamlConfig.SetConfigName(fileName[0])
|
|
|
}
|
|
|
//设置配置文件类型(后缀)为 yml
|
|
|
yamlConfig.SetConfigType("yml")
|
|
|
|
|
|
if err := yamlConfig.ReadInConfig(); err != nil {
|
|
|
log.Fatal(my_errors.ErrorsConfigInitFail + err.Error())
|
|
|
}
|
|
|
|
|
|
return &ymlConfig{
|
|
|
viper: yamlConfig,
|
|
|
mu: new(sync.Mutex),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
type ymlConfig struct {
|
|
|
viper *viper.Viper
|
|
|
mu *sync.Mutex
|
|
|
}
|
|
|
|
|
|
//ConfigFileChangeListen 监听文件变化
|
|
|
func (y *ymlConfig) ConfigFileChangeListen() {
|
|
|
y.viper.OnConfigChange(func(changeEvent fsnotify.Event) {
|
|
|
if time.Now().Sub(lastChangeTime).Seconds() >= 1 {
|
|
|
if changeEvent.Op.String() == "WRITE" {
|
|
|
y.clearCache()
|
|
|
lastChangeTime = time.Now()
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
y.viper.WatchConfig()
|
|
|
}
|
|
|
|
|
|
// keyIsCache 判断相关键是否已经缓存
|
|
|
func (y *ymlConfig) keyIsCache(keyName string) bool {
|
|
|
if _, exists := containerFactory.KeyIsExists(variable.ConfigKeyPrefix + keyName); exists {
|
|
|
return true
|
|
|
} else {
|
|
|
return false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 对键值进行缓存
|
|
|
func (y *ymlConfig) cache(keyName string, value interface{}) bool {
|
|
|
// 避免瞬间缓存键、值时,程序提示键名已经被注册的日志输出
|
|
|
y.mu.Lock()
|
|
|
defer y.mu.Unlock()
|
|
|
if _, exists := containerFactory.KeyIsExists(variable.ConfigKeyPrefix + keyName); exists {
|
|
|
return true
|
|
|
}
|
|
|
return containerFactory.Set(variable.ConfigKeyPrefix+keyName, value)
|
|
|
}
|
|
|
|
|
|
// 通过键获取缓存的值
|
|
|
func (y *ymlConfig) getValueFromCache(keyName string) interface{} {
|
|
|
return containerFactory.Get(variable.ConfigKeyPrefix + keyName)
|
|
|
}
|
|
|
|
|
|
// 清空已经缓存的配置项信息
|
|
|
func (y *ymlConfig) clearCache() {
|
|
|
containerFactory.FuzzyDelete(variable.ConfigKeyPrefix)
|
|
|
}
|
|
|
|
|
|
// Clone 允许 clone 一个相同功能的结构体
|
|
|
func (y *ymlConfig) Clone(fileName string) ymlconfig_interf.YmlConfigInterf {
|
|
|
// 这里存在一个深拷贝,需要注意,避免拷贝的结构体操作对原始结构体造成影响
|
|
|
var ymlC = *y
|
|
|
var ymlConfViper = *(y.viper)
|
|
|
(&ymlC).viper = &ymlConfViper
|
|
|
|
|
|
(&ymlC).viper.SetConfigName(fileName)
|
|
|
if err := (&ymlC).viper.ReadInConfig(); err != nil {
|
|
|
variable.ZapLog.Error(my_errors.ErrorsConfigInitFail, zap.Error(err))
|
|
|
}
|
|
|
return &ymlC
|
|
|
}
|
|
|
|
|
|
// Get 一个原始值
|
|
|
func (y *ymlConfig) Get(keyName string) interface{} {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName)
|
|
|
} else {
|
|
|
value := y.viper.Get(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetString 字符串格式返回值
|
|
|
func (y *ymlConfig) GetString(keyName string) string {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(string)
|
|
|
} else {
|
|
|
value := y.viper.GetString(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// GetBool 布尔格式返回值
|
|
|
func (y *ymlConfig) GetBool(keyName string) bool {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(bool)
|
|
|
} else {
|
|
|
value := y.viper.GetBool(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetInt 整数格式返回值
|
|
|
func (y *ymlConfig) GetInt(keyName string) int {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(int)
|
|
|
} else {
|
|
|
value := y.viper.GetInt(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetInt32 整数格式返回值
|
|
|
func (y *ymlConfig) GetInt32(keyName string) int32 {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(int32)
|
|
|
} else {
|
|
|
value := y.viper.GetInt32(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetInt64 整数格式返回值
|
|
|
func (y *ymlConfig) GetInt64(keyName string) int64 {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(int64)
|
|
|
} else {
|
|
|
value := y.viper.GetInt64(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetFloat64 小数格式返回值
|
|
|
func (y *ymlConfig) GetFloat64(keyName string) float64 {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(float64)
|
|
|
} else {
|
|
|
value := y.viper.GetFloat64(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetDuration 时间单位格式返回值
|
|
|
func (y *ymlConfig) GetDuration(keyName string) time.Duration {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).(time.Duration)
|
|
|
} else {
|
|
|
value := y.viper.GetDuration(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// GetStringSlice 字符串切片数格式返回值
|
|
|
func (y *ymlConfig) GetStringSlice(keyName string) []string {
|
|
|
if y.keyIsCache(keyName) {
|
|
|
return y.getValueFromCache(keyName).([]string)
|
|
|
} else {
|
|
|
value := y.viper.GetStringSlice(keyName)
|
|
|
y.cache(keyName, value)
|
|
|
return value
|
|
|
}
|
|
|
}
|