github.com/aaabigfish/gopkg@v1.1.0/config/config.go (about)

     1  // Package config 提供最基础的配置加载功能
     2  package config
     3  
     4  import (
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/fsnotify/fsnotify"
    11  	"github.com/spf13/cast"
    12  	"github.com/spf13/viper"
    13  )
    14  
    15  const (
    16  	EnvDev    = "dev"
    17  	EnvTest   = "test"
    18  	EnvMirror = "mirror"
    19  	EnvProd   = "prod"
    20  )
    21  
    22  // Get 查询配置/环境变量
    23  var Get func(string) string
    24  
    25  var (
    26  	// Host 主机名
    27  	Host = "localhost"
    28  	// App 服务标识
    29  	App = "localapp"
    30  	// Env 运行环境
    31  	Env = EnvProd
    32  	// Zone 服务区域
    33  	Zone = "sh001"
    34  
    35  	DbMode = "release"
    36  
    37  	files = map[string]*Client{}
    38  
    39  	defaultFile = "config.toml"
    40  
    41  	configErr error
    42  )
    43  
    44  type DBConfig struct {
    45  	Type        string
    46  	Dsn         string
    47  	MaxIdle     int
    48  	MaxActive   int
    49  	IdleTimeout int
    50  }
    51  
    52  // LogConfig is used to configure uber zap
    53  type LogConfig struct {
    54  	Level      string
    55  	FileName   string
    56  	TimeFormat string
    57  	MaxSize    int
    58  	MaxBackups int
    59  	MaxAge     int
    60  	Compress   bool
    61  	LocalTime  bool
    62  	Console    bool
    63  }
    64  
    65  func init() {
    66  	Host, _ = os.Hostname()
    67  	if appID := os.Getenv("APP_ID"); appID != "" {
    68  		App = appID
    69  	}
    70  
    71  	if env := os.Getenv("ENV"); env != "" {
    72  		Env = env
    73  	}
    74  
    75  	if zone := os.Getenv("ZONE"); zone != "" {
    76  		Zone = zone
    77  	}
    78  
    79  	if name := os.Getenv("CONF_NAME"); name != "" {
    80  		defaultFile = name
    81  	}
    82  
    83  	if dbmode := os.Getenv("DB_MODE"); dbmode != "" {
    84  		DbMode = dbmode
    85  	}
    86  
    87  	path := os.Getenv("CONF_PATH")
    88  	if path == "" {
    89  		var err error
    90  		path, err = os.Getwd()
    91  		if err != nil {
    92  			configErr = err
    93  			return
    94  		}
    95  	}
    96  
    97  	configPath := filepath.Join(path, "conf")
    98  	if !fileExists(configPath) {
    99  		appPath, err := filepath.Abs(filepath.Dir(os.Args[0]))
   100  		if err != nil {
   101  			configErr = err
   102  			return
   103  		}
   104  		configPath = filepath.Join(appPath, "conf")
   105  	}
   106  
   107  	fs, err := os.ReadDir(configPath)
   108  	if err != nil {
   109  		return
   110  	}
   111  
   112  	for _, f := range fs {
   113  		if !(strings.HasSuffix(f.Name(), ".toml") || strings.HasSuffix(f.Name(), ".json")) {
   114  			continue
   115  		}
   116  
   117  		v := viper.New()
   118  		v.SetConfigFile(filepath.Join(configPath, f.Name()))
   119  		if err := v.ReadInConfig(); err != nil {
   120  			configErr = err
   121  			return
   122  		}
   123  		v.AutomaticEnv()
   124  
   125  		files[f.Name()] = &Client{v}
   126  	}
   127  
   128  	if File(defaultFile) == nil {
   129  		return
   130  	}
   131  
   132  	Get = GetString
   133  
   134  	if appName := GetString("app.appname"); appName != "" {
   135  		App = appName
   136  	}
   137  
   138  	if env := GetString("app.env"); env != "" {
   139  		Env = env
   140  	}
   141  
   142  	if GetBool("log.Console") {
   143  		DbMode = "debug"
   144  	}
   145  }
   146  
   147  func Error() string {
   148  	return configErr.Error()
   149  }
   150  
   151  func NewDbConfig(key string) *DBConfig {
   152  	maxIdle := 10
   153  	maxActive := 1000
   154  	idleTimeout := 600
   155  	if v := GetInt("db_" + key + ".maxidle"); v > 0 {
   156  		maxIdle = v
   157  	}
   158  	if v := GetInt("db_" + key + ".maxactive"); v > 0 {
   159  		maxActive = v
   160  	}
   161  	if v := GetInt("db_" + key + ".idletimeout"); v > 0 {
   162  		idleTimeout = v
   163  	}
   164  
   165  	return &DBConfig{
   166  		Type:        GetString("db_" + key + ".type"),
   167  		Dsn:         GetString("db_" + key + ".dsn"),
   168  		MaxIdle:     maxIdle,
   169  		MaxActive:   maxActive,
   170  		IdleTimeout: idleTimeout,
   171  	}
   172  }
   173  
   174  func NewLogConfig() *LogConfig {
   175  	cfg := &LogConfig{
   176  		Level:     "debug",
   177  		LocalTime: true,
   178  		Console:   true,
   179  	}
   180  
   181  	if File(defaultFile) == nil {
   182  		return cfg
   183  	}
   184  
   185  	return &LogConfig{
   186  		Level:      GetString("log.Level"),
   187  		FileName:   GetString("log.FileName"),
   188  		TimeFormat: GetString("log.TimeFormat"),
   189  		MaxSize:    GetInt("log.MaxSize"),
   190  		MaxBackups: GetInt("log.MaxBackups"),
   191  		MaxAge:     GetInt("log.MaxAge"),
   192  		Compress:   GetBool("log.Compress"),
   193  		LocalTime:  GetBool("log.LocalTime"),
   194  		Console:    GetBool("log.Console"),
   195  	}
   196  }
   197  
   198  func fileExists(name string) bool {
   199  	if _, err := os.Stat(name); err != nil {
   200  		if os.IsNotExist(err) {
   201  			return false
   202  		}
   203  	}
   204  	return true
   205  }
   206  
   207  type Client struct {
   208  	*viper.Viper
   209  }
   210  
   211  // File 根据文件名获取对应配置对象
   212  // 目前仅支持 toml和json 文件
   213  // 如果要读取 foo.toml 配置,可以 File("foo.toml").Get("bar")
   214  func File(name string) *Client {
   215  	return files[name]
   216  }
   217  
   218  // OnConfigChange 注册配置文件变更回调
   219  // 需要在 WatchConfig 之前调用
   220  func OnConfigChange(run func()) {
   221  	for _, v := range files {
   222  		v.OnConfigChange(func(in fsnotify.Event) { run() })
   223  	}
   224  }
   225  
   226  // WatchConfig 启动配置变更监听,业务代码不要调用。
   227  func WatchConfig() {
   228  	for _, v := range files {
   229  		v.WatchConfig()
   230  	}
   231  }
   232  
   233  // Set 设置配置,仅用于测试
   234  func Set(key string, value interface{}) { File(defaultFile).Set(key, value) }
   235  
   236  func GetBool(key string) bool              { return File(defaultFile).GetBool(key) }
   237  func GetDuration(key string) time.Duration { return File(defaultFile).GetDuration(key) }
   238  func GetFloat64(key string) float64        { return File(defaultFile).GetFloat64(key) }
   239  func GetInt(key string) int                { return File(defaultFile).GetInt(key) }
   240  func GetInt32(key string) int32            { return File(defaultFile).GetInt32(key) }
   241  func GetInt64(key string) int64            { return File(defaultFile).GetInt64(key) }
   242  func GetIntSlice(key string) []int         { return File(defaultFile).GetIntSlice(key) }
   243  func GetSizeInBytes(key string) uint       { return File(defaultFile).GetSizeInBytes(key) }
   244  func GetString(key string) string          { return File(defaultFile).GetString(key) }
   245  func GetStringSlice(key string) []string   { return File(defaultFile).GetStringSlice(key) }
   246  func GetTime(key string) time.Time         { return File(defaultFile).GetTime(key) }
   247  func GetUint(key string) uint              { return File(defaultFile).GetUint(key) }
   248  func GetUint32(key string) uint32          { return File(defaultFile).GetUint32(key) }
   249  func GetUint64(key string) uint64          { return File(defaultFile).GetUint64(key) }
   250  
   251  func GetStringMap(key string) map[string]interface{} { return File(defaultFile).GetStringMap(key) }
   252  
   253  func GetStringMapInt(key string) map[string]int {
   254  	stringMap := File(defaultFile).GetStringMap(key)
   255  	mapInt := make(map[string]int, len(stringMap))
   256  	for key, val := range stringMap {
   257  		mapInt[key] = cast.ToInt(val)
   258  	}
   259  	return mapInt
   260  }
   261  
   262  func GetStringMapString(key string) map[string]string {
   263  	return File(defaultFile).GetStringMapString(key)
   264  }
   265  func GetStringMapStringSlice(key string) map[string][]string {
   266  	return File(defaultFile).GetStringMapStringSlice(key)
   267  }