Files
sunhpc-go/internal/config/config.go
2026-02-15 07:18:14 +08:00

148 lines
3.6 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/spf13/viper"
)
const (
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"
)
type Config struct {
DB DBConfig `yaml:"db"`
Log LogConfig `yaml:"log"`
Cluster ClusterConfig `yaml:"cluster"`
}
type DBConfig struct {
Type string `yaml:"type"`
Path string `yaml:"path"` // SQLite: 目录路径
Name string `yaml:"name"` // SQLite: 文件名
User string `yaml:"user"`
Password string `yaml:"password"`
Host string `yaml:"host"`
Port int `yaml:"port"`
Socket string `yaml:"socket"`
Verbose bool `yaml:"verbose"`
}
type LogConfig struct {
Level string `yaml:"level"`
Format string `yaml:"format"`
Output string `yaml:"output"`
FilePath string `yaml:"file_path"`
}
type ClusterConfig struct {
Name string `yaml:"name"`
AdminEmail string `yaml:"admin_email"`
TimeZone string `yaml:"time_zone"`
NodePrefix string `yaml:"node_prefix"`
}
// LoadConfig loads configuration with the following precedence:
// 优先级排序:
// 1. 环境变量 (prefix: SUNHPC_)
// 2. ~/.sunhpc.yaml
// 3. ./sunhpc.yaml
// 4. /etc/sunhpc/sunhpc.yaml
// 5. Default values
/*
示例配置文件:
```yaml
db:
type: sqlite
name: sunhpc.db
path: /var/lib/sunhpc
socket: /var/lib/sunhpc/mysql/mysqld.sock
user: root
password: ""
host: localhost
```
环境变量配置示例:
```bash
export SUNHPC_DATABASE_TYPE=mysql
export SUNHPC_DATABASE_NAME=sunhpc
export SUNHPC_DATABASE_USER=root
export SUNHPC_DATABASE_PASSWORD=123456
export SUNHPC_DATABASE_HOST=localhost
```
*/
func LoadConfig() (*Config, error) {
v := viper.New()
// Step 1: 设置默认值(最低优先级)
v.SetDefault("db.type", "sqlite")
v.SetDefault("db.name", "sunhpc.db")
v.SetDefault("db.path", "/var/lib/sunhpc")
v.SetDefault("db.socket", "/var/lib/sunhpc/mysql/mysqld.sock")
v.SetDefault("db.user", "")
v.SetDefault("db.password", "")
v.SetDefault("db.host", "localhost")
v.SetDefault("db.port", 3306)
v.SetDefault("db.verbose", false)
// Step 2: 启用环境变量(高优先级)
v.SetEnvPrefix("SUNHPC") // e.g., SUNHPC_DATABASE_NAME
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // db.type -> SUNHPC_DB_TYPE
v.AutomaticEnv() // Auto bind env vars matching config keys
// Step 3: 按优先级从高到低加载配置文件
// 优先级: env > ./sunhpc.yaml > ~/.sunhpc.yaml > /etc/sunhpc/sunhpc.yaml > defaults
configFiles := []string{
"./sunhpc.yaml",
filepath.Join(os.Getenv("HOME"), ".sunhpc.yaml"),
filepath.Join(BaseDir, "sunhpc.yaml"),
}
var configFile string
for _, cfgFile := range configFiles {
if _, err := os.Stat(cfgFile); err == nil {
configFile = cfgFile
break // 找到第一个就停止.
}
}
// 如果找到配置文件,就加载它.
if configFile != "" {
v.SetConfigFile(configFile)
if err := v.ReadInConfig(); err != nil {
return nil, fmt.Errorf("加载配置文件 %s 失败: %w", configFile, err)
}
}
// 解码到结构体
var cfg Config
if err := v.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("解码配置到结构体失败: %w", err)
}
return &cfg, 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
}