127 lines
3.0 KiB
Go
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"
|
|
}
|