rwadurian/backend/mpc-system/pkg/config/config.go

228 lines
7.1 KiB
Go

package config
import (
"fmt"
"strings"
"time"
"github.com/spf13/viper"
)
// Config holds all configuration for the MPC system
type Config struct {
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
Redis RedisConfig `mapstructure:"redis"`
RabbitMQ RabbitMQConfig `mapstructure:"rabbitmq"`
Consul ConsulConfig `mapstructure:"consul"`
JWT JWTConfig `mapstructure:"jwt"`
MPC MPCConfig `mapstructure:"mpc"`
Logger LoggerConfig `mapstructure:"logger"`
}
// ServerConfig holds server-related configuration
type ServerConfig struct {
GRPCPort int `mapstructure:"grpc_port"`
HTTPPort int `mapstructure:"http_port"`
Environment string `mapstructure:"environment"`
Timeout time.Duration `mapstructure:"timeout"`
TLSEnabled bool `mapstructure:"tls_enabled"`
TLSCertFile string `mapstructure:"tls_cert_file"`
TLSKeyFile string `mapstructure:"tls_key_file"`
}
// DatabaseConfig holds database configuration
type DatabaseConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
DBName string `mapstructure:"dbname"`
SSLMode string `mapstructure:"sslmode"`
MaxOpenConns int `mapstructure:"max_open_conns"`
MaxIdleConns int `mapstructure:"max_idle_conns"`
ConnMaxLife time.Duration `mapstructure:"conn_max_life"`
}
// DSN returns the database connection string
func (c *DatabaseConfig) DSN() string {
return fmt.Sprintf(
"host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
c.Host, c.Port, c.User, c.Password, c.DBName, c.SSLMode,
)
}
// RedisConfig holds Redis configuration
type RedisConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
Password string `mapstructure:"password"`
DB int `mapstructure:"db"`
}
// Addr returns the Redis address
func (c *RedisConfig) Addr() string {
return fmt.Sprintf("%s:%d", c.Host, c.Port)
}
// RabbitMQConfig holds RabbitMQ configuration
type RabbitMQConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
User string `mapstructure:"user"`
Password string `mapstructure:"password"`
VHost string `mapstructure:"vhost"`
}
// URL returns the RabbitMQ connection URL
func (c *RabbitMQConfig) URL() string {
return fmt.Sprintf(
"amqp://%s:%s@%s:%d/%s",
c.User, c.Password, c.Host, c.Port, c.VHost,
)
}
// ConsulConfig holds Consul configuration
type ConsulConfig struct {
Host string `mapstructure:"host"`
Port int `mapstructure:"port"`
ServiceID string `mapstructure:"service_id"`
Tags []string `mapstructure:"tags"`
}
// Addr returns the Consul address
func (c *ConsulConfig) Addr() string {
return fmt.Sprintf("%s:%d", c.Host, c.Port)
}
// JWTConfig holds JWT configuration
type JWTConfig struct {
SecretKey string `mapstructure:"secret_key"`
Issuer string `mapstructure:"issuer"`
TokenExpiry time.Duration `mapstructure:"token_expiry"`
RefreshExpiry time.Duration `mapstructure:"refresh_expiry"`
}
// MPCConfig holds MPC-specific configuration
type MPCConfig struct {
DefaultThresholdN int `mapstructure:"default_threshold_n"`
DefaultThresholdT int `mapstructure:"default_threshold_t"`
SessionTimeout time.Duration `mapstructure:"session_timeout"`
MessageTimeout time.Duration `mapstructure:"message_timeout"`
KeygenTimeout time.Duration `mapstructure:"keygen_timeout"`
SigningTimeout time.Duration `mapstructure:"signing_timeout"`
MaxParties int `mapstructure:"max_parties"`
}
// LoggerConfig holds logger configuration
type LoggerConfig struct {
Level string `mapstructure:"level"`
Encoding string `mapstructure:"encoding"`
OutputPath string `mapstructure:"output_path"`
}
// Load loads configuration from file and environment variables
func Load(configPath string) (*Config, error) {
v := viper.New()
// Set default values
setDefaults(v)
// Read config file
if configPath != "" {
v.SetConfigFile(configPath)
} else {
v.SetConfigName("config")
v.SetConfigType("yaml")
v.AddConfigPath(".")
v.AddConfigPath("./config")
v.AddConfigPath("/etc/mpc-system/")
}
// Read environment variables
v.SetEnvPrefix("MPC")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
v.AutomaticEnv()
// Read config file (if exists)
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
// Config file not found is not an error, we'll use defaults + env vars
}
var config Config
if err := v.Unmarshal(&config); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
return &config, nil
}
// setDefaults sets default configuration values
func setDefaults(v *viper.Viper) {
// Server defaults
v.SetDefault("server.grpc_port", 50051)
v.SetDefault("server.http_port", 8080)
v.SetDefault("server.environment", "development")
v.SetDefault("server.timeout", "30s")
v.SetDefault("server.tls_enabled", false)
// Database defaults
v.SetDefault("database.host", "localhost")
v.SetDefault("database.port", 5432)
v.SetDefault("database.user", "mpc_user")
v.SetDefault("database.password", "")
v.SetDefault("database.dbname", "mpc_system")
v.SetDefault("database.sslmode", "disable")
v.SetDefault("database.max_open_conns", 25)
v.SetDefault("database.max_idle_conns", 5)
v.SetDefault("database.conn_max_life", "5m")
// Redis defaults
v.SetDefault("redis.host", "localhost")
v.SetDefault("redis.port", 6379)
v.SetDefault("redis.password", "")
v.SetDefault("redis.db", 0)
// RabbitMQ defaults
v.SetDefault("rabbitmq.host", "localhost")
v.SetDefault("rabbitmq.port", 5672)
v.SetDefault("rabbitmq.user", "guest")
v.SetDefault("rabbitmq.password", "guest")
v.SetDefault("rabbitmq.vhost", "/")
// Consul defaults
v.SetDefault("consul.host", "localhost")
v.SetDefault("consul.port", 8500)
// JWT defaults
v.SetDefault("jwt.issuer", "mpc-system")
v.SetDefault("jwt.token_expiry", "15m")
v.SetDefault("jwt.refresh_expiry", "24h")
// MPC defaults
v.SetDefault("mpc.default_threshold_n", 3)
v.SetDefault("mpc.default_threshold_t", 2)
v.SetDefault("mpc.session_timeout", "10m")
v.SetDefault("mpc.message_timeout", "30s")
v.SetDefault("mpc.keygen_timeout", "10m")
v.SetDefault("mpc.signing_timeout", "5m")
v.SetDefault("mpc.max_parties", 10)
// Logger defaults
v.SetDefault("logger.level", "info")
v.SetDefault("logger.encoding", "json")
v.SetDefault("logger.output_path", "stdout")
}
// MustLoad loads configuration and panics on error
func MustLoad(configPath string) *Config {
cfg, err := Load(configPath)
if err != nil {
panic(fmt.Sprintf("failed to load config: %v", err))
}
return cfg
}