160 lines
3.8 KiB
Go
160 lines
3.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
type Config struct {
|
|
Server ServerConfig `mapstructure:"server"`
|
|
Database DatabaseConfig `mapstructure:"database"`
|
|
Redis RedisConfig `mapstructure:"redis"`
|
|
JWT JWTConfig `mapstructure:"jwt"`
|
|
Captcha CaptchaConfig `mapstructure:"captcha"`
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
Mode string `mapstructure:"mode"`
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Type string `mapstructure:"type"` // sqlite or mysql
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
User string `mapstructure:"user"`
|
|
Password string `mapstructure:"password"`
|
|
Database string `mapstructure:"database"`
|
|
SQLite SQLiteConfig `mapstructure:"sqlite"`
|
|
}
|
|
|
|
type SQLiteConfig struct {
|
|
Path string `mapstructure:"path"`
|
|
}
|
|
|
|
type RedisConfig struct {
|
|
Enabled bool `mapstructure:"enabled"`
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
Password string `mapstructure:"password"`
|
|
DB int `mapstructure:"db"`
|
|
}
|
|
|
|
type JWTConfig struct {
|
|
Secret string `mapstructure:"secret"`
|
|
ExpireTime int `mapstructure:"expire_time"` // hours
|
|
}
|
|
|
|
type CaptchaConfig struct {
|
|
ModelPath string `mapstructure:"model_path"`
|
|
}
|
|
|
|
var Cfg *Config
|
|
|
|
func Load(configPath string) error {
|
|
viper.SetConfigName("config")
|
|
viper.SetConfigType("yaml")
|
|
viper.AddConfigPath(".")
|
|
viper.AddConfigPath("./data")
|
|
viper.AddConfigPath("/app/data")
|
|
viper.AddConfigPath(configPath)
|
|
|
|
// 默认值
|
|
viper.SetDefault("server.host", "0.0.0.0")
|
|
viper.SetDefault("server.port", 6688)
|
|
viper.SetDefault("server.mode", "release")
|
|
viper.SetDefault("database.type", "sqlite")
|
|
viper.SetDefault("database.sqlite.path", "./data/app.db")
|
|
viper.SetDefault("database.host", "localhost")
|
|
viper.SetDefault("database.port", 3306)
|
|
viper.SetDefault("redis.enabled", false)
|
|
viper.SetDefault("redis.host", "localhost")
|
|
viper.SetDefault("redis.port", 6379)
|
|
viper.SetDefault("redis.db", 0)
|
|
viper.SetDefault("jwt.expire_time", 1440) // 60 days
|
|
viper.SetDefault("captcha.model_path", "./models")
|
|
|
|
if err := viper.ReadInConfig(); err != nil {
|
|
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
|
return fmt.Errorf("配置文件未找到,请先运行安装向导")
|
|
}
|
|
return err
|
|
}
|
|
|
|
Cfg = &Config{}
|
|
if err := viper.Unmarshal(Cfg); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 确保 JWT Secret 有值
|
|
if Cfg.JWT.Secret == "" {
|
|
Cfg.JWT.Secret = "default-jwt-secret-change-in-production"
|
|
}
|
|
|
|
// 从环境变量读取 JWT Secret(优先级更高)
|
|
if secret := os.Getenv("JWT_SECRET"); secret != "" {
|
|
Cfg.JWT.Secret = secret
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
const dataDir = "/app/data"
|
|
|
|
func Save(cfg *Config) error {
|
|
// 确保 data 目录存在
|
|
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
|
return fmt.Errorf("创建数据目录失败: %w", err)
|
|
}
|
|
|
|
// 直接写入配置文件
|
|
configPath := dataDir + "/config.yaml"
|
|
|
|
// 构建 YAML 内容
|
|
content := fmt.Sprintf(`server:
|
|
host: %s
|
|
port: %d
|
|
mode: %s
|
|
database:
|
|
type: %s
|
|
host: %s
|
|
port: %d
|
|
user: %s
|
|
password: %s
|
|
database: %s
|
|
sqlite:
|
|
path: %s
|
|
redis:
|
|
enabled: %v
|
|
host: %s
|
|
port: %d
|
|
password: %s
|
|
db: %d
|
|
jwt:
|
|
secret: %s
|
|
expire_time: %d
|
|
captcha:
|
|
model_path: %s
|
|
`,
|
|
cfg.Server.Host, cfg.Server.Port, cfg.Server.Mode,
|
|
cfg.Database.Type, cfg.Database.Host, cfg.Database.Port, cfg.Database.User, cfg.Database.Password, cfg.Database.Database, cfg.Database.SQLite.Path,
|
|
cfg.Redis.Enabled, cfg.Redis.Host, cfg.Redis.Port, cfg.Redis.Password, cfg.Redis.DB,
|
|
cfg.JWT.Secret, cfg.JWT.ExpireTime,
|
|
cfg.Captcha.ModelPath,
|
|
)
|
|
|
|
if err := os.WriteFile(configPath, []byte(content), 0644); err != nil {
|
|
return fmt.Errorf("写入配置文件失败: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func IsInstalled() bool {
|
|
_, err := os.Stat(dataDir + "/config.yaml")
|
|
return err == nil
|
|
}
|