send (title/priority/tags), read (poll mode, greppable one-liners), topics (known homelab buses from config). Config with homelab defaults on first run. Unit tests against httptest; smoked against the real ntfy on topic agent-tools-test. Spec: doc/tool-parity.md 3.3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011KikHkfCiC3yELbsMN8fT9
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
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)
|
|
}
|