Files

127 lines
3.0 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"time"
toml "github.com/pelletier/go-toml/v2"
)
type Config struct {
Reddit RedditConfig `toml:"reddit"`
LLM LLMConfig `toml:"llm"`
Interests InterestsConfig `toml:"interests"`
Monitor MonitorConfig `toml:"monitor"`
GRPC GRPCConfig `toml:"grpc"`
}
type RedditConfig struct {
ClientID string `toml:"client_id"`
ClientSecret string `toml:"client_secret"`
Username string `toml:"username"`
Password string `toml:"password"`
}
type LLMConfig struct {
Backend string `toml:"backend"`
Endpoint string `toml:"endpoint"`
Model string `toml:"model"`
APIKey string `toml:"api_key"`
RelevanceThreshold float64 `toml:"relevance_threshold"`
}
type InterestsConfig struct {
Description string `toml:"description"`
}
type MonitorConfig struct {
PollInterval Duration `toml:"poll_interval"`
MaxPostsPerPoll int `toml:"max_posts_per_poll"`
}
type GRPCConfig struct {
Socket string `toml:"socket"`
}
// Duration wraps time.Duration for TOML string parsing.
type Duration struct {
time.Duration
}
func (d *Duration) UnmarshalText(text []byte) error {
var err error
d.Duration, err = time.ParseDuration(string(text))
return err
}
func (d Duration) MarshalText() ([]byte, error) {
return []byte(d.Duration.String()), nil
}
func LoadFromFile(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read config: %w", err)
}
var cfg Config
if err := toml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parse config: %w", err)
}
return &cfg, nil
}
func (c *Config) ApplyEnvOverrides() {
if v := os.Getenv("REDDIT_READER_REDDIT_CLIENT_ID"); v != "" {
c.Reddit.ClientID = v
}
if v := os.Getenv("REDDIT_READER_REDDIT_CLIENT_SECRET"); v != "" {
c.Reddit.ClientSecret = v
}
if v := os.Getenv("REDDIT_READER_REDDIT_USERNAME"); v != "" {
c.Reddit.Username = v
}
if v := os.Getenv("REDDIT_READER_REDDIT_PASSWORD"); v != "" {
c.Reddit.Password = v
}
if v := os.Getenv("REDDIT_READER_LLM_API_KEY"); v != "" {
c.LLM.APIKey = v
}
if v := os.Getenv("REDDIT_READER_LLM_BACKEND"); v != "" {
c.LLM.Backend = v
}
if v := os.Getenv("REDDIT_READER_LLM_ENDPOINT"); v != "" {
c.LLM.Endpoint = v
}
if v := os.Getenv("REDDIT_READER_LLM_MODEL"); v != "" {
c.LLM.Model = v
}
}
func DefaultPath() string {
dir, err := os.UserConfigDir()
if err != nil {
return ""
}
return filepath.Join(dir, "reddit-reader", "config.toml")
}
func (c *Config) SaveToFile(path string) error {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return fmt.Errorf("create config dir: %w", err)
}
data, err := toml.Marshal(c)
if err != nil {
return fmt.Errorf("marshal config: %w", err)
}
return os.WriteFile(path, data, 0o600)
}
func DefaultSocket() string {
if dir := os.Getenv("XDG_RUNTIME_DIR"); dir != "" {
return filepath.Join(dir, "reddit-reader.sock")
}
return "/tmp/reddit-reader.sock"
}