package config import ( "fmt" "io/fs" "log/slog" "net/url" "os" "strconv" "github.com/BurntSushi/toml" "github.com/pkg/errors" ) type Taxonomy struct { Name string Feed bool } type MenuItem struct { Name string URL string `toml:"url"` } type URL struct { *url.URL } func (u *URL) UnmarshalText(text []byte) (err error) { u.URL, err = url.Parse(string(text)) return err } type Config struct { DefaultLanguage string `toml:"default_language"` BaseURL URL `toml:"base_url"` RedirectOtherHostnames bool `toml:"redirect_other_hostnames"` Port uint64 Production bool Title string Email string Description string DomainStartDate string `toml:"domain_start_date"` OriginalDomain string `toml:"original_domain"` Taxonomies []Taxonomy Extra struct { Headers map[string]string } Menus map[string][]MenuItem } func getEnvFallback(key, fallback string) string { if value, ok := os.LookupEnv(key); ok { return value } else { return fallback } } func setDevelopmentOverrides(config *Config) error { overrideURL, err := URL.Parse(config.BaseURL, "http://localhost:"+fmt.Sprint(config.Port)) if err != nil { return err } config.BaseURL.URL = overrideURL return nil } func GetConfig() (*Config, error) { config := Config{} slog.Debug("reading config.toml") _, err := toml.DecodeFile("config.toml", &config) if err != nil { var pathError *fs.PathError var tomlError toml.ParseError if errors.As(err, &pathError) { return nil, errors.WithMessage(err, "could not read configuration") } else if errors.As(err, &tomlError) { return nil, errors.WithMessage(err, tomlError.ErrorWithUsage()) } else { return nil, errors.Wrap(err, "config error") } } port, err := strconv.ParseUint(getEnvFallback("PORT", "3000"), 10, 16) if err != nil { return nil, err } config.Port = port config.Production = os.Getenv("ENV") == "production" if !config.Production { err = setDevelopmentOverrides(&config) if err != nil { return nil, errors.WithMessage(err, "could not override configuration") } } return &config, nil }