2017-12-29 16:03:30 +08:00
|
|
|
|
// Copyright 2017 gf Author(https://gitee.com/johng/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://gitee.com/johng/gf.
|
|
|
|
|
|
2019-01-16 13:02:59 +08:00
|
|
|
|
// Package gcfg provides reading, caching and managing for configuration files.
|
2018-01-19 16:19:48 +08:00
|
|
|
|
// 配置管理.
|
2018-01-20 11:09:27 +08:00
|
|
|
|
// 配置文件格式支持:json, xml, toml, yaml/yml
|
2017-12-30 23:49:55 +08:00
|
|
|
|
package gcfg
|
2017-12-13 16:45:00 +08:00
|
|
|
|
|
|
|
|
|
import (
|
2018-11-25 22:18:36 +08:00
|
|
|
|
"bytes"
|
2018-10-30 23:58:10 +08:00
|
|
|
|
"errors"
|
2018-11-25 22:18:36 +08:00
|
|
|
|
"fmt"
|
2018-11-30 09:48:57 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/garray"
|
2017-12-13 16:45:00 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/gmap"
|
2018-04-17 14:47:45 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/gtype"
|
2018-10-30 23:58:10 +08:00
|
|
|
|
"gitee.com/johng/gf/g/container/gvar"
|
|
|
|
|
"gitee.com/johng/gf/g/encoding/gjson"
|
2018-11-30 09:48:57 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gfile"
|
2018-10-30 23:58:10 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gfsnotify"
|
2018-10-08 13:38:36 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/glog"
|
2018-10-30 23:58:10 +08:00
|
|
|
|
"gitee.com/johng/gf/g/os/gspath"
|
2017-12-13 16:45:00 +08:00
|
|
|
|
)
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
const (
|
2018-10-13 20:43:21 +08:00
|
|
|
|
DEFAULT_CONFIG_FILE = "config.toml" // 默认的配置管理文件名称
|
2017-12-14 17:32:51 +08:00
|
|
|
|
)
|
2017-12-13 16:45:00 +08:00
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 配置管理对象
|
|
|
|
|
type Config struct {
|
2018-05-23 18:42:21 +08:00
|
|
|
|
name *gtype.String // 默认配置文件名称
|
2018-11-30 09:48:57 +08:00
|
|
|
|
paths *garray.StringArray // 搜索目录路径
|
2018-04-17 17:09:07 +08:00
|
|
|
|
jsons *gmap.StringInterfaceMap // 配置文件对象
|
2018-07-01 00:38:35 +08:00
|
|
|
|
vc *gtype.Bool // 层级检索是否执行分隔符冲突检测(默认为false,检测会比较影响检索效率)
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 生成一个配置管理对象
|
2018-05-23 18:42:21 +08:00
|
|
|
|
func New(path string, file...string) *Config {
|
2018-10-13 20:43:21 +08:00
|
|
|
|
name := DEFAULT_CONFIG_FILE
|
2018-05-23 18:42:21 +08:00
|
|
|
|
if len(file) > 0 {
|
|
|
|
|
name = file[0]
|
|
|
|
|
}
|
2018-10-30 23:58:10 +08:00
|
|
|
|
c := &Config {
|
2018-05-23 18:42:21 +08:00
|
|
|
|
name : gtype.NewString(name),
|
2018-11-30 09:48:57 +08:00
|
|
|
|
paths : garray.NewStringArray(0, 1),
|
2018-04-17 17:09:07 +08:00
|
|
|
|
jsons : gmap.NewStringInterfaceMap(),
|
2018-07-01 00:38:35 +08:00
|
|
|
|
vc : gtype.NewBool(),
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
2018-11-18 19:45:04 +08:00
|
|
|
|
if len(path) > 0 {
|
|
|
|
|
c.SetPath(path)
|
|
|
|
|
}
|
2018-10-30 23:58:10 +08:00
|
|
|
|
return c
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-17 17:09:07 +08:00
|
|
|
|
// 判断从哪个配置文件中获取内容,返回配置文件的绝对路径
|
2018-11-30 09:48:57 +08:00
|
|
|
|
func (c *Config) filePath(file...string) (path string) {
|
2018-05-23 18:42:21 +08:00
|
|
|
|
name := c.name.Val()
|
2018-04-17 15:09:32 +08:00
|
|
|
|
if len(file) > 0 {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
name = file[0]
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
2018-11-30 09:48:57 +08:00
|
|
|
|
c.paths.RLockFunc(func(array []string) {
|
|
|
|
|
for _, v := range array {
|
|
|
|
|
if path, _ = gspath.Search(v, name); path != "" {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
2018-11-25 22:18:36 +08:00
|
|
|
|
if path == "" {
|
|
|
|
|
buffer := bytes.NewBuffer(nil)
|
|
|
|
|
buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" in following paths:", name))
|
2018-11-30 09:48:57 +08:00
|
|
|
|
c.paths.RLockFunc(func(array []string) {
|
|
|
|
|
for k, v := range array {
|
|
|
|
|
buffer.WriteString(fmt.Sprintf("\n%d. %s",k + 1, v))
|
|
|
|
|
}
|
|
|
|
|
})
|
2018-11-25 22:18:36 +08:00
|
|
|
|
glog.Error(buffer.String())
|
|
|
|
|
}
|
2018-11-17 02:39:23 +08:00
|
|
|
|
return path
|
2018-01-04 11:08:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置配置管理器的配置文件存放目录绝对路径
|
2018-05-03 13:35:08 +08:00
|
|
|
|
func (c *Config) SetPath(path string) error {
|
2018-11-30 09:48:57 +08:00
|
|
|
|
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()))
|
2018-05-03 13:35:08 +08:00
|
|
|
|
return err
|
2018-01-04 11:59:35 +08:00
|
|
|
|
}
|
2018-11-30 09:48:57 +08:00
|
|
|
|
c.jsons.Clear()
|
|
|
|
|
c.paths.Clear()
|
|
|
|
|
c.paths.Append(realPath)
|
|
|
|
|
glog.Debug("[gcfg] SetPath:", realPath)
|
2018-05-03 13:35:08 +08:00
|
|
|
|
return nil
|
2018-04-17 14:47:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 00:38:35 +08:00
|
|
|
|
// 设置是否执行层级冲突检查,当键名中存在层级符号时需要开启该特性,默认为关闭。
|
|
|
|
|
// 开启比较耗性能,也不建议允许键名中存在分隔符,最好在应用端避免这种情况。
|
|
|
|
|
func (c *Config) SetViolenceCheck(check bool) {
|
|
|
|
|
c.vc.Set(check)
|
|
|
|
|
c.Reload()
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-03 13:35:08 +08:00
|
|
|
|
// 添加配置管理器的配置文件搜索路径
|
|
|
|
|
func (c *Config) AddPath(path string) error {
|
2018-11-30 09:48:57 +08:00
|
|
|
|
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()))
|
2018-05-03 13:35:08 +08:00
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-30 09:48:57 +08:00
|
|
|
|
c.paths.Append(realPath)
|
|
|
|
|
glog.Debug("[gcfg] AddPath:", realPath)
|
2018-05-03 13:35:08 +08:00
|
|
|
|
return nil
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-21 11:20:31 +08:00
|
|
|
|
// 获取指定文件的绝对路径,默认获取默认的配置文件路径
|
2018-05-03 13:35:08 +08:00
|
|
|
|
func (c *Config) GetFilePath(file...string) string {
|
2018-11-25 22:18:36 +08:00
|
|
|
|
return c.filePath(file...)
|
2018-04-21 11:20:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-23 18:42:21 +08:00
|
|
|
|
// 设置配置管理对象的默认文件名称
|
|
|
|
|
func (c *Config) SetFileName(name string) {
|
2018-11-25 22:18:36 +08:00
|
|
|
|
glog.Debug("[gcfg] SetFileName:", name)
|
2018-05-23 18:42:21 +08:00
|
|
|
|
c.name.Set(name)
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 添加配置文件到配置管理器中,第二个参数为非必须,如果不输入表示添加进入默认的配置名称中
|
2018-05-03 13:35:08 +08:00
|
|
|
|
func (c *Config) getJson(file...string) *gjson.Json {
|
2018-11-25 22:18:36 +08:00
|
|
|
|
filePath := c.filePath(file...)
|
|
|
|
|
if filePath == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
if r := c.jsons.Get(filePath); r != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return r.(*gjson.Json)
|
|
|
|
|
}
|
2018-11-25 22:18:36 +08:00
|
|
|
|
if j, err := gjson.Load(filePath); err == nil {
|
2018-07-01 00:38:35 +08:00
|
|
|
|
j.SetViolenceCheck(c.vc.Val())
|
2018-11-25 22:18:36 +08:00
|
|
|
|
c.addMonitor(filePath)
|
|
|
|
|
c.jsons.Set(filePath, j)
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j
|
2018-10-29 13:59:06 +08:00
|
|
|
|
} else {
|
2018-11-25 22:18:36 +08:00
|
|
|
|
glog.Errorfln(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return nil
|
2017-12-13 16:45:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 获取配置项,当不存在时返回nil
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) Get(pattern string, file...string) interface{} {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j.Get(pattern)
|
2017-12-14 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
return nil
|
2017-12-13 17:35:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-27 16:05:36 +08:00
|
|
|
|
// 获得配置项,返回动态变量
|
2018-11-19 21:11:43 +08:00
|
|
|
|
func (c *Config) GetVar(pattern string, file...string) gvar.VarRead {
|
2018-10-27 16:05:36 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2019-01-14 22:55:43 +08:00
|
|
|
|
return gvar.New(j.Get(pattern), true)
|
2018-10-27 16:05:36 +08:00
|
|
|
|
}
|
2019-01-14 22:55:43 +08:00
|
|
|
|
return gvar.New(nil, true)
|
2018-10-27 16:05:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换
|
|
|
|
|
// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetMap(pattern string, file...string) map[string]interface{} {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j.GetMap(pattern)
|
2017-12-13 17:35:43 +08:00
|
|
|
|
}
|
2017-12-14 17:32:51 +08:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获得一个数组[]interface{},方便操作,不需要自己做类型转换
|
|
|
|
|
// 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetArray(pattern string, file...string) []interface{} {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j.GetArray(pattern)
|
2017-12-13 17:35:43 +08:00
|
|
|
|
}
|
|
|
|
|
return nil
|
2017-12-14 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 返回指定json中的string
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetString(pattern string, file...string) string {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j.GetString(pattern)
|
2017-12-14 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-01 00:27:33 +08:00
|
|
|
|
func (c *Config) GetStrings(pattern string, file...string) []string {
|
|
|
|
|
if j := c.getJson(file...); j != nil {
|
|
|
|
|
return j.GetStrings(pattern)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 10:05:55 +08:00
|
|
|
|
func (c *Config) GetInterfaces(pattern string, file...string) []interface{} {
|
|
|
|
|
if j := c.getJson(file...); j != nil {
|
|
|
|
|
return j.GetInterfaces(pattern)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 返回指定json中的bool
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetBool(pattern string, file...string) bool {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j.GetBool(pattern)
|
2017-12-14 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 15:26:28 +08:00
|
|
|
|
// 返回指定json中的float32
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetFloat32(pattern string, file...string) float32 {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2018-01-19 15:26:28 +08:00
|
|
|
|
return j.GetFloat32(pattern)
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 返回指定json中的float64
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetFloat64(pattern string, file...string) float64 {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2017-12-15 13:09:09 +08:00
|
|
|
|
return j.GetFloat64(pattern)
|
2017-12-14 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 10:05:55 +08:00
|
|
|
|
func (c *Config) GetFloats(pattern string, file...string) []float64 {
|
|
|
|
|
if j := c.getJson(file...); j != nil {
|
|
|
|
|
return j.GetFloats(pattern)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 17:32:51 +08:00
|
|
|
|
// 返回指定json中的float64->int
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetInt(pattern string, file...string) int {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2018-01-19 15:26:28 +08:00
|
|
|
|
return j.GetInt(pattern)
|
|
|
|
|
}
|
|
|
|
|
return 0
|
2017-12-14 17:32:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-23 20:14:37 +08:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 10:05:55 +08:00
|
|
|
|
func (c *Config) GetInts(pattern string, file...string) []int {
|
|
|
|
|
if j := c.getJson(file...); j != nil {
|
|
|
|
|
return j.GetInts(pattern)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-19 15:26:28 +08:00
|
|
|
|
// 返回指定json中的float64->uint
|
2018-04-17 15:09:32 +08:00
|
|
|
|
func (c *Config) GetUint(pattern string, file...string) uint {
|
2018-05-03 13:35:08 +08:00
|
|
|
|
if j := c.getJson(file...); j != nil {
|
2018-01-19 15:26:28 +08:00
|
|
|
|
return j.GetUint(pattern)
|
|
|
|
|
}
|
|
|
|
|
return 0
|
2018-04-17 17:09:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-05-23 20:14:37 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-08 13:38:36 +08:00
|
|
|
|
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")
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-17 17:09:07 +08:00
|
|
|
|
// 清空当前配置文件缓存,强制重新从磁盘文件读取配置文件内容
|
|
|
|
|
func (c *Config) Reload() {
|
|
|
|
|
c.jsons.Clear()
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-18 16:00:47 +08:00
|
|
|
|
// 添加文件监控
|
2018-04-18 16:16:09 +08:00
|
|
|
|
func (c *Config) addMonitor(path string) {
|
2018-08-21 21:18:56 +08:00
|
|
|
|
// 防止多goroutine同时调用
|
|
|
|
|
if c.jsons.Get(path) != nil {
|
|
|
|
|
return
|
2018-04-18 16:00:47 +08:00
|
|
|
|
}
|
2018-08-21 21:18:56 +08:00
|
|
|
|
gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
|
|
|
|
// 删除文件内容缓存,下一次查询会自动更新
|
|
|
|
|
c.jsons.Remove(event.Path)
|
|
|
|
|
})
|
2018-04-18 16:00:47 +08:00
|
|
|
|
}
|