✨ Upgrade Go version to 1.23.0 and update dependencies. Introduce new application structure with Clean Architecture principles, including message processing, NATS integration, and PostgreSQL repository. Add configuration management using Koanf and structured logging with Zap. Remove legacy GraphQL integration and related files. Implement dependency injection with Google Wire.
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/knadh/koanf/parsers/toml"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
envprovider "github.com/knadh/koanf/providers/env"
|
||||
)
|
||||
|
||||
// Config holds all application configuration
|
||||
type Config struct {
|
||||
NATS NATSConfig `koanf:"nats"`
|
||||
Postgres PostgresConfig `koanf:"postgres"`
|
||||
App AppConfig `koanf:"app"`
|
||||
Log LogConfig `koanf:"log"`
|
||||
Publisher PublisherConfig `koanf:"publisher"`
|
||||
// Legacy fields for backward compatibility during migration
|
||||
Subscription SubscriptionConfig `koanf:"subscription"`
|
||||
Timeouts TimeoutsConfig `koanf:"timeouts"`
|
||||
}
|
||||
|
||||
// NATSConfig holds NATS/JetStream configuration
|
||||
type NATSConfig struct {
|
||||
URL string `koanf:"url"`
|
||||
Stream string `koanf:"stream"`
|
||||
Consumer string `koanf:"consumer"`
|
||||
// Legacy fields
|
||||
Client string `koanf:"client"`
|
||||
Cluster string `koanf:"cluster"`
|
||||
}
|
||||
|
||||
// PostgresConfig holds PostgreSQL configuration
|
||||
type PostgresConfig struct {
|
||||
URL string `koanf:"url"`
|
||||
MaxConns int32 `koanf:"max_conns"`
|
||||
MinConns int32 `koanf:"min_conns"`
|
||||
}
|
||||
|
||||
// AppConfig holds application-level configuration
|
||||
type AppConfig struct {
|
||||
BatchSize int `koanf:"batch_size"`
|
||||
BatchTimeout time.Duration `koanf:"batch_timeout"`
|
||||
}
|
||||
|
||||
// LogConfig holds logging configuration
|
||||
type LogConfig struct {
|
||||
Level string `koanf:"level"`
|
||||
Format string `koanf:"format"` // json or console
|
||||
}
|
||||
|
||||
// PublisherConfig holds publisher configuration
|
||||
type PublisherConfig struct {
|
||||
Topic string `koanf:"topic"`
|
||||
}
|
||||
|
||||
// SubscriptionConfig holds subscription configuration (legacy)
|
||||
type SubscriptionConfig struct {
|
||||
Topic string `koanf:"topic"`
|
||||
QueueGroup string `koanf:"queue_group"`
|
||||
}
|
||||
|
||||
// TimeoutsConfig holds timeout configuration (legacy)
|
||||
type TimeoutsConfig struct {
|
||||
Server time.Duration `koanf:"server"`
|
||||
ReconnectWait time.Duration `koanf:"reconnect_wait"`
|
||||
Close time.Duration `koanf:"close"`
|
||||
AckWait time.Duration `koanf:"ack_wait"`
|
||||
}
|
||||
|
||||
// LoadConfig loads configuration from file and environment variables
|
||||
func LoadConfig() (*Config, error) {
|
||||
k := koanf.New(".")
|
||||
|
||||
// Determine environment
|
||||
env := os.Getenv("GO_ENV")
|
||||
if env == "" {
|
||||
env = "dev"
|
||||
}
|
||||
|
||||
// Load from TOML file
|
||||
configFile := fmt.Sprintf("configs/config.%s.toml", env)
|
||||
if err := k.Load(file.Provider(configFile), toml.Parser()); err != nil {
|
||||
return nil, fmt.Errorf("error loading config file '%s': %w", configFile, err)
|
||||
}
|
||||
|
||||
// Load from environment variables with CAATSM_ prefix
|
||||
envProvider := envprovider.Provider("CAATSM_", ".", func(s string) string {
|
||||
// Convert CAATSM_NATS_URL to nats.url
|
||||
s = strings.TrimPrefix(s, "CAATSM_")
|
||||
return strings.ToLower(strings.ReplaceAll(s, "_", "."))
|
||||
})
|
||||
if err := k.Load(envProvider, nil); err != nil {
|
||||
// Environment variables are optional, so we don't fail if they're not present
|
||||
// This allows the config to work with just the file
|
||||
}
|
||||
|
||||
// Unmarshal into Config struct
|
||||
var cfg Config
|
||||
if err := k.Unmarshal("", &cfg); err != nil {
|
||||
return nil, fmt.Errorf("error unmarshaling config: %w", err)
|
||||
}
|
||||
|
||||
// Set defaults
|
||||
if cfg.App.BatchSize == 0 {
|
||||
cfg.App.BatchSize = 50
|
||||
}
|
||||
if cfg.App.BatchTimeout == 0 {
|
||||
cfg.App.BatchTimeout = 2 * time.Second
|
||||
}
|
||||
if cfg.Postgres.MaxConns == 0 {
|
||||
cfg.Postgres.MaxConns = 10
|
||||
}
|
||||
if cfg.Postgres.MinConns == 0 {
|
||||
cfg.Postgres.MinConns = 2
|
||||
}
|
||||
if cfg.Log.Level == "" {
|
||||
cfg.Log.Level = "info"
|
||||
}
|
||||
if cfg.Log.Format == "" {
|
||||
cfg.Log.Format = "json"
|
||||
}
|
||||
if cfg.NATS.Stream == "" {
|
||||
cfg.NATS.Stream = "TELEGRAM"
|
||||
}
|
||||
if cfg.NATS.Consumer == "" {
|
||||
cfg.NATS.Consumer = "telegram-consumer"
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return nil, fmt.Errorf("config validation failed: %w", err)
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// Validate validates the configuration
|
||||
func (c *Config) Validate() error {
|
||||
if c.NATS.URL == "" {
|
||||
return fmt.Errorf("nats.url is required")
|
||||
}
|
||||
if c.Subscription.Topic == "" && c.NATS.Stream == "" {
|
||||
return fmt.Errorf("subscription.topic or nats.stream is required")
|
||||
}
|
||||
if c.Publisher.Topic == "" {
|
||||
return fmt.Errorf("publisher.topic is required")
|
||||
}
|
||||
if c.Postgres.URL == "" {
|
||||
return fmt.Errorf("postgres.url is required")
|
||||
}
|
||||
if c.App.BatchSize <= 0 {
|
||||
return fmt.Errorf("app.batch_size must be greater than 0")
|
||||
}
|
||||
if c.App.BatchTimeout <= 0 {
|
||||
return fmt.Errorf("app.batch_timeout must be greater than 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProvideConfig is a Wire provider function
|
||||
func ProvideConfig() (*Config, error) {
|
||||
return LoadConfig()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user