// Package config provides application configuration via environment and files. package config import ( "errors" "log/slog" "git.eeqj.de/sneak/neoirc/internal/globals" "git.eeqj.de/sneak/neoirc/internal/logger" "github.com/spf13/viper" "go.uber.org/fx" _ "github.com/joho/godotenv/autoload" // loads .env file ) const defaultMOTD = ` _ __ ___ ___ (_)_ __ ___ | '_ \ / _ \/ _ \ | | '__/ __| | | | | __/ (_) || | | | (__ |_| |_|\___|\___/ |_|_| \___| Welcome to NeoIRC — IRC semantics over HTTP. Type /help for available commands.` // 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 MessageMaxAge string MaxMessageSize int QueueMaxAge string MOTD string ServerName string FederationKey string SessionIdleTimeout string HashcashBits int 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:///var/lib/neoirc/state.db?_journal_mode=WAL") viper.SetDefault("SENTRY_DSN", "") viper.SetDefault("METRICS_USERNAME", "") viper.SetDefault("METRICS_PASSWORD", "") viper.SetDefault("MESSAGE_MAX_AGE", "720h") viper.SetDefault("MAX_MESSAGE_SIZE", "4096") viper.SetDefault("QUEUE_MAX_AGE", "720h") viper.SetDefault("MOTD", defaultMOTD) viper.SetDefault("SERVER_NAME", "") viper.SetDefault("FEDERATION_KEY", "") viper.SetDefault("SESSION_IDLE_TIMEOUT", "720h") viper.SetDefault("NEOIRC_HASHCASH_BITS", "20") 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"), MessageMaxAge: viper.GetString("MESSAGE_MAX_AGE"), MaxMessageSize: viper.GetInt("MAX_MESSAGE_SIZE"), QueueMaxAge: viper.GetString("QUEUE_MAX_AGE"), MOTD: viper.GetString("MOTD"), ServerName: viper.GetString("SERVER_NAME"), FederationKey: viper.GetString("FEDERATION_KEY"), SessionIdleTimeout: viper.GetString("SESSION_IDLE_TIMEOUT"), HashcashBits: viper.GetInt("NEOIRC_HASHCASH_BITS"), log: log, params: ¶ms, } if cfg.Debug { params.Logger.EnableDebugLogging() cfg.log = params.Logger.Get() } return cfg, nil }