Files
chatlog_alpha/pkg/config/config.go
lx1056758714-glitch 3d04a7f3eb 同步本地代码
2025-12-13 17:30:38 +08:00

160 lines
3.7 KiB
Go

/*
* Copyright (c) 2023 shenjunzheng@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package config
import (
"errors"
"os"
"strings"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
)
const (
DefaultConfigType = "json"
)
var (
// ERROR
ErrInvalidDirectory = errors.New("invalid directory path")
ErrMissingConfigName = errors.New("config name not specified")
)
type Manager struct {
App string
EnvPrefix string
Path string
Name string
WriteConfig bool
Viper *viper.Viper
}
// New initializes the configuration settings.
// It sets up the name, type, and path for the configuration file.
func New(app, path, name, envPrefix string, writeConfig bool) (*Manager, error) {
if len(app) == 0 {
return nil, ErrMissingConfigName
}
v := viper.New()
v.SetConfigType(DefaultConfigType)
var err error
// Path
if len(path) == 0 {
path, err = os.UserHomeDir()
if err != nil {
path = os.TempDir()
}
path += string(os.PathSeparator) + "." + app
}
if err := PrepareDir(path); err != nil {
return nil, err
}
v.AddConfigPath(path)
// Name
if len(name) == 0 {
name = app
}
v.SetConfigName(name)
// Env
if len(envPrefix) != 0 {
v.SetEnvPrefix(strings.ToUpper(app))
v.AutomaticEnv()
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
}
return &Manager{
App: app,
EnvPrefix: envPrefix,
Path: path,
Name: name,
Viper: v,
WriteConfig: writeConfig,
}, nil
}
// Load loads the configuration from the previously initialized file.
// It unmarshals the configuration into the provided conf interface.
func (c *Manager) Load(conf interface{}) error {
if err := c.Viper.ReadInConfig(); err != nil {
log.Error().Err(err).Msg("read config failed")
if c.WriteConfig {
if err := c.Viper.SafeWriteConfig(); err != nil {
return err
}
}
}
if err := c.Viper.Unmarshal(conf, decoderConfig()); err != nil {
return err
}
return nil
}
// LoadFile loads the configuration from a specified file.
// It unmarshals the configuration into the provided conf interface.
func (c *Manager) LoadFile(file string, conf interface{}) error {
c.Viper.SetConfigFile(file)
if err := c.Viper.ReadInConfig(); err != nil {
return err
}
if err := c.Viper.Unmarshal(conf, decoderConfig()); err != nil {
return err
}
return nil
}
// SetConfig sets a configuration key to a specified value.
// It also writes the updated configuration back to the file.
func (c *Manager) SetConfig(key string, value interface{}) error {
c.Viper.Set(key, value)
if c.WriteConfig {
if err := c.Viper.WriteConfig(); err != nil {
return err
}
}
return nil
}
// GetConfig retrieves all configuration settings as a map.
func (c *Manager) GetConfig() map[string]interface{} {
return c.Viper.AllSettings()
}
// PrepareDir ensures that the specified directory path exists.
// If the directory does not exist, it attempts to create it.
func PrepareDir(path string) error {
stat, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
if err := os.MkdirAll(path, 0755); err != nil {
return err
}
} else {
return err
}
} else if !stat.IsDir() {
log.Debug().Msgf("%s is not a directory", path)
return ErrInvalidDirectory
}
return nil
}