Notification System - Functional Spec
Overview
OpenRiot uses a centralized notification system to prevent dunst crashes and provide consistent icon/error handling across all notification call sites.
Architecture
Core Function: notify.SendNotify()
Location: source/notify/cooldown.go
Signature:
func SendNotify(iconName, title, body, urgency string, timeoutMs int) error
Parameters:
| Param | Type | Description |
|——-|——|————-|
| iconName | string | Icon filename only (e.g., "cpu.png") - NOT full path |
| title | string | Notification title |
| body | string | Notification body text |
| urgency | string | "normal" or "critical" |
| timeoutMs | int | Timeout in milliseconds |
Behavior:
- Checks cooldown - skips if < 500ms since last notification
- Records current timestamp to cooldown file
- Resolves icon path via
paths.GetIconPath(iconName)(includes fallback toinfo.png) - Calls
notify-sendwith appropriate flags
Internal Functions
ShouldSend() bool - Checks if cooldown period has elapsed
RecordSend() error - Writes current nanosecond timestamp to cooldown file
Cooldown Mechanism
File: ~/.cache/openriot/notify-cooldown (permissions: 0600)
Duration: 500ms
Purpose: Prevent dunst crashes from rapid-fire notifications when multiple polybar modules query simultaneously or user spam-triggers keybindings.
Icon Resolution
SendNotify internally calls paths.GetIconPath(iconName) which:
- Returns full path to icon in
~/.local/share/openriot/config/icons/ - Falls back to
info.pngif icon not found (prevents dunst crashes from missing icons)
Migration Status
Completed (use notify.SendNotify)
All main.go notification calls converted.
Remaining (still use raw exec.Command)
source/crypto/crypto.go:1007- crypto notificationsource/nightlight/nightlight.go:85- night light togglesource/workspace/workspace.go:47- workspace switchsource/update/update.go:62,70,79- update checkssource/lock/lock.go:46- screen locksource/rofi/rofi.go:76- app launchersource/wireguard/wireguard.go:45,54,64- VPN statussource/audio/volume.go:27- volume changessource/display/display.go:28- brightness changes
Examples
Good (using centralized function):
notify.SendNotify("cpu.png", "CPU", "Usage: 45%", "normal", 5000)
notify.SendNotify("proton-drive.png", "Proton Drive", "Syncing...", "normal", 2000)
notify.SendNotify("power.png", "Power", "Shutting down...", "critical", 5000)
Bad (bypassing centralized function):
exec.Command("/usr/local/bin/notify-send", "-i", paths.GetIconPath("cpu.png"), "-t", "5000", "CPU", details).Start()
Future Improvements
Potential additions (not implemented):
- Notification logging to file
- Retry logic on failure
- Configurable cooldown duration
- Rate limiting per category (crypto vs system vs app)