Files
sunhpc-go/pkg/config/config.go
2026-02-20 18:44:43 +08:00

170 lines
4.1 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.
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/spf13/viper"
"go.yaml.in/yaml/v3"
)
type Config struct {
Database DatabaseConfig `yaml:"database"`
Log LogConfig `yaml:"log"`
}
type DatabaseConfig struct {
DSN string `yaml:"dsn"` // 数据库连接字符串
Path string `yaml:"path"` // SQLite: 目录路径
Name string `yaml:"name"` // SQLite: 文件名
}
type LogConfig struct {
Level string `yaml:"level"`
Format string `yaml:"format"`
Output string `yaml:"output"`
Verbose bool `yaml:"verbose"`
LogFile string `yaml:"log_file"`
ShowColor bool `yaml:"show_color"`
}
// --------------------------------- 全局单例配置(核心) ---------------------------------
var (
// GlobalConfig 全局配置单例实例
GlobalConfig *Config
// 命令行参数配置(全局、由root命令绑定)
CLIParams = struct {
Verbose bool // -v/--verbose
NoColor bool // --no-color
Config string // -c/--config
}{}
BaseDir string = "/etc/sunhpc"
LogDir string = "/var/log/sunhpc"
TmplDir string = BaseDir + "/tmpl.d"
appName string = "sunhpc"
defaultDBPath string = "/var/lib/sunhpc"
defaultDBName string = "sunhpc.db"
)
// ----------------------------------- 配置加载(只加载一次) -----------------------------------
func LoadConfig() (*Config, error) {
// 如果已经加载过,直接返回
if GlobalConfig != nil {
return GlobalConfig, nil
}
viper.SetConfigName("sunhpc")
viper.SetConfigType("yaml")
viper.AddConfigPath(BaseDir)
viper.AddConfigPath(".")
viper.AddConfigPath(filepath.Join(os.Getenv("HOME"), "."))
// Step 1: 设置默认值(最低优先级)
viper.SetDefault("log.level", "info")
viper.SetDefault("log.format", "text")
viper.SetDefault("log.output", "stdout")
viper.SetDefault("log.verbose", false)
viper.SetDefault("log.log_file", filepath.Join(LogDir, "sunhpc.log"))
viper.SetDefault("database.name", "sunhpc.db")
viper.SetDefault("database.path", "/var/lib/sunhpc")
if err := viper.ReadInConfig(); err != nil {
// 配置文件不存在时,使用默认值
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return nil, err
}
}
// 合并命令行参数(最高优先级)
if CLIParams.Verbose {
viper.Set("log.verbose", true)
viper.Set("log.level", "debug")
}
// 合并noColor参数
if CLIParams.NoColor {
viper.Set("log.show_color", false)
}
fullPath := filepath.Join(
viper.GetString("database.path"), viper.GetString("database.name"))
dsn := fmt.Sprintf(
"%s?_foreign_keys=on&_journal_mode=WAL&_timeout=5000", fullPath)
viper.Set("database.dsn", dsn)
// 解码到结构体
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return nil, err
}
GlobalConfig = &cfg
return GlobalConfig, nil
}
// InitDirs 创建所有必需目录
func InitDirs() error {
dirs := []string{
BaseDir,
TmplDir,
LogDir,
}
for _, d := range dirs {
if err := os.MkdirAll(d, 0755); err != nil {
return fmt.Errorf("创建目录 %s 失败: %w", d, err)
}
}
return nil
}
func (c *Config) WriteDefaultConfig(path string) error {
// 确保目录存在
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0755); err != nil {
return fmt.Errorf("创建目录失败: %w", err)
}
// 生成默认配置
cfg := DefaultConfig(path)
// 序列化为 YAML
data, err := yaml.Marshal(cfg)
if err != nil {
return fmt.Errorf("序列化配置失败: %w", err)
}
// 写入文件0644 权限)
return os.WriteFile(path, data, 0644)
}
func DefaultConfig(path string) *Config {
return &Config{
Database: DatabaseConfig{
DSN: fmt.Sprintf("%s?_foreign_keys=on&_journal_mode=WAL&_timeout=5000",
filepath.Join(filepath.Dir(path), defaultDBName)),
Path: filepath.Dir(path),
Name: defaultDBName,
},
Log: LogConfig{
Level: "info",
Format: "text",
Output: "stdout",
LogFile: filepath.Join(filepath.Dir(path), "sunhpc.log"),
Verbose: false,
},
}
}
// ResetConfig 重置全局配置为默认值
func ResetConfig() {
GlobalConfig = nil
viper.Reset()
CLIParams = struct {
Verbose bool // -v/--verbose
NoColor bool // --no-color
Config string // -c/--config
}{}
}