gf/g/os/gcfg/gcfg.go

380 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package gcfg provides reading, caching and managing for configuration files.
//
// 配置管理,
// 配置文件格式支持json, xml, toml, yaml/yml
package gcfg
import (
"bytes"
"errors"
"fmt"
"github.com/gogf/gf/g/container/garray"
"github.com/gogf/gf/g/container/gmap"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/container/gvar"
"github.com/gogf/gf/g/encoding/gjson"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/gfsnotify"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gspath"
)
const (
// 默认的配置管理文件名称
DEFAULT_CONFIG_FILE = "config.toml"
)
// 配置管理对象
type Config struct {
name *gtype.String // 默认配置文件名称
paths *garray.StringArray // 搜索目录路径
jsons *gmap.StringInterfaceMap // 配置文件对象
vc *gtype.Bool // 层级检索是否执行分隔符冲突检测(默认为false检测会比较影响检索效率)
}
// New returns a new configuration management object.
//
// 生成一个配置管理对象
func New(path string, file...string) *Config {
name := DEFAULT_CONFIG_FILE
if len(file) > 0 {
name = file[0]
}
c := &Config {
name : gtype.NewString(name),
paths : garray.NewStringArray(),
jsons : gmap.NewStringInterfaceMap(),
vc : gtype.NewBool(),
}
if len(path) > 0 {
c.SetPath(path)
}
return c
}
// filePath returns the absolute configuration file path for the given filename by <file>.
//
// 判断从哪个配置文件中获取内容,返回配置文件的绝对路径
func (c *Config) filePath(file...string) (path string) {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
path = c.GetFilePath(name)
if path == "" {
buffer := bytes.NewBuffer(nil)
if c.paths.Len() > 0 {
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" in following paths:", name))
c.paths.RLockFunc(func(array []string) {
for k, v := range array {
buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v))
}
})
} else {
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" with no path set/add", name))
}
glog.Error(buffer.String())
}
return path
}
// 设置配置管理器的配置文件存放目录绝对路径
func (c *Config) SetPath(path string) error {
realPath := gfile.RealPath(path)
if realPath == "" {
err := errors.New(fmt.Sprintf(`path "%s" does not exist`, path))
glog.Error(fmt.Sprintf(`[gcfg] SetPath failed: %s`, err.Error()))
return err
}
// 重复判断
if c.paths.Search(realPath) != -1 {
return nil
}
c.jsons.Clear()
c.paths.Clear()
c.paths.Append(realPath)
//glog.Debug("[gcfg] SetPath:", realPath)
return nil
}
// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。
// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。
func (c *Config) SetViolenceCheck(check bool) {
c.vc.Set(check)
c.Reload()
}
// 添加配置管理器的配置文件搜索路径
func (c *Config) AddPath(path string) error {
realPath := gfile.RealPath(path)
if realPath == "" {
err := errors.New(fmt.Sprintf(`path "%s" does not exist`, path))
glog.Error(fmt.Sprintf(`[gcfg] AddPath failed: %s`, err.Error()))
return err
}
// 重复判断
if c.paths.Search(realPath) != -1 {
return nil
}
c.paths.Append(realPath)
//glog.Debug("[gcfg] AddPath:", realPath)
return nil
}
// 查找配置文件,获取指定配置文件的绝对路径,默认获取默认的配置文件路径;
// 当指定的配置文件不存在时,返回空字符串,并且不会报错。
func (c *Config) GetFilePath(file...string) (path string) {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
c.paths.RLockFunc(func(array []string) {
for _, v := range array {
// 查找当前目录
if path, _ = gspath.Search(v, name); path != "" {
break
}
// 查找当前目录下的config子目录
if path, _ = gspath.Search(v, "config" + gfile.Separator + name); path != "" {
break
}
}
})
return
}
// 设置配置管理对象的默认文件名称
func (c *Config) SetFileName(name string) {
//glog.Debug("[gcfg] SetFileName:", name)
c.name.Set(name)
}
// 获取配置管理对象的默认文件名称
func (c *Config) GetFileName() string {
return c.name.Val()
}
// 添加配置文件到配置管理器中,第二个参数为非必须,如果不输入表示添加进入默认的配置名称中
// 内部带缓存控制功能。
func (c *Config) getJson(file...string) *gjson.Json {
name := c.name.Val()
if len(file) > 0 {
name = file[0]
}
r := c.jsons.GetOrSetFuncLock(name, func() interface{} {
filePath := c.filePath(file...)
if filePath == "" {
return nil
}
if j, err := gjson.Load(filePath); err == nil {
j.SetViolenceCheck(c.vc.Val())
// 添加配置文件监听,如果有任何变化,删除文件内容缓存,下一次查询会自动更新
gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
c.jsons.Remove(name)
})
return j
} else {
glog.Criticalfln(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
}
return nil
})
if r != nil {
return r.(*gjson.Json)
}
return nil
}
// 获取配置项当不存在时返回nil
func (c *Config) Get(pattern string, file...string) interface{} {
if j := c.getJson(file...); j != nil {
return j.Get(pattern)
}
return nil
}
// 获得配置项,返回动态变量
func (c *Config) GetVar(pattern string, file...string) gvar.VarRead {
if j := c.getJson(file...); j != nil {
return gvar.New(j.Get(pattern), true)
}
return gvar.New(nil, true)
}
// 判断指定的配置项是否存在
func (c *Config) Contains(pattern string, file...string) bool {
if j := c.getJson(file...); j != nil {
return j.Contains(pattern)
}
return false
}
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
func (c *Config) GetMap(pattern string, file...string) map[string]interface{} {
if j := c.getJson(file...); j != nil {
return j.GetMap(pattern)
}
return nil
}
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
// 注意如果获取的值不存在或者类型与json类型不匹配那么将会返回nil
func (c *Config) GetArray(pattern string, file...string) []interface{} {
if j := c.getJson(file...); j != nil {
return j.GetArray(pattern)
}
return nil
}
// 返回指定json中的string
func (c *Config) GetString(pattern string, file...string) string {
if j := c.getJson(file...); j != nil {
return j.GetString(pattern)
}
return ""
}
func (c *Config) GetStrings(pattern string, file...string) []string {
if j := c.getJson(file...); j != nil {
return j.GetStrings(pattern)
}
return nil
}
func (c *Config) GetInterfaces(pattern string, file...string) []interface{} {
if j := c.getJson(file...); j != nil {
return j.GetInterfaces(pattern)
}
return nil
}
// 返回指定json中的bool
func (c *Config) GetBool(pattern string, file...string) bool {
if j := c.getJson(file...); j != nil {
return j.GetBool(pattern)
}
return false
}
// 返回指定json中的float32
func (c *Config) GetFloat32(pattern string, file...string) float32 {
if j := c.getJson(file...); j != nil {
return j.GetFloat32(pattern)
}
return 0
}
// 返回指定json中的float64
func (c *Config) GetFloat64(pattern string, file...string) float64 {
if j := c.getJson(file...); j != nil {
return j.GetFloat64(pattern)
}
return 0
}
func (c *Config) GetFloats(pattern string, file...string) []float64 {
if j := c.getJson(file...); j != nil {
return j.GetFloats(pattern)
}
return nil
}
// 返回指定json中的float64->int
func (c *Config) GetInt(pattern string, file...string) int {
if j := c.getJson(file...); j != nil {
return j.GetInt(pattern)
}
return 0
}
func (c *Config) GetInt8(pattern string, file...string) int8 {
if j := c.getJson(file...); j != nil {
return j.GetInt8(pattern)
}
return 0
}
func (c *Config) GetInt16(pattern string, file...string) int16 {
if j := c.getJson(file...); j != nil {
return j.GetInt16(pattern)
}
return 0
}
func (c *Config) GetInt32(pattern string, file...string) int32 {
if j := c.getJson(file...); j != nil {
return j.GetInt32(pattern)
}
return 0
}
func (c *Config) GetInt64(pattern string, file...string) int64 {
if j := c.getJson(file...); j != nil {
return j.GetInt64(pattern)
}
return 0
}
func (c *Config) GetInts(pattern string, file...string) []int {
if j := c.getJson(file...); j != nil {
return j.GetInts(pattern)
}
return nil
}
// 返回指定json中的float64->uint
func (c *Config) GetUint(pattern string, file...string) uint {
if j := c.getJson(file...); j != nil {
return j.GetUint(pattern)
}
return 0
}
func (c *Config) GetUint8(pattern string, file...string) uint8 {
if j := c.getJson(file...); j != nil {
return j.GetUint8(pattern)
}
return 0
}
func (c *Config) GetUint16(pattern string, file...string) uint16 {
if j := c.getJson(file...); j != nil {
return j.GetUint16(pattern)
}
return 0
}
func (c *Config) GetUint32(pattern string, file...string) uint32 {
if j := c.getJson(file...); j != nil {
return j.GetUint32(pattern)
}
return 0
}
func (c *Config) GetUint64(pattern string, file...string) uint64 {
if j := c.getJson(file...); j != nil {
return j.GetUint64(pattern)
}
return 0
}
func (c *Config) GetToStruct(pattern string, objPointer interface{}, file...string) error {
if j := c.getJson(file...); j != nil {
return j.GetToStruct(pattern, objPointer)
}
return errors.New("config file not found")
}
// 清空当前配置文件缓存,强制重新从磁盘文件读取配置文件内容
func (c *Config) Reload() {
c.jsons.Clear()
}