package notify import ( "encoding/json" "fmt" "os" "path/filepath" ) // Config is ~/.config/notifyr/config.json, created with homelab // defaults on first run. NOTIFYR_CONFIG overrides the path. type Config struct { Server string `json:"server"` Token string `json:"token"` DefaultTopic string `json:"default_topic"` Topics map[string]string `json:"topics"` // known topics -> what they carry (informational) } func DefaultConfig() *Config { return &Config{ Server: "https://ntfy.brasse-pc.eu", Token: "", DefaultTopic: "claude", Topics: map[string]string{ "claude": "agents' direct notes to Björn", "agent-helm": "agent-helm events (question waiting, session died)", "Info": "*arr system events", "media-hamtningar": "media grabbed for download", "media-nytt": "new media landed in Jellyfin", "pi5-server": "server maintenance (reboots, watchtower)", "pi5-server-fel": "server problems: failed units, disk space", "ci-fel": "failed Gitea Actions builds", "monitoring": "Uptime Kuma up/down alerts", }, } } func ConfigPath() string { if p := os.Getenv("NOTIFYR_CONFIG"); p != "" { return p } dir, err := os.UserConfigDir() if err != nil { dir = "." } return filepath.Join(dir, "notifyr", "config.json") } // LoadConfig reads the config, creating it with defaults on first run. func LoadConfig(path string) (*Config, error) { cfg := DefaultConfig() data, err := os.ReadFile(path) if os.IsNotExist(err) { if err := SaveConfig(path, cfg); err != nil { return nil, err } fmt.Fprintf(os.Stderr, "notifyr: created %s\n", path) return cfg, nil } if err != nil { return nil, err } if err := json.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("%s: %w", path, err) } return cfg, nil } func SaveConfig(path string, cfg *Config) error { if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { return err } data, err := json.MarshalIndent(cfg, "", " ") if err != nil { return err } return os.WriteFile(path, append(data, '\n'), 0o600) }