216 lines
5.7 KiB
Go
216 lines
5.7 KiB
Go
package yml_config
|
||
|
||
import (
|
||
"catface/app/core/container"
|
||
"catface/app/global/my_errors"
|
||
"catface/app/global/variable"
|
||
"catface/app/utils/yml_config/ymlconfig_interf"
|
||
"log"
|
||
"sync"
|
||
"time"
|
||
|
||
"github.com/fsnotify/fsnotify"
|
||
"github.com/spf13/viper"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// 由于 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
|
||
}
|
||
}
|