// Package config parses the clip-sync TOML configuration file and applies // environment variable overrides. // // Config file location: ~/.config/clip-sync/peers.toml // Environment overrides: // CLIP_SYNC_PORT — override daemon.port // CLIP_SYNC_POLL_MS — override daemon.poll_interval_ms package config import ( "fmt" "os" "path/filepath" "strconv" "time" "github.com/BurntSushi/toml" ) // Config represents the full clip-sync configuration. type Config struct { Daemon DaemonConfig `toml:"daemon"` Peers []PeerConfig `toml:"peers"` } // DaemonConfig holds daemon-level settings. type DaemonConfig struct { Port int `toml:"port"` PollIntervalMs int `toml:"poll_interval_ms"` } // PeerConfig represents one remote clip-sync peer. type PeerConfig struct { Name string `toml:"name"` Addr string `toml:"addr"` } // Default values. const ( DefaultPort = 9137 DefaultPollIntervalMs = 500 ConfigDir = ".config/clip-sync" ConfigFile = "peers.toml" ) // Load reads the config file from ~/.config/clip-sync/peers.toml and applies // environment variable overrides. func Load() (*Config, error) { home, err := os.UserHomeDir() if err != nil { return nil, fmt.Errorf("config: cannot find home directory: %w", err) } cfgPath := filepath.Join(home, ConfigDir, ConfigFile) cfg := &Config{ Daemon: DaemonConfig{ Port: DefaultPort, PollIntervalMs: DefaultPollIntervalMs, }, } if _, err := toml.DecodeFile(cfgPath, cfg); err != nil { if !os.IsNotExist(err) { return nil, fmt.Errorf("config: cannot parse %s: %w", cfgPath, err) } // File doesn't exist — use defaults (no peers configured). } // Environment variable overrides. if v := os.Getenv("CLIP_SYNC_PORT"); v != "" { port, err := strconv.Atoi(v) if err != nil { return nil, fmt.Errorf("config: invalid CLIP_SYNC_PORT: %w", err) } cfg.Daemon.Port = port } if v := os.Getenv("CLIP_SYNC_POLL_MS"); v != "" { ms, err := strconv.Atoi(v) if err != nil { return nil, fmt.Errorf("config: invalid CLIP_SYNC_POLL_MS: %w", err) } cfg.Daemon.PollIntervalMs = ms } return cfg, nil } // PollInterval returns the poll interval as a time.Duration. func (c *Config) PollInterval() time.Duration { return time.Duration(c.Daemon.PollIntervalMs) * time.Millisecond } // ListenAddr returns the HTTP listen address for this daemon. func (c *Config) ListenAddr() string { return fmt.Sprintf(":%d", c.Daemon.Port) }