Files
AntiCaptcha/internal/config/config.go
T
admin d9cc4b0be0
Build and Deploy / build (push) Successful in 2m39s
Build and Deploy / deploy (push) Successful in 9s
fix: add mapstructure tags to config structs for proper viper parsing
2026-07-17 07:51:57 +00:00

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
}