You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
5.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}
}