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, replaceID 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 |
| replaceID | int | Notification ID to replace (0 = no replacement) |
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
All notification call sites have been migrated to use notify.SendNotify().
Completed (use notify.SendNotify)
| Module | Location | Status |
|---|---|---|
| crypto | source/crypto/crypto.go:1004 |
✓ Migrated |
| nightlight | source/nightlight/nightlight.go:85 |
✓ Migrated |
| workspace | source/workspace/workspace.go:47 |
✓ Migrated |
| update | source/update/update.go:61,67,74 |
✓ Migrated |
| lock | source/lock/lock.go:47 |
✓ Migrated |
| rofi | source/rofi/rofi.go |
✓ Migrated |
| wireguard | source/wireguard/wireguard.go |
✓ Migrated |
| audio | source/audio/volume.go:24 |
✓ Migrated |
| display | source/display/display.go:28 |
✓ Migrated |
All modules now use centralized notification system with cooldown protection.
Examples
Good (using centralized function):
notify.SendNotify("cpu.png", "CPU", "Usage: 45%", "normal", 5000, 0)
notify.SendNotify("proton-drive.png", "Proton Drive", "Syncing...", "normal", 2000, 0)
notify.SendNotify("power.png", "Power", "Shutting down...", "critical", 5000, 0)
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)