diff options
Diffstat (limited to 'internal/notify/config.go')
| -rw-r--r-- | internal/notify/config.go | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/internal/notify/config.go b/internal/notify/config.go new file mode 100644 index 0000000..2b6ba5e --- /dev/null +++ b/internal/notify/config.go @@ -0,0 +1,91 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +package notify + +import ( + "encoding/json" + "errors" + "log" + "os" + "path/filepath" +) + +// Timeouts are the balloon lifetimes in seconds per urgency, used only when a +// client leaves the choice to the server. 0 means never expires. +type Timeouts struct { + Low int `json:"low"` + Normal int `json:"normal"` + Critical int `json:"critical"` +} + +// Config is the daemon's share of ~/.config/notifyd/config.json. The file +// also carries the balloon shell's keys (placement, DND, mute); they are not +// declared here and the decoder ignores them. +type Config struct { + Timeouts Timeouts `json:"timeouts"` + LiveCap int `json:"liveCap"` + HistoryCap int `json:"historyCap"` +} + +// DefaultConfig is the behaviour before the file existed. +func DefaultConfig() Config { + return Config{Timeouts: Timeouts{Low: 10, Normal: 10, Critical: 0}, LiveCap: 20, HistoryCap: 20} +} + +// ConfigPath is $XDG_CONFIG_HOME/notifyd/config.json, ~/.config when unset. +func ConfigPath() string { + dir, err := os.UserConfigDir() + if err != nil { + dir = filepath.Join(homeDir(), ".config") + } + return filepath.Join(dir, "notifyd", "config.json") +} + +// LoadConfig never fails: a hand typo must not stop the daemon. A missing +// file or broken JSON is the defaults; a key of the wrong type keeps its +// default while the rest of the file applies, which is what encoding/json +// does on an UnmarshalTypeError. Out-of-range values clamp. +func LoadConfig(path string) Config { + def := DefaultConfig() + data, err := os.ReadFile(path) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + log.Printf("notifyd: config: %v", err) + } + return def + } + c := def + if err := json.Unmarshal(data, &c); err != nil { + var typeErr *json.UnmarshalTypeError + if !errors.As(err, &typeErr) { + log.Printf("notifyd: config %s: %v, using defaults", path, err) + return def + } + log.Printf("notifyd: config %s: %v", path, err) + } + c.LiveCap = clamp(c.LiveCap, 1, 100) + c.HistoryCap = clamp(c.HistoryCap, 1, 100) + if c.Timeouts.Low < 0 { + c.Timeouts.Low = def.Timeouts.Low + } + if c.Timeouts.Normal < 0 { + c.Timeouts.Normal = def.Timeouts.Normal + } + if c.Timeouts.Critical < 0 { + c.Timeouts.Critical = def.Timeouts.Critical + } + return c +} + +func clamp(v, lo, hi int) int { + return min(max(v, lo), hi) +} |
