// Package config provides application configuration via environment and files. package config import ( "errors" "log/slog" "git.eeqj.de/sneak/chat/internal/globals" "git.eeqj.de/sneak/chat/internal/logger" "github.com/spf13/viper" "go.uber.org/fx" _ "github.com/joho/godotenv/autoload" // loads .env file ) // Params defines the dependencies for creating a Config. type Params struct { fx.In Globals *globals.Globals Logger *logger.Logger } // Config holds all application configuration values. type Config struct { DBURL string Debug bool MaintenanceMode bool MetricsPassword string MetricsUsername string Port int SentryDSN string MaxHistory int SessionTimeout int MaxMessageSize int MOTD string ServerName string FederationKey string SessionIdleTimeout string params *Params log *slog.Logger } // New creates a new Config by reading from files and environment variables. func New( _ fx.Lifecycle, params Params, ) (*Config, error) { log := params.Logger.Get() name := params.Globals.Appname viper.SetConfigName(name) viper.SetConfigType("yaml") viper.AddConfigPath("/etc/" + name) viper.AddConfigPath("$HOME/.config/" + name) viper.AutomaticEnv() viper.SetDefault("DEBUG", "false") viper.SetDefault("MAINTENANCE_MODE", "false") viper.SetDefault("PORT", "8080") viper.SetDefault("DBURL", "file:./data.db?_journal_mode=WAL") viper.SetDefault("SENTRY_DSN", "") viper.SetDefault("METRICS_USERNAME", "") viper.SetDefault("METRICS_PASSWORD", "") viper.SetDefault("MAX_HISTORY", "10000") viper.SetDefault("SESSION_TIMEOUT", "86400") viper.SetDefault("MAX_MESSAGE_SIZE", "4096") viper.SetDefault("MOTD", "") viper.SetDefault("SERVER_NAME", "") viper.SetDefault("FEDERATION_KEY", "") viper.SetDefault("SESSION_IDLE_TIMEOUT", "24h") err := viper.ReadInConfig() if err != nil { var notFound viper.ConfigFileNotFoundError if !errors.As(err, ¬Found) { log.Error("config file malformed", "error", err) panic(err) } } cfg := &Config{ DBURL: viper.GetString("DBURL"), Debug: viper.GetBool("DEBUG"), Port: viper.GetInt("PORT"), SentryDSN: viper.GetString("SENTRY_DSN"), MaintenanceMode: viper.GetBool("MAINTENANCE_MODE"), MetricsUsername: viper.GetString("METRICS_USERNAME"), MetricsPassword: viper.GetString("METRICS_PASSWORD"), MaxHistory: viper.GetInt("MAX_HISTORY"), SessionTimeout: viper.GetInt("SESSION_TIMEOUT"), MaxMessageSize: viper.GetInt("MAX_MESSAGE_SIZE"), MOTD: viper.GetString("MOTD"), ServerName: viper.GetString("SERVER_NAME"), FederationKey: viper.GetString("FEDERATION_KEY"), SessionIdleTimeout: viper.GetString("SESSION_IDLE_TIMEOUT"), log: log, params: ¶ms, } if cfg.Debug { params.Logger.EnableDebugLogging() cfg.log = params.Logger.Get() } return cfg, nil }