171 lines
4.7 KiB
Go
171 lines
4.7 KiB
Go
// 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 {
|
|
// 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"`
|
|
}
|
|
|
|
// 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")
|
|
v.SetDefault("server_port", 8080)
|
|
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{}{
|
|
{"url": "wss://relay.damus.io", "read": true, "write": true},
|
|
{"url": "wss://nostr.mutinywallet.com", "read": true, "write": true},
|
|
{"url": "wss://relay.nostr.band", "read": true, "write": true},
|
|
})
|
|
|
|
// 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,
|
|
})
|
|
|
|
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()
|
|
} |