- Backend: Go API server with Gin framework - Frontend: React setup (placeholder) - ML Service: Python FastAPI skeleton - Docker Compose: Full stack configuration - Database: PostgreSQL schema with migrations - Documentation: Implementation plan and README Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
107 lines
2.8 KiB
Go
107 lines
2.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type Config struct {
|
|
Server ServerConfig `yaml:"server"`
|
|
Database DatabaseConfig `yaml:"database"`
|
|
VictoriaLogs VictoriaLogsConfig `yaml:"victorialogs"`
|
|
VMAlert VMAlertConfig `yaml:"vmalert"`
|
|
MLService MLServiceConfig `yaml:"ml_service"`
|
|
Auth AuthConfig `yaml:"auth"`
|
|
RateLimiting RateLimitingConfig `yaml:"rate_limiting"`
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Port int `yaml:"port"`
|
|
ReadTimeout time.Duration `yaml:"read_timeout"`
|
|
WriteTimeout time.Duration `yaml:"write_timeout"`
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Host string `yaml:"host"`
|
|
Port int `yaml:"port"`
|
|
Name string `yaml:"name"`
|
|
User string `yaml:"user"`
|
|
Password string `yaml:"password"`
|
|
MaxConnections int `yaml:"max_connections"`
|
|
}
|
|
|
|
type VictoriaLogsConfig struct {
|
|
URL string `yaml:"url"`
|
|
Timeout time.Duration `yaml:"timeout"`
|
|
MaxQuerySize int `yaml:"max_query_size"`
|
|
}
|
|
|
|
type VMAlertConfig struct {
|
|
URL string `yaml:"url"`
|
|
RulesDir string `yaml:"rules_dir"`
|
|
ReloadEndpoint string `yaml:"reload_endpoint"`
|
|
}
|
|
|
|
type MLServiceConfig struct {
|
|
URL string `yaml:"url"`
|
|
Timeout time.Duration `yaml:"timeout"`
|
|
}
|
|
|
|
type AuthConfig struct {
|
|
JWTSecret string `yaml:"jwt_secret"`
|
|
AccessTokenDuration time.Duration `yaml:"access_token_duration"`
|
|
RefreshTokenDuration time.Duration `yaml:"refresh_token_duration"`
|
|
}
|
|
|
|
type RateLimitingConfig struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
RequestsPerMinute map[string]int `yaml:"requests_per_minute"`
|
|
}
|
|
|
|
// Load loads configuration from YAML file and environment variables
|
|
func Load(configPath string) (*Config, error) {
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read config file: %w", err)
|
|
}
|
|
|
|
// Expand environment variables in config
|
|
expandedData := []byte(os.ExpandEnv(string(data)))
|
|
|
|
var cfg Config
|
|
if err := yaml.Unmarshal(expandedData, &cfg); err != nil {
|
|
return nil, fmt.Errorf("failed to parse config: %w", err)
|
|
}
|
|
|
|
// Validate required fields
|
|
if err := cfg.validate(); err != nil {
|
|
return nil, fmt.Errorf("config validation failed: %w", err)
|
|
}
|
|
|
|
return &cfg, nil
|
|
}
|
|
|
|
func (c *Config) validate() error {
|
|
if c.Database.Password == "" {
|
|
return fmt.Errorf("database password is required")
|
|
}
|
|
if c.Auth.JWTSecret == "" {
|
|
return fmt.Errorf("JWT secret is required")
|
|
}
|
|
if len(c.Auth.JWTSecret) < 32 {
|
|
return fmt.Errorf("JWT secret must be at least 32 characters")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetDSN returns the PostgreSQL connection string
|
|
func (c *DatabaseConfig) GetDSN() string {
|
|
return fmt.Sprintf(
|
|
"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
|
c.Host, c.Port, c.User, c.Password, c.Name,
|
|
)
|
|
}
|