package config import ( "encoding/json" "github.com/joho/godotenv" "log/slog" "os" "regexp" "yobbly-gateway-go/internal/logger" "gopkg.in/yaml.v3" ) // Backend представляет собой отдельный сервер бэкенда. type Backend struct { URL string `json:"url"` Role string `json:"role"` AllowSelfSigned bool `json:"allow_self_signed"` } // Routes сопоставляет строки версий с префиксами маршрутов и бэкендами. type Routes map[string]map[string][]Backend // ServerConfig содержит настройки, связанные с сервером. type ServerConfig struct { Host string `yaml:"host"` Port string `yaml:"port"` } // GatewayConfig содержит настройки, специфичные для шлюза. type GatewayConfig struct { RouteFile string `yaml:"route_file"` GeoIPDB string `yaml:"geoip_db"` BlockedCountries []string `yaml:"blocked_countries"` } // TLSConfig содержит настройки, связанные с TLS. type TLSConfig struct { FullChain string `yaml:"full_chain"` PrivateKey string `yaml:"private_key"` } // LogConfig содержит настройки, связанные с логированием. type LogConfig struct { Level string `yaml:"level"` Format string `yaml:"format"` } // Settings содержит всю конфигурацию приложения. type Settings struct { Server ServerConfig `yaml:"server"` Gateway GatewayConfig `yaml:"gateway"` TLS TLSConfig `yaml:"tls"` Logging LogConfig `yaml:"logging"` RouteConfig Routes `yaml:"-"` // Загружается отдельно, не из корня YAML } // Load возвращает новый объект конфигурации, считывая YAML-файл. func Load(configPath string) (*Settings, error) { op := "config.Load" log := logger.NewLoggerWithOp(op) if err := godotenv.Load(); err != nil { log.Warn("[Attention]: No .env file found or failed to load, using STANDARD settings!") } configFile, err := os.ReadFile(configPath) if err != nil { log.Error("failed to read config file", slog.String("path", configPath), slog.Any("error", err)) return nil, err } processed := replaceEnvVars(string(configFile)) var settings Settings if err := yaml.Unmarshal([]byte(processed), &settings); err != nil { log.Error("failed to unmarshal config file", slog.String("path", configPath), slog.Any("error", err)) return nil, err } // Загружаем маршруты из JSON-файла routeFile, err := os.ReadFile(settings.Gateway.RouteFile) if err != nil { log.Error("failed to read route file", slog.String("path", settings.Gateway.RouteFile), slog.Any("error", err)) return nil, err } var routes Routes if err := json.Unmarshal(routeFile, &routes); err != nil { log.Error("failed to unmarshal route file", slog.String("path", settings.Gateway.RouteFile), slog.Any("error", err)) return nil, err } settings.RouteConfig = routes return &settings, nil } // replaceEnvVars Поддержка ${ENV_VAR:default} AKA SpringBoot func replaceEnvVars(input string) string { re := regexp.MustCompile(`\$\{([^}:\s]+)(?::([^}]*))?\}`) return re.ReplaceAllStringFunc(input, func(s string) string { matches := re.FindStringSubmatch(s) envVar := matches[1] defVal := matches[2] val := os.Getenv(envVar) if val == "" { val = defVal } return val }) }