This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
# fluxo
|
||||
|
||||
`fluxo` 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.
|
||||
`fluxo` is a high-performance system metrics daemon and client for status bars. 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.
|
||||
With its **100% Native, Content-Based Event-Driven Architecture**, it consumes effectively 0% CPU while idle and pushes updates *only* when the rendered UI text or icons physically change.
|
||||
|
||||
It speaks two dialects, both driven by that same change detection:
|
||||
|
||||
- **Waybar** — the daemon sends `SIGRTMIN+N` and the bar re-runs `fluxo <module>`. See [Waybar Configuration](#waybar-configuration).
|
||||
- **Any other bar** (Quickshell, ags, eww, …) — hold one `fluxo stream <modules...>` child open and read newline-delimited JSON from its stdout. See [Streaming](#streaming).
|
||||
|
||||
## Key Features
|
||||
|
||||
- **100% Native Architecture**: Zero shell-outs or subprocesses. Uses `bluer` for Bluetooth, `libpulse-binding` for audio, `zbus` for MPRIS/DND, and `notify` for backlight.
|
||||
- **Push-Based for Any Bar**: `fluxo stream` turns the daemon into a push source, so bars that keep long-lived child processes never have to poll or re-exec a client.
|
||||
- **Content-Based Event Signaling**: `fluxo` 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.
|
||||
@@ -115,6 +121,58 @@ To achieve zero-latency updates and zero-polling CPU usage, set `interval: 0` on
|
||||
}
|
||||
```
|
||||
|
||||
## Streaming
|
||||
|
||||
Waybar's model is *signal the bar, the bar re-runs a command*, which is why the
|
||||
one-shot client exists. Other bars have no equivalent of a signal, so they end up
|
||||
emulating one by polling — spawning a `fluxo <module>` client per module per
|
||||
interval, which means an exec and a dynamic link per reading, and values that are
|
||||
still up to one interval stale.
|
||||
|
||||
`fluxo stream` is the push-based path for those bars. Subscribe once, and the
|
||||
daemon writes a JSON line whenever a module's rendered output actually changes:
|
||||
|
||||
```console
|
||||
$ fluxo stream cpu mem net
|
||||
{"module":"cpu","text":"7.4|41.0","tooltip":"AMD Ryzen 7 PRO 3700U","class":"normal","percentage":7}
|
||||
{"module":"mem","text":"9.41|15.49","class":"normal","percentage":60}
|
||||
{"module":"cpu","text":"6.9|40.5","tooltip":"AMD Ryzen 7 PRO 3700U","class":"normal","percentage":6}
|
||||
```
|
||||
|
||||
Each line is one complete JSON object: a `module` key naming the source, plus the
|
||||
module's usual `text` and — when set — `tooltip`, `class` and `percentage`. A full
|
||||
snapshot of every subscribed module is sent immediately on connect, so a bar
|
||||
renders correctly the moment it attaches rather than after the first change.
|
||||
|
||||
Two deliberate differences from the one-shot client:
|
||||
|
||||
- `text` is **not** padded with figure-spaces and zero-width spaces. That padding
|
||||
exists to stop Waybar's proportional font from reflowing, and is noise to a
|
||||
consumer doing its own layout.
|
||||
- Modules without a watch channel (`power`, `game`, `pool`) are re-evaluated on a
|
||||
5 second sweep rather than event-driven. Unchanged output is never written, so a
|
||||
quiet sweep costs nothing on the wire.
|
||||
|
||||
Quickshell, for example, needs one `Process` for the whole bar:
|
||||
|
||||
```qml
|
||||
Process {
|
||||
running: true
|
||||
command: ["fluxo", "stream", "cpu", "mem", "gpu", "net", "sys"]
|
||||
stdout: SplitParser {
|
||||
onRead: line => {
|
||||
const ev = JSON.parse(line);
|
||||
// dispatch on ev.module
|
||||
}
|
||||
}
|
||||
onExited: reconnectTimer.restart()
|
||||
}
|
||||
```
|
||||
|
||||
The connection dies when the daemon restarts, so drive `running` back to `true`
|
||||
from a timer — that is a reconnect, not a poll, and only ever fires while the
|
||||
stream is actually down.
|
||||
|
||||
## Debugging
|
||||
|
||||
Use `--loglevel` to control log verbosity (trace, debug, info, warn, error):
|
||||
|
||||
Reference in New Issue
Block a user