package config import ( "fmt" "os" "strconv" "time" ) type Config struct { Env string Host string Port int Database DatabaseConfig Meilisearch MeilisearchConfig Redis RedisConfig Equalize EqualizeConfig S3 S3Config EnablePersistTask bool EnableImpedancePersistTask bool ShareCodeMaxPerMac int ShareCodeTTL time.Duration } func Load() (*Config, error) { port, err := strconv.Atoi(getEnv("APP_PORT", "8080")) if err != nil { return nil, fmt.Errorf("invalid APP_PORT: %w", err) } env := getEnv("APP_ENV", "development") db, err := loadDatabase() if err != nil { return nil, err } if err := db.validate(); err != nil { return nil, err } ms := loadMeilisearch() if err := ms.validate(); err != nil { return nil, err } rd := loadRedis() if err := rd.validate(); err != nil { return nil, err } eq := loadEqualize() s3cfg := loadS3() shareCodeTTL, err := parseShareCodeTTL(getEnv("SHARE_CODE_TTL_MIN", "30")) if err != nil { return nil, fmt.Errorf("invalid SHARE_CODE_TTL_MIN: %w", err) } return &Config{ Env: env, Host: getEnv("APP_HOST", "0.0.0.0"), Port: port, Database: db, Meilisearch: ms, Redis: rd, Equalize: eq, S3: s3cfg, EnablePersistTask: getEnv("ENABLE_PERSIST_TASK", "false") == "true", EnableImpedancePersistTask: getEnv("ENABLE_IMPEDANCE_PERSIST_TASK", "false") == "true", ShareCodeMaxPerMac: getEnvInt("SHARE_CODE_MAX_PER_MAC", 1), ShareCodeTTL: shareCodeTTL, }, nil } func (c *Config) Addr() string { return fmt.Sprintf("%s:%d", c.Host, c.Port) } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func getEnvInt(key string, fallback int) int { v := os.Getenv(key) if v == "" { return fallback } n, err := strconv.Atoi(v) if err != nil { return fallback } return n }