add service
This commit is contained in:
111
internal/config/config.go
Normal file
111
internal/config/config.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
AI AIConfig `yaml:"ai"`
|
||||
Security SecurityConfig `yaml:"security"`
|
||||
GRPC GRPCConfig `yaml:"grpc"`
|
||||
Logging LoggingConfig `yaml:"logging"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Host string `yaml:"host"`
|
||||
Port int `yaml:"port"`
|
||||
Name string `yaml:"name"`
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
SSLMode string `yaml:"ssl_mode"`
|
||||
MaxConns int `yaml:"max_conns"`
|
||||
MinConns int `yaml:"min_conns"`
|
||||
}
|
||||
|
||||
type AIConfig struct {
|
||||
OpenAIKey string `yaml:"openai_key"`
|
||||
PerplexityKey string `yaml:"perplexity_key"`
|
||||
}
|
||||
|
||||
type SecurityConfig struct {
|
||||
JWTSecret string `yaml:"jwt_secret"`
|
||||
CryptoSecret string `yaml:"crypto_secret"`
|
||||
}
|
||||
|
||||
type GRPCConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
MaxConnections int `yaml:"max_connections"`
|
||||
}
|
||||
|
||||
type LoggingConfig struct {
|
||||
Level string `yaml:"level"`
|
||||
}
|
||||
|
||||
func Load(path string) (*Config, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
|
||||
data = []byte(expandEnvWithDefaults(string(data)))
|
||||
|
||||
var cfg Config
|
||||
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||
}
|
||||
|
||||
if err := cfg.validate(); err != nil {
|
||||
return nil, fmt.Errorf("invalid config: %w", err)
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func expandEnvWithDefaults(s string) string {
|
||||
re := regexp.MustCompile(`\$\{([^:}]+):([^}]*)\}`)
|
||||
result := re.ReplaceAllStringFunc(s, func(match string) string {
|
||||
parts := re.FindStringSubmatch(match)
|
||||
if len(parts) != 3 {
|
||||
return match
|
||||
}
|
||||
envVar := parts[1]
|
||||
defaultVal := parts[2]
|
||||
if val := os.Getenv(envVar); val != "" {
|
||||
return val
|
||||
}
|
||||
return defaultVal
|
||||
})
|
||||
return os.ExpandEnv(result)
|
||||
}
|
||||
|
||||
func (c *Config) validate() error {
|
||||
if c.Database.Host == "" {
|
||||
return fmt.Errorf("database host is required")
|
||||
}
|
||||
if c.Database.Name == "" {
|
||||
return fmt.Errorf("database name is required")
|
||||
}
|
||||
if c.Database.User == "" {
|
||||
return fmt.Errorf("database user is required")
|
||||
}
|
||||
if c.Database.Password == "" {
|
||||
return fmt.Errorf("database password is required")
|
||||
}
|
||||
if c.Security.JWTSecret == "" {
|
||||
return fmt.Errorf("JWT secret is required")
|
||||
}
|
||||
if c.Security.CryptoSecret == "" {
|
||||
return fmt.Errorf("crypto secret is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) DatabaseURL() string {
|
||||
return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s",
|
||||
c.Database.User, c.Database.Password, c.Database.Host, c.Database.Port, c.Database.Name, c.Database.SSLMode)
|
||||
}
|
||||
Reference in New Issue
Block a user