mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 16:46:37 +08:00
env load
This commit is contained in:
@@ -70,9 +70,19 @@ func init() {
|
||||
viper.SetConfigFile(configPath)
|
||||
viper.AutomaticEnv()
|
||||
|
||||
// 读取配置文件
|
||||
// 读取配置文件(可选:找不到文件时使用空默认值 + 环境变量)
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Fatalf("[Config] read config failed: %v\n", err)
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||
// 文件存在但读取/解析失败
|
||||
if _, statErr := os.Stat(configPath); statErr == nil {
|
||||
log.Fatalf("[Config] read config failed: %v\n", err)
|
||||
}
|
||||
}
|
||||
log.Println("[Config] no config file found, using environment variables only")
|
||||
viper.SetConfigType("yaml")
|
||||
if err := viper.ReadConfig(strings.NewReader("")); err != nil {
|
||||
log.Fatalf("[Config] failed to init empty config: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析配置到结构体
|
||||
@@ -81,8 +91,11 @@ func init() {
|
||||
log.Fatalf("[Config] parse config failed: %v\n", err)
|
||||
}
|
||||
|
||||
applyDefaults(&c)
|
||||
|
||||
// 环境变量覆盖(优先级高于 config.yaml)
|
||||
applyEnvOverrides(&c)
|
||||
applyDefaults(&c)
|
||||
|
||||
// Disable standard DB/Redis initializations during tests to prevent connection attempts.
|
||||
if isTest() {
|
||||
@@ -98,6 +111,12 @@ func init() {
|
||||
printConfig(&c)
|
||||
}
|
||||
|
||||
func applyDefaults(c *configModel) {
|
||||
if c.App.SessionAge <= 0 {
|
||||
c.App.SessionAge = 86400
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 环境变量覆盖层 ────────────────────────────────────────────────────────────
|
||||
// 环境变量优先级高于 config.yaml,未设置则保留 yaml 中的值。
|
||||
|
||||
@@ -171,11 +190,19 @@ func applyEnvOverrides(c *configModel) {
|
||||
c.Database.LogLevel = envStr("DB_LOG_LEVEL", c.Database.LogLevel)
|
||||
c.Database.MaxIdleConn = envInt("DB_MAX_IDLE_CONN", c.Database.MaxIdleConn)
|
||||
c.Database.MaxOpenConn = envInt("DB_MAX_OPEN_CONN", c.Database.MaxOpenConn)
|
||||
// 当 DB_HOST 环境变量已设置时自动启用数据库
|
||||
if _, ok := os.LookupEnv("DB_HOST"); ok {
|
||||
c.Database.Enabled = true
|
||||
}
|
||||
c.Database.Enabled = envBool("DB_ENABLED", c.Database.Enabled)
|
||||
c.Database.SQLitePath = envStr("SQLITE_PATH", c.Database.SQLitePath)
|
||||
|
||||
// ─── Redis ───
|
||||
if v, ok := os.LookupEnv("REDIS_ADDR"); ok {
|
||||
c.Redis.Addrs = []string{v}
|
||||
c.Redis.Enabled = true // 当 REDIS_ADDR 已设置时自动启用
|
||||
}
|
||||
c.Redis.Enabled = envBool("REDIS_ENABLED", c.Redis.Enabled)
|
||||
c.Redis.Username = envStr("REDIS_USERNAME", c.Redis.Username)
|
||||
c.Redis.Password = envStr("REDIS_PASSWORD", c.Redis.Password)
|
||||
c.Redis.DB = envInt("REDIS_DB", c.Redis.DB)
|
||||
@@ -185,7 +212,9 @@ func applyEnvOverrides(c *configModel) {
|
||||
// ─── ClickHouse ───
|
||||
if v, ok := os.LookupEnv("CLICKHOUSE_HOST"); ok {
|
||||
c.ClickHouse.Hosts = []string{v}
|
||||
c.ClickHouse.Enabled = true
|
||||
}
|
||||
c.ClickHouse.Enabled = envBool("CLICKHOUSE_ENABLED", c.ClickHouse.Enabled)
|
||||
c.ClickHouse.Username = envStr("CLICKHOUSE_USERNAME", c.ClickHouse.Username)
|
||||
c.ClickHouse.Password = envStr("CLICKHOUSE_PASSWORD", c.ClickHouse.Password)
|
||||
c.ClickHouse.Database = envStr("CLICKHOUSE_NAME", c.ClickHouse.Database)
|
||||
@@ -206,14 +235,28 @@ func applyEnvOverrides(c *configModel) {
|
||||
c.S3.SecretAccessKey = envStr("S3_SECRET_ACCESS_KEY", c.S3.SecretAccessKey)
|
||||
c.S3.CdnURL = envStr("S3_CDN_URL", c.S3.CdnURL)
|
||||
c.S3.PathStyle = envBool("S3_PATH_STYLE", c.S3.PathStyle)
|
||||
c.S3.Enabled = envBool("S3_ENABLED", c.S3.Enabled)
|
||||
|
||||
// ─── Worker ───
|
||||
c.Worker.Concurrency = envInt("WORKER_CONCURRENCY", c.Worker.Concurrency)
|
||||
c.Worker.StrictPriority = envBool("WORKER_STRICT_PRIORITY", c.Worker.StrictPriority)
|
||||
|
||||
// 无 yaml 且无环境变量时,使用代码级默认队列
|
||||
if len(c.Worker.Queues) == 0 {
|
||||
c.Worker.Queues = []QueueConfig{
|
||||
{Name: "webhook", Priority: 10},
|
||||
{Name: "whitelist_only", Priority: 5},
|
||||
{Name: "default", Priority: 3},
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Scheduler ───
|
||||
c.Scheduler.CleanupUnusedUploadsTaskCron = envStr(
|
||||
"SCHEDULER_CLEANUP_CRON", c.Scheduler.CleanupUnusedUploadsTaskCron,
|
||||
)
|
||||
if c.Scheduler.CleanupUnusedUploadsTaskCron == "" {
|
||||
c.Scheduler.CleanupUnusedUploadsTaskCron = "@daily"
|
||||
}
|
||||
}
|
||||
|
||||
// printConfig 打印配置内容
|
||||
|
||||
@@ -55,6 +55,7 @@ func (a *appConfig) IsProduction() bool {
|
||||
// databaseConfig 数据库配置
|
||||
type databaseConfig struct {
|
||||
Enabled bool `mapstructure:"enabled"`
|
||||
SQLitePath string `mapstructure:"sqlite_path"` // PostgreSQL 禁用时的 SQLite 文件路径
|
||||
Host string `mapstructure:"host"`
|
||||
Port int `mapstructure:"port"`
|
||||
Username string `mapstructure:"username"`
|
||||
|
||||
@@ -29,11 +29,15 @@ import (
|
||||
"github.com/Rain-kl/Wavelet/internal/db/idgen"
|
||||
)
|
||||
|
||||
func Migrate() {
|
||||
// dbType 返回当前数据库类型名称(用于日志输出)
|
||||
func dbType() string {
|
||||
if !config.Config.Database.Enabled {
|
||||
return
|
||||
return "SQLite"
|
||||
}
|
||||
return "PostgreSQL"
|
||||
}
|
||||
|
||||
func Migrate() {
|
||||
if err := db.DB(context.Background()).AutoMigrate(
|
||||
&model.User{},
|
||||
&model.AuthSource{},
|
||||
@@ -44,9 +48,9 @@ func Migrate() {
|
||||
&model.TaskExecution{},
|
||||
&model.Template{},
|
||||
); err != nil {
|
||||
log.Fatalf("[PostgreSQL] auto migrate failed: %v\n", err)
|
||||
log.Fatalf("[%s] auto migrate failed: %v\n", dbType(), err)
|
||||
}
|
||||
log.Printf("[PostgreSQL] auto migrate success\n")
|
||||
log.Printf("[%s] auto migrate success\n", dbType())
|
||||
|
||||
// 初始化系统配置数据
|
||||
initSystemConfigs()
|
||||
@@ -68,9 +72,9 @@ func ensureConfigKeyExists(key, value, configType, description string) {
|
||||
Description: description,
|
||||
}
|
||||
if err := tx.Create(&newConfig).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to create system config key %s: %v\n", key, err)
|
||||
log.Printf("[%s] failed to create system config key %s: %v\n", dbType(), key, err)
|
||||
} else {
|
||||
log.Printf("[PostgreSQL] initialized system config key %s\n", key)
|
||||
log.Printf("[%s] initialized system config key %s\n", dbType(), key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +85,7 @@ func initSystemConfigs() {
|
||||
|
||||
var count int64
|
||||
if err := tx.Model(&model.SystemConfig{}).Count(&count).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to check system_config table: %v\n", err)
|
||||
log.Printf("[%s] failed to check system_config table: %v\n", dbType(), err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -240,9 +244,9 @@ func initSystemConfigs() {
|
||||
}
|
||||
|
||||
if err := tx.Create(&defaultConfigs).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to create default system configs: %v\n", err)
|
||||
log.Printf("[%s] failed to create default system configs: %v\n", dbType(), err)
|
||||
} else {
|
||||
log.Printf("[PostgreSQL] initialized %d default system configs\n", len(defaultConfigs))
|
||||
log.Printf("[%s] initialized %d default system configs\n", dbType(), len(defaultConfigs))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +256,7 @@ func initDefaultAdmin() {
|
||||
|
||||
var count int64
|
||||
if err := tx.Model(&model.User{}).Where("username = ?", "admin").Count(&count).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to check default admin user: %v\n", err)
|
||||
log.Printf("[%s] failed to check default admin user: %v\n", dbType(), err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -272,9 +276,9 @@ func initDefaultAdmin() {
|
||||
}
|
||||
|
||||
if err := tx.Create(&adminUser).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to create default admin user: %v\n", err)
|
||||
log.Printf("[%s] failed to create default admin user: %v\n", dbType(), err)
|
||||
} else {
|
||||
log.Printf("[PostgreSQL] default admin user created successfully (username: admin, password: 12345678)\n")
|
||||
log.Printf("[%s] default admin user created successfully (username: admin, password: 12345678)\n", dbType())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +287,7 @@ func initTemplates() {
|
||||
tx := db.DB(context.Background())
|
||||
var count int64
|
||||
if err := tx.Model(&model.Template{}).Count(&count).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to check templates table: %v\n", err)
|
||||
log.Printf("[%s] failed to check templates table: %v\n", dbType(), err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -314,9 +318,9 @@ func initTemplates() {
|
||||
var t model.Template
|
||||
if err := tx.Where("key = ?", dt.Key).First(&t).Error; err != nil {
|
||||
if err := tx.Create(&dt).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to create template key %s: %v\n", dt.Key, err)
|
||||
log.Printf("[%s] failed to create template key %s: %v\n", dbType(), dt.Key, err)
|
||||
} else {
|
||||
log.Printf("[PostgreSQL] initialized template key %s\n", dt.Key)
|
||||
log.Printf("[%s] initialized template key %s\n", dbType(), dt.Key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,8 +328,8 @@ func initTemplates() {
|
||||
}
|
||||
|
||||
if err := tx.Create(&defaultTemplates).Error; err != nil {
|
||||
log.Printf("[PostgreSQL] failed to create default templates: %v\n", err)
|
||||
log.Printf("[%s] failed to create default templates: %v\n", dbType(), err)
|
||||
} else {
|
||||
log.Printf("[PostgreSQL] initialized %d default templates\n", len(defaultTemplates))
|
||||
log.Printf("[%s] initialized %d default templates\n", dbType(), len(defaultTemplates))
|
||||
}
|
||||
}
|
||||
|
||||
+31
-1
@@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/config"
|
||||
"github.com/glebarez/sqlite"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
@@ -39,10 +40,39 @@ var (
|
||||
|
||||
func init() {
|
||||
if !config.Config.Database.Enabled {
|
||||
log.Println("[PostgreSQL] is disabled, skipping initialization")
|
||||
// PostgreSQL 禁用,使用 SQLite
|
||||
initSQLite()
|
||||
return
|
||||
}
|
||||
|
||||
initPostgres()
|
||||
}
|
||||
|
||||
// initSQLite 初始化 SQLite 数据库(PostgreSQL 禁用时的后备方案)
|
||||
func initSQLite() {
|
||||
sqlitePath := config.Config.Database.SQLitePath
|
||||
if sqlitePath == "" {
|
||||
sqlitePath = "./data/wavelet.db"
|
||||
}
|
||||
|
||||
var err error
|
||||
db, err = gorm.Open(sqlite.Open(sqlitePath), &gorm.Config{
|
||||
DisableForeignKeyConstraintWhenMigrating: true,
|
||||
Logger: &gormZapLogger{
|
||||
logLevel: parseLogLevel(config.Config.Database.LogLevel),
|
||||
slowThreshold: config.Config.Database.SlowThreshold,
|
||||
ignoreRecordNotFoundError: config.Config.App.IsProduction(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("[SQLite] init connection failed: %v\n", err)
|
||||
}
|
||||
|
||||
log.Printf("[SQLite] initialized (path: %s)\n", sqlitePath)
|
||||
}
|
||||
|
||||
// initPostgres 初始化 PostgreSQL 数据库
|
||||
func initPostgres() {
|
||||
var err error
|
||||
dbConfig := config.Config.Database
|
||||
|
||||
|
||||
Reference in New Issue
Block a user