数据库+redis+meilisearch+s3+EQURL 配置全部走环境变量,不在代码层硬编码

This commit is contained in:
eafonyang
2026-07-13 14:16:05 +08:00
parent c1547f9a8f
commit 4f1da3675b
9 changed files with 80 additions and 215 deletions
+31 -20
View File
@@ -1,35 +1,46 @@
# Server # Server
APP_ENV=development APP_ENV=production
APP_HOST=0.0.0.0 APP_HOST=0.0.0.0
APP_PORT=8080 APP_PORT=8080
# Gin mode: debug | release | test # Gin mode: debug | release | test
GIN_MODE=debug GIN_MODE=release
# Database (development reads from env, default host 192.168.9.127) # Database
DATABASE_HOST=192.168.9.127 DATABASE_HOST=database-1.chmuueamo72p.eu-central-1.rds.amazonaws.com
DATABASE_PORT=3306 DATABASE_PORT=3306
DATABASE_NAME=audio DATABASE_NAME=audio
DATABASE_USER=root DATABASE_USER=root
DATABASE_PASSWORD=root123 DATABASE_PASSWORD="young9#!UJsD219921031"
# Meilisearch (development defaults apply when APP_ENV=development and vars are unset) # Meilisearch
# MEILISEARCH_HOST=http://ec2-18-184-205-87.eu-central-1.compute.amazonaws.com:7700 MEILISEARCH_HOST=http://ip-172-31-13-240.eu-central-1.compute.internal:7700
# MEILISEARCH_API_KEY=your-api-key MEILISEARCH_API_KEY="young9#!UJsD219921031"
# MEILISEARCH_INDEX=models MEILISEARCH_INDEX=models
# Redis (development reads from env, default host 192.168.9.127) # Redis
REDIS_HOST=192.168.9.127 REDIS_HOST=172.31.13.240
REDIS_PORT=6379 REDIS_PORT=6379
REDIS_PASSWORD= REDIS_PASSWORD=eafon123!
REDIS_DATABASE=1 REDIS_DATABASE=1
# Share code TTL (bare number = minutes; suffix: m/h/d), e.g. 30, 30m, 24h, 30d # Equalize API
SHARE_CODE_TTL_MIN=30 EQ_API_URL=http://172.31.18.70:8000/equalize
# SHARE_CODE_MAX_PER_MAC=1 EQ_EXTERNAL_API_URL=https://autoeq.app/equalize
# S3 (local development only; production uses EC2 IAM role) # Share code TTL (bare number = minutes; suffix: m/h/d), e.g. 30, 30m, 24h, 30d
# AWS_REGION=eu-central-1 #一个用户在有效期内至多可以创建多少个分享码
# S3_BUCKET=luxsin-app-bucket SHARE_CODE_MAX_PER_MAC=10
# AWS_ACCESS_KEY_ID=your-access-key-id #分享码有效期
# AWS_SECRET_ACCESS_KEY=your-secret-access-key SHARE_CODE_TTL_MIN=30d
# S3 (生产环境使用 EC2 IAM role 时,可不设置 AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)
AWS_REGION=eu-central-1
S3_BUCKET=luxsin-app-bucket
AWS_ACCESS_KEY_ID=AKIAVMFK45I6P3TNI3VJ
AWS_SECRET_ACCESS_KEY=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
# Persist tasks
ENABLE_PERSIST_TASK=false
ENABLE_IMPEDANCE_PERSIST_TASK=false
-19
View File
@@ -1,19 +0,0 @@
APP_ENV=production
APP_HOST=0.0.0.0
APP_PORT=8080
GIN_MODE=release
# Production uses built-in RDS host when DATABASE_HOST is unset.
# Password must be set via environment variable (never commit real password).
# jdbc:mysql://database-1.chmuueamo72p.eu-central-1.rds.amazonaws.com:3306/audio?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
# young9#!UJsD219921031
# root
DATABASE_PASSWORD=your-production-password
# S3 (uses EC2 IAM role; do not set access keys in production)
AWS_REGION=eu-central-1
S3_BUCKET=luxsin-app-bucket
# Share code TTL (bare number = minutes; suffix: m/h/d), e.g. 30, 30m, 24h, 30d
SHARE_CODE_TTL_MIN=30
+2 -13
View File
@@ -7,19 +7,8 @@ services:
restart: always restart: always
ports: ports:
- "8084:8080" - "8084:8080"
environment: env_file:
- APP_ENV=production - .env
- APP_HOST=0.0.0.0
- APP_PORT=8080
- DATABASE_PASSWORD=${DATABASE_PASSWORD}
- REDIS_PASSWORD=${REDIS_PASSWORD:-eafon123!}
- MEILISEARCH_API_KEY=${MEILISEARCH_API_KEY:-young9#!UJsD219921031}
- ENABLE_PERSIST_TASK=false
- ENABLE_IMPEDANCE_PERSIST_TASK=false
- AWS_REGION=eu-central-1
- S3_BUCKET=luxsin-app-bucket
- SHARE_CODE_MAX_PER_MAC=${SHARE_CODE_MAX_PER_MAC:-1}
- SHARE_CODE_TTL_MIN=${SHARE_CODE_TTL_MIN:-30}
healthcheck: healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8080/api/v1/health"] test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8080/api/v1/health"]
interval: 30s interval: 30s
+24 -24
View File
@@ -8,18 +8,18 @@ import (
) )
type Config struct { type Config struct {
Env string Env string
Host string Host string
Port int Port int
Database DatabaseConfig Database DatabaseConfig
Meilisearch MeilisearchConfig Meilisearch MeilisearchConfig
Redis RedisConfig Redis RedisConfig
Equalize EqualizeConfig Equalize EqualizeConfig
S3 S3Config S3 S3Config
EnablePersistTask bool EnablePersistTask bool
EnableImpedancePersistTask bool EnableImpedancePersistTask bool
ShareCodeMaxPerMac int ShareCodeMaxPerMac int
ShareCodeTTL time.Duration ShareCodeTTL time.Duration
} }
func Load() (*Config, error) { func Load() (*Config, error) {
@@ -30,26 +30,26 @@ func Load() (*Config, error) {
env := getEnv("APP_ENV", "development") env := getEnv("APP_ENV", "development")
db, err := loadDatabase(env) db, err := loadDatabase()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := db.validate(env); err != nil { if err := db.validate(); err != nil {
return nil, err return nil, err
} }
ms := loadMeilisearch(env) ms := loadMeilisearch()
if err := ms.validate(); err != nil { if err := ms.validate(); err != nil {
return nil, err return nil, err
} }
rd := loadRedis(env) rd := loadRedis()
if err := rd.validate(); err != nil { if err := rd.validate(); err != nil {
return nil, err return nil, err
} }
eq := loadEqualize(env) eq := loadEqualize()
s3cfg := loadS3(env) s3cfg := loadS3()
shareCodeTTL, err := parseShareCodeTTL(getEnv("SHARE_CODE_TTL_MIN", "30")) shareCodeTTL, err := parseShareCodeTTL(getEnv("SHARE_CODE_TTL_MIN", "30"))
if err != nil { if err != nil {
@@ -57,18 +57,18 @@ func Load() (*Config, error) {
} }
return &Config{ return &Config{
Env: env, Env: env,
Host: getEnv("APP_HOST", "0.0.0.0"), Host: getEnv("APP_HOST", "0.0.0.0"),
Port: port, Port: port,
Database: db, Database: db,
Meilisearch: ms, Meilisearch: ms,
Redis: rd, Redis: rd,
Equalize: eq, Equalize: eq,
S3: s3cfg, S3: s3cfg,
EnablePersistTask: getEnv("ENABLE_PERSIST_TASK", "false") == "true", EnablePersistTask: getEnv("ENABLE_PERSIST_TASK", "false") == "true",
EnableImpedancePersistTask: getEnv("ENABLE_IMPEDANCE_PERSIST_TASK", "false") == "true", EnableImpedancePersistTask: getEnv("ENABLE_IMPEDANCE_PERSIST_TASK", "false") == "true",
ShareCodeMaxPerMac: getEnvInt("SHARE_CODE_MAX_PER_MAC", 1), ShareCodeMaxPerMac: getEnvInt("SHARE_CODE_MAX_PER_MAC", 1),
ShareCodeTTL: shareCodeTTL, ShareCodeTTL: shareCodeTTL,
}, nil }, nil
} }
+4 -37
View File
@@ -2,7 +2,6 @@ package config
import ( import (
"fmt" "fmt"
"os"
"strconv" "strconv"
) )
@@ -14,50 +13,21 @@ type DatabaseConfig struct {
Password string Password string
} }
func loadDatabase(env string) (DatabaseConfig, error) { func loadDatabase() (DatabaseConfig, error) {
switch env {
case "production":
if os.Getenv("DATABASE_HOST") != "" {
return databaseFromEnv()
}
return DatabaseConfig{
Host: "database-1.chmuueamo72p.eu-central-1.rds.amazonaws.com",
Port: 3306,
Name: "audio",
User: "root",
Password: os.Getenv("DATABASE_PASSWORD"),
}, nil
default:
port, err := strconv.Atoi(getEnv("DATABASE_PORT", "3306"))
if err != nil {
return DatabaseConfig{}, fmt.Errorf("invalid DATABASE_PORT: %w", err)
}
return DatabaseConfig{
Host: getEnv("DATABASE_HOST", "192.168.9.127"),
Port: port,
Name: getEnv("DATABASE_NAME", "audio"),
User: getEnv("DATABASE_USER", "root"),
Password: getEnv("DATABASE_PASSWORD", "root123"),
}, nil
}
}
func databaseFromEnv() (DatabaseConfig, error) {
port, err := strconv.Atoi(getEnv("DATABASE_PORT", "3306")) port, err := strconv.Atoi(getEnv("DATABASE_PORT", "3306"))
if err != nil { if err != nil {
return DatabaseConfig{}, fmt.Errorf("invalid DATABASE_PORT: %w", err) return DatabaseConfig{}, fmt.Errorf("invalid DATABASE_PORT: %w", err)
} }
return DatabaseConfig{ return DatabaseConfig{
Host: os.Getenv("DATABASE_HOST"), Host: getEnv("DATABASE_HOST", ""),
Port: port, Port: port,
Name: getEnv("DATABASE_NAME", "audio"), Name: getEnv("DATABASE_NAME", "audio"),
User: getEnv("DATABASE_USER", "root"), User: getEnv("DATABASE_USER", "root"),
Password: os.Getenv("DATABASE_PASSWORD"), Password: getEnv("DATABASE_PASSWORD", ""),
}, nil }, nil
} }
func (d DatabaseConfig) validate(env string) error { func (d DatabaseConfig) validate() error {
if d.Host == "" { if d.Host == "" {
return fmt.Errorf("database host is required") return fmt.Errorf("database host is required")
} }
@@ -67,8 +37,5 @@ func (d DatabaseConfig) validate(env string) error {
if d.User == "" { if d.User == "" {
return fmt.Errorf("database user is required") return fmt.Errorf("database user is required")
} }
if env == "production" && d.Password == "" {
return fmt.Errorf("DATABASE_PASSWORD is required in production")
}
return nil return nil
} }
+4 -24
View File
@@ -1,33 +1,13 @@
package config package config
import "os"
const defaultExternalEQAPIURL = "https://autoeq.app/equalize"
type EqualizeConfig struct { type EqualizeConfig struct {
APIURL string // 内网 EQ 接口(正式环境 Eafonyoung 源使用) APIURL string // 内网 EQ 接口(正式环境 Eafonyoung 源使用)
ExternalAPIURL string // 公网 EQ 接口(正式环境非 Eafonyoung 源使用) ExternalAPIURL string // 公网 EQ 接口(正式环境非 Eafonyoung 源使用)
} }
func loadEqualize(env string) EqualizeConfig { func loadEqualize() EqualizeConfig {
external := getEnv("EQ_EXTERNAL_API_URL", defaultExternalEQAPIURL) return EqualizeConfig{
if os.Getenv("EQ_API_URL") != "" { APIURL: getEnv("EQ_API_URL", ""),
return EqualizeConfig{ ExternalAPIURL: getEnv("EQ_EXTERNAL_API_URL", "https://autoeq.app/equalize"),
APIURL: os.Getenv("EQ_API_URL"),
ExternalAPIURL: external,
}
}
switch env {
case "production":
return EqualizeConfig{
APIURL: "http://172.31.18.70:8000/equalize",
ExternalAPIURL: external,
}
default:
return EqualizeConfig{
APIURL: defaultExternalEQAPIURL,
ExternalAPIURL: external,
}
} }
} }
+5 -23
View File
@@ -2,7 +2,6 @@ package config
import ( import (
"fmt" "fmt"
"os"
) )
type MeilisearchConfig struct { type MeilisearchConfig struct {
@@ -11,28 +10,11 @@ type MeilisearchConfig struct {
Index string Index string
} }
func loadMeilisearch(env string) MeilisearchConfig { func loadMeilisearch() MeilisearchConfig {
if os.Getenv("MEILISEARCH_HOST") != "" { return MeilisearchConfig{
return MeilisearchConfig{ Host: getEnv("MEILISEARCH_HOST", ""),
Host: os.Getenv("MEILISEARCH_HOST"), APIKey: getEnv("MEILISEARCH_API_KEY", ""),
APIKey: os.Getenv("MEILISEARCH_API_KEY"), Index: getEnv("MEILISEARCH_INDEX", "models"),
Index: getEnv("MEILISEARCH_INDEX", "models"),
}
}
switch env {
case "production":
return MeilisearchConfig{
Host: "http://ip-172-31-22-170.eu-central-1.compute.internal:7700",
APIKey: getEnv("MEILISEARCH_API_KEY", "young9#!UJsD219921031"),
Index: "models",
}
default:
return MeilisearchConfig{
Host: "http://ec2-18-184-205-87.eu-central-1.compute.amazonaws.com:7700",
APIKey: getEnv("MEILISEARCH_API_KEY", "young9#!UJsD219921031"),
Index: "models",
}
} }
} }
+4 -30
View File
@@ -2,7 +2,6 @@ package config
import ( import (
"fmt" "fmt"
"os"
"strconv" "strconv"
) )
@@ -13,38 +12,13 @@ type RedisConfig struct {
Database int Database int
} }
func loadRedis(env string) RedisConfig { func loadRedis() RedisConfig {
switch env { port, _ := strconv.Atoi(getEnv("REDIS_PORT", "6379"))
case "production":
if os.Getenv("REDIS_HOST") != "" {
return redisFromEnv("16279")
}
return RedisConfig{
Host: "172.31.38.162",
Port: 16279,
Password: getEnv("REDIS_PASSWORD", "eafon123!"),
Database: 1,
}
default:
port, _ := strconv.Atoi(getEnv("REDIS_PORT", "6379"))
db, _ := strconv.Atoi(getEnv("REDIS_DATABASE", "1"))
return RedisConfig{
Host: getEnv("REDIS_HOST", "192.168.9.127"),
Port: port,
Password: getEnv("REDIS_PASSWORD", ""),
Database: db,
}
}
}
func redisFromEnv(defaultPort string) RedisConfig {
port, _ := strconv.Atoi(getEnv("REDIS_PORT", defaultPort))
db, _ := strconv.Atoi(getEnv("REDIS_DATABASE", "1")) db, _ := strconv.Atoi(getEnv("REDIS_DATABASE", "1"))
return RedisConfig{ return RedisConfig{
Host: os.Getenv("REDIS_HOST"), Host: getEnv("REDIS_HOST", ""),
Port: port, Port: port,
Password: os.Getenv("REDIS_PASSWORD"), Password: getEnv("REDIS_PASSWORD", ""),
Database: db, Database: db,
} }
} }
+6 -25
View File
@@ -1,7 +1,5 @@
package config package config
import "os"
type S3Config struct { type S3Config struct {
Bucket string Bucket string
Region string Region string
@@ -9,28 +7,11 @@ type S3Config struct {
SecretAccessKey string SecretAccessKey string
} }
func loadS3(env string) S3Config { func loadS3() S3Config {
if os.Getenv("AWS_ACCESS_KEY_ID") != "" || os.Getenv("AWS_SECRET_ACCESS_KEY") != "" { return S3Config{
return S3Config{ Bucket: getEnv("S3_BUCKET", ""),
Bucket: getEnv("S3_BUCKET", "luxsin-app-bucket"), Region: getEnv("AWS_REGION", "eu-central-1"),
Region: getEnv("AWS_REGION", "eu-central-1"), AccessKeyID: getEnv("AWS_ACCESS_KEY_ID", ""),
AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"), SecretAccessKey: getEnv("AWS_SECRET_ACCESS_KEY", ""),
SecretAccessKey: os.Getenv("AWS_SECRET_ACCESS_KEY"),
}
}
switch env {
case "production":
return S3Config{
Bucket: getEnv("S3_BUCKET", "luxsin-app-bucket"),
Region: getEnv("AWS_REGION", "eu-central-1"),
}
default:
return S3Config{
Bucket: getEnv("S3_BUCKET", "luxsin-app-bucket"),
Region: getEnv("AWS_REGION", "eu-central-1"),
AccessKeyID: "AKIAVMFK45I6P3TNI3VJ",
SecretAccessKey: "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",
}
} }
} }