174 lines
4.8 KiB
Go
Raw Normal View History

// internal/config/config.go
package config
import (
"fmt"
"os"
"path/filepath"
"github.com/spf13/viper"
)
// Config holds all configuration for the application
type Config struct {
2025-03-01 22:53:36 -08:00
// General configuration
AppName string `mapstructure:"app_name"`
ServerPort int `mapstructure:"server_port"`
LogLevel string `mapstructure:"log_level"`
// Bot configuration
Bot struct {
KeysFile string `mapstructure:"keys_file"`
ContentDir string `mapstructure:"content_dir"`
ArchiveDir string `mapstructure:"archive_dir"`
DefaultInterval int `mapstructure:"default_interval"` // in minutes
} `mapstructure:"bot"`
// Database configuration
DB struct {
Path string `mapstructure:"path"`
} `mapstructure:"db"`
// Media services configuration
Media struct {
DefaultService string `mapstructure:"default_service"` // "nip94" or "blossom"
// NIP-94 configuration
NIP94 struct {
ServerURL string `mapstructure:"server_url"`
RequireAuth bool `mapstructure:"require_auth"`
} `mapstructure:"nip94"`
// Blossom configuration
Blossom struct {
ServerURL string `mapstructure:"server_url"`
} `mapstructure:"blossom"`
} `mapstructure:"media"`
// Default relays
Relays []struct {
URL string `mapstructure:"url"`
Read bool `mapstructure:"read"`
Write bool `mapstructure:"write"`
} `mapstructure:"relays"`
AllowedNpub string `mapstructure:"allowed_npub"` // NEW
}
// LoadConfig loads the configuration from file or environment variables
func LoadConfig(configPath string) (*Config, error) {
v := viper.New()
// Set defaults
v.SetDefault("app_name", "Nostr Poster")
2025-03-01 22:53:36 -08:00
v.SetDefault("server_port", 8765)
v.SetDefault("log_level", "info")
v.SetDefault("bot.keys_file", "keys.json")
v.SetDefault("bot.content_dir", "./content")
v.SetDefault("bot.archive_dir", "./archive")
v.SetDefault("bot.default_interval", 60) // 1 hour
v.SetDefault("db.path", "./nostr-poster.db")
v.SetDefault("media.default_service", "nip94")
v.SetDefault("media.nip94.require_auth", true)
// Default relays
v.SetDefault("relays", []map[string]interface{}{
2025-03-01 22:53:36 -08:00
{"url": "wss://freelay.sovbit.host", "read": true, "write": true},
})
2025-03-01 22:53:36 -08:00
v.SetDefault("allowed_npub", "")
// Setup config file search
if configPath != "" {
// Use config file from the flag
v.SetConfigFile(configPath)
} else {
// Try to find config in default locations
v.AddConfigPath(".")
v.AddConfigPath("./config")
v.AddConfigPath("$HOME/.nostr-poster")
v.SetConfigName("config")
}
// Read the config file
v.SetConfigType("yaml")
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
// Config file not found, we'll create a default one
fmt.Println("Config file not found, creating default config")
defaultConfig := &Config{}
v.Unmarshal(defaultConfig)
// Ensure directories exist
os.MkdirAll(filepath.Dir(v.GetString("db.path")), 0755)
os.MkdirAll(v.GetString("bot.content_dir"), 0755)
os.MkdirAll(v.GetString("bot.archive_dir"), 0755)
// Create default config file
if err := v.SafeWriteConfig(); err != nil {
return nil, fmt.Errorf("failed to write default config: %w", err)
}
} else {
// Config file was found but another error was produced
return nil, fmt.Errorf("error reading config file: %w", err)
}
}
// Environment variables can override config values
v.SetEnvPrefix("NOSTR_POSTER")
v.AutomaticEnv()
// Parse config into struct
config := &Config{}
if err := v.Unmarshal(config); err != nil {
return nil, fmt.Errorf("failed to parse config: %w", err)
}
return config, nil
}
// Save writes the current configuration to disk
func (c *Config) Save(configPath string) error {
v := viper.New()
// Convert config struct to map
err := v.MergeConfigMap(map[string]interface{}{
"app_name": c.AppName,
"server_port": c.ServerPort,
"log_level": c.LogLevel,
"bot": map[string]interface{}{
"keys_file": c.Bot.KeysFile,
"content_dir": c.Bot.ContentDir,
"archive_dir": c.Bot.ArchiveDir,
"default_interval": c.Bot.DefaultInterval,
},
"db": map[string]interface{}{
"path": c.DB.Path,
},
"media": map[string]interface{}{
"default_service": c.Media.DefaultService,
"nip94": map[string]interface{}{
"server_url": c.Media.NIP94.ServerURL,
"require_auth": c.Media.NIP94.RequireAuth,
},
"blossom": map[string]interface{}{
"server_url": c.Media.Blossom.ServerURL,
},
},
"relays": c.Relays,
2025-03-01 22:53:36 -08:00
"allowed_npub": c.AllowedNpub,
})
if err != nil {
return fmt.Errorf("failed to merge config: %w", err)
}
// Set the config path
v.SetConfigFile(configPath)
// Write the config file
return v.WriteConfig()
}