From b2e8d5fc1b8d40adf63b36d7687c8cc1ca1c536b Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Fri, 3 Apr 2026 15:14:49 +0200 Subject: [PATCH] updated docu --- README.md | 56 ++++++++++++++++++--------------- example.config.toml | 73 +++++++++++++++++++++++++++++++++++++------- src/main.rs | 4 +-- src/modules/mpris.rs | 5 ++- 4 files changed, 97 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e30defc..c3f91bb 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,16 @@ # fluxo-rs -fluxo-rs is a high-performance system metrics daemon and client designed specifically for Waybar. It replaces standard shell scripts with a compiled Rust binary that collects data via a background polling loop and serves it over a Unix socket. +`fluxo-rs` is a high-performance system metrics daemon and client designed specifically for Waybar. It entirely replaces standard shell scripts with a compiled Rust binary that collects data via a background polling loop and serves it over a Unix socket. + +With its **100% Native, Content-Based Event-Driven Architecture**, it consumes effectively 0% CPU while idle and signals Waybar to redraw *only* when the rendered UI text or icons physically change. ## Key Features -- **Asynchronous Architecture**: Built on **Tokio**, the daemon handles concurrent IPC requests and background tasks with zero latency and minimal CPU overhead. -- **Native Library Integrations**: - - **Audio**: Direct `libpulse` integration for event-driven, instant volume and device updates. - - **Bluetooth**: Native `bluer` integration for robust device monitoring. - - **Pixel Buds Pro**: Custom native RPC implementation for real-time battery and ANC control. - - **Network**: Native `nix` and `/proc` inspection for high-speed interface monitoring. - - **Hyprland**: Direct IPC Unix socket communication for gamemode and animation status. -- **Circuit Breaker (Failsafe)**: Automatically detects failing modules and enters a "Cool down" state to prevent resource waste and log spam. -- **Multi-threaded Polling**: Decoupled subsystem threads ensure that a hang in one system (e.g., a slow GPU probe) never freezes your entire bar. +- **100% Native Architecture**: Zero shell-outs or subprocesses. Uses `bluer` for Bluetooth, `libpulse-binding` for audio, `zbus` for MPRIS/DND, and `notify` for backlight. +- **Content-Based Event Signaling**: `fluxo-rs` evaluates your custom configuration formats internally. It only sends a `SIGRTMIN+X` signal to Waybar if the resulting string or CSS class has actually changed, eliminating pointless re-renders from raw polling fluctuations. +- **Zero-Latency Interactions**: Direct library bindings mean that when you change your volume or connect a Bluetooth device via the CLI, the daemon updates instantly. +- **Circuit Breaker (Failsafe)**: Automatically detects failing modules and enters a "Cool down" state, preventing resource waste and log spam. Fallback caching keeps your bar looking clean even during brief failures. +- **Multi-threaded Polling**: Decoupled Tokio subsystem threads ensure that a hang in one system (e.g., a slow GPU probe) never freezes your Waybar. ## Modules @@ -24,37 +22,47 @@ fluxo-rs is a high-performance system metrics daemon and client designed specifi | `sys` | System load and uptime | `{uptime}`, `{load1}`, `{load5}`, `{load15}`, `{procs}` | | `disk` | Disk usage | `{mount}`, `{used}`, `{total}` | | `pool` | Btrfs aggregate storage | `{used}`, `{total}` | +| `gpu` | GPU usage & thermals | `{usage}`, `{vram_used}`, `{vram_total}`, `{temp}` | | `vol` | Audio output (sink) | `{name}`, `{volume}`, `{icon}` | | `mic` | Audio input (source) | `{name}`, `{volume}`, `{icon}` | | `bt` | Bluetooth status & plugins | `{alias}`, `{mac}`, `{left}`, `{right}`, `{anc}` | | `power` | Battery and AC status | `{percentage}`, `{icon}` | -| `game` | Hyprland status | active/inactive icons | +| `game` | Hyprland Gamemode status | active/inactive strings | +| `mpris` | Media Player status | `{artist}`, `{title}`, `{album}`, `{status_icon}` | +| `backlight` | Display Brightness | `{percentage}`, `{icon}` | +| `kbd` | Keyboard Layout | `{layout}` | +| `dnd` | Do Not Disturb (SwayNC) | active/inactive strings | ## Setup 1. **Build**: `cargo build --release` -2. **Configure**: Create `~/.config/fluxo/config.toml` (see `example.config.toml`). -3. **Daemon**: Start `fluxo-rs daemon`. It's recommended to run this as a systemd user service. +2. **Configure**: Create `~/.config/fluxo/config.toml` (see `example.config.toml`). Ensure you map your `[signals]`. +3. **Daemon**: Start `fluxo-rs daemon`. It is highly recommended to run this as a systemd user service. ## Waybar Configuration -To achieve zero-latency updates, use **Waybar Signals**: +To achieve zero-latency updates and zero-polling CPU usage, set `interval: 0` on your modules and rely entirely on **Waybar Signals** mapped in your `config.toml`: ```jsonc -"custom/audio": { - "exec": "fluxo vol", +"custom/volume": { + "exec": "fluxo-rs vol", "return-type": "json", - "interval": 5, - "signal": 8, - "on-click": "fluxo audio cycle sink && pkill -RTMIN+8 waybar" + "interval": 0, + "signal": 8, // Must match the value in config.toml [signals] + "on-click": "fluxo-rs vol mute", + "on-scroll-up": "fluxo-rs vol up 1", + "on-scroll-down": "fluxo-rs vol down 1", + "on-click-right": "fluxo-rs vol cycle" }, -"custom/bluetooth": { - "exec": "fluxo bt", +"custom/bluetooth-audio": { + "format": "{}", "return-type": "json", - "interval": 5, + "exec": "fluxo-rs bt", + "on-click": "fluxo-rs bt menu", + "on-click-right": "fluxo-rs bt cycle_mode", "signal": 9, - "on-click": "fluxo bt menu && pkill -RTMIN+9 waybar", - "on-click-right": "fluxo bt cycle_mode && pkill -RTMIN+9 waybar" + "interval": 0, + "tooltip": true } ``` diff --git a/example.config.toml b/example.config.toml index 8fcc7a1..ca14178 100644 --- a/example.config.toml +++ b/example.config.toml @@ -1,46 +1,97 @@ # Fluxo configuration example +# Place this at ~/.config/fluxo/config.toml + +# Note: All tokens support standard alignment, padding, and precision specifiers dynamically. +# For example, you can change {rx:>5.2} to {rx:<8.1} or {used} to {used:^4.0} directly here. [general] +# command used for interactive menus (e.g., bluetooth device selection) +# $FLUXO_PROMPT is securely injected to prevent shell escaping issues menu_command = "fuzzel --dmenu --prompt \"$FLUXO_PROMPT\"" +# For Wofi use: menu_command = "wofi --show dmenu --prompt \"$FLUXO_PROMPT\"" + +# Map modules to specific Waybar signals for zero-latency, event-driven UI updates. +# These MUST match the `signal` configuration in your waybar config.jsonc +[signals] +network = 1 +cpu = 2 +memory = 3 +gpu = 4 +sys = 5 +disk = 6 +game = 7 +audio = 8 +bt = 9 +power = 10 +keyboard = 11 +mpris = 12 +backlight = 13 +dnd = 14 [network] -format = "{interface} ({ip}):  {rx:>5.2} MB/s  {tx:>5.2} MB/s" +# tokens: {interface}, {ip}, {rx}, {tx} +format = "{interface} ({ip}):  {rx:^4.1} MB/s  {tx:^4.1} MB/s" [cpu] -format = "CPU: {usage:>4.1}% {temp:>4.1}C" +# tokens: {usage}, {temp}, {model} +format = "CPU: {usage:^4.1}% {temp:^4.1}C" [memory] -format = "{used:>5.2}/{total:>5.2}GB" +# tokens: {used}, {total} +format = "MEM: {used:^4.1}/{total:^4.1}GB" [gpu] +# tokens: {usage}, {vram_used}, {vram_total}, {temp} format_amd = "AMD: {usage:>3.0}% {vram_used:>4.1}/{vram_total:>4.1}GB {temp:>4.1}C" format_intel = "iGPU: {usage:>3.0}%" format_nvidia = "NV: {usage:>3.0}% {vram_used:>4.1}/{vram_total:>4.1}GB {temp:>4.1}C" [sys] -format = "UP: {uptime} | LOAD: {load1:>4.2} {load5:>4.2} {load15:>4.2}" +# tokens: {uptime}, {load1}, {load5}, {load15}, {procs} +format = "UP: {uptime} LOAD: {load1:^3.1} " [disk] -format = "{mount} {used:>5.1}/{total:>5.1}G" +# tokens: {mount}, {used}, {total} +format = "{mount} {used:^3.0}/{total:^3.0}G" [pool] +# tokens: {used}, {total} format = "{used:>4.0}G / {total:>4.0}G" [power] +# tokens: {percentage}, {icon} format = "{percentage:>3}% {icon}" -[bt] -format_connected = "{alias} 󰂰" -format_plugin = "{alias} [{left}|{right}] {anc} 󰂰" -format_disconnected = "󰂯" -format_disabled = "󰂲 Off" - [audio] +# tokens: {name}, {volume}, {icon} format_sink_unmuted = "{name} {volume:>3}% {icon}" format_sink_muted = "{name} {icon}" format_source_unmuted = "{name} {volume:>3}% {icon}" format_source_muted = "{name} {icon}" +[bt] +# tokens: {alias}, {mac}, {left}, {right}, {anc} +format_plugin = "{alias} [{left}|{right}] {anc} 󰂰" +format_connected = "󰂰 {alias}" +format_disconnected = "󰂯 Disconnected" +format_disabled = "󰂲 Off" + [game] format_active = "󰊖" format_inactive = "" + +[mpris] +# tokens: {artist}, {title}, {album}, {status_icon} +format = "{status_icon} {artist} - {title}" + +[backlight] +# tokens: {percentage}, {icon} +format = "{percentage:>3}% {icon}" + +[keyboard] +# tokens: {layout} +format = "{layout}" + +[dnd] +format_dnd = "󰂛" +format_normal = "󰂚" diff --git a/src/main.rs b/src/main.rs index c3de821..a50441d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -131,9 +131,7 @@ fn main() { } // Generic module dispatch - // To handle module-specific default targets like "vol up" -> "vol sink up" or "mic up" -> "vol source up" - // Wait, `daemon.rs` `evaluate_module_for_signaler` defaults `vol` to `sink show`. - // If we map `mic` to `["vol", "source"]` in `main.rs` instead of keeping `mic` in daemon: + // Translate module-specific shorthand targets let (actual_module, actual_args) = if module == "vol" { let mut new_args = vec!["sink".to_string()]; new_args.extend(cli.args.clone()); diff --git a/src/modules/mpris.rs b/src/modules/mpris.rs index d63e1ca..7e88e84 100644 --- a/src/modules/mpris.rs +++ b/src/modules/mpris.rs @@ -109,9 +109,8 @@ impl MprisDaemon { info!("Connected to D-Bus for MPRIS monitoring"); - // Simple poll loop for MPRIS since players can come and go, and tracking dynamically - // with pure signals across multiple dynamically spawned DBus names is complex. - // A robust hybrid approach: poll every 2s for active players, and update state. + // Periodically poll for the active player and update the MPRIS state. + // This avoids complex dynamic signal tracking across ephemeral player instances. let dbus_proxy = DBusProxy::new(&connection).await?;