package config import ( "io" "os" "path/filepath" "strings" "gopkg.in/yaml.v3" ) type DB struct { Host string `yaml:"host"` Port string `yaml:"port"` User string `yaml:"user"` Password string `yaml:"password"` Name string `yaml:"name"` } type App struct { Port string `yaml:"port"` MarketingDB DB `yaml:"marketing_db"` YMTDB DB `yaml:"ymt_db"` } type root struct { App App `yaml:"app"` } func Load() App { env := strings.ToLower(strings.TrimSpace(os.Getenv("APP_ENV"))) paths := []string{} if env != "" { paths = append(paths, "config."+env+".yaml", filepath.Join("server", "config."+env+".yaml"), ) } // no global fallback to config.yaml; rely on APP_ENV or environment variables var cfg App for _, p := range paths { if readYAML(p, &cfg) { break } } LoadEnv() if v := os.Getenv("MARKETING_DB_HOST"); v != "" { cfg.MarketingDB.Host = v } if v := os.Getenv("MARKETING_DB_PORT"); v != "" { cfg.MarketingDB.Port = v } if v := os.Getenv("MARKETING_DB_USER"); v != "" { cfg.MarketingDB.User = v } if v := os.Getenv("MARKETING_DB_PASSWORD"); v != "" { cfg.MarketingDB.Password = v } if v := os.Getenv("MARKETING_DB_NAME"); v != "" { cfg.MarketingDB.Name = v } if v := os.Getenv("YMT_DB_HOST"); v != "" { cfg.YMTDB.Host = v } if v := os.Getenv("YMT_DB_PORT"); v != "" { cfg.YMTDB.Port = v } if v := os.Getenv("YMT_DB_USER"); v != "" { cfg.YMTDB.User = v } if v := os.Getenv("YMT_DB_PASSWORD"); v != "" { cfg.YMTDB.Password = v } if v := os.Getenv("YMT_DB_NAME"); v != "" { cfg.YMTDB.Name = v } return cfg } func readYAML(path string, out *App) bool { f, err := os.Open(path) if err != nil { return false } defer f.Close() b, err := io.ReadAll(f) if err != nil { return false } var r root if err := yaml.Unmarshal(b, &r); err == nil { if r.App.Port != "" || r.App.MarketingDB.Host != "" || r.App.YMTDB.Host != "" { *out = r.App return true } } if err := yaml.Unmarshal(b, out); err != nil { return false } return true } func (d DB) DSN() string { if strings.TrimSpace(d.User) == "" || strings.TrimSpace(d.Host) == "" || strings.TrimSpace(d.Port) == "" || strings.TrimSpace(d.Name) == "" { return "" } return d.User + ":" + d.Password + "@tcp(" + d.Host + ":" + d.Port + ")/" + d.Name + "?parseTime=True&loc=Local&charset=utf8mb4" } func LoadEnv() { env := strings.ToLower(strings.TrimSpace(os.Getenv("APP_ENV"))) paths := []string{} if env != "" { paths = append(paths, ".env."+env, filepath.Join("server", ".env."+env), ) } paths = append(paths, ".env.local", filepath.Join("server", ".env.local"), ) for _, p := range paths { f, err := os.Open(p) if err != nil { continue } b, err := io.ReadAll(f) f.Close() if err != nil { continue } lines := strings.Split(string(b), "\n") for _, ln := range lines { s := strings.TrimSpace(ln) if s == "" || strings.HasPrefix(s, "#") { continue } kv := strings.SplitN(s, "=", 2) if len(kv) != 2 { continue } k := strings.TrimSpace(kv[0]) v := strings.TrimSpace(kv[1]) if k != "" { os.Setenv(k, v) } } break } }