112 lines
3.4 KiB
Go
112 lines
3.4 KiB
Go
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
|
||
})
|
||
}
|