Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1152ce1b9 | |||
| 230604dae3 |
@@ -64,31 +64,31 @@ jobs:
|
||||
VERSION: ${{ steps.get_version.outputs.VERSION }}
|
||||
TAG: ${{ steps.get_version.outputs.TAG }}
|
||||
run: |
|
||||
PKG="fluxo-rs_${VERSION}_amd64"
|
||||
PKG="fluxo_${VERSION}_amd64"
|
||||
|
||||
mkdir -p "${PKG}/DEBIAN"
|
||||
mkdir -p "${PKG}/usr/bin"
|
||||
|
||||
cp target/release/fluxo-rs "${PKG}/usr/bin/"
|
||||
strip "${PKG}/usr/bin/fluxo-rs"
|
||||
cp target/release/fluxo "${PKG}/usr/bin/"
|
||||
strip "${PKG}/usr/bin/fluxo"
|
||||
|
||||
printf '%s\n' \
|
||||
"Package: fluxo-rs" \
|
||||
"Package: fluxo" \
|
||||
"Version: ${VERSION}" \
|
||||
"Section: utils" \
|
||||
"Priority: optional" \
|
||||
"Architecture: amd64" \
|
||||
"Maintainer: fluxo-rs contributors" \
|
||||
"Maintainer: fluxo contributors" \
|
||||
"Description: High-performance daemon/client for Waybar custom modules" \
|
||||
" fluxo-rs is a compiled Rust daemon that polls system metrics and" \
|
||||
" fluxo is a compiled Rust daemon that polls system metrics and" \
|
||||
" serves formatted JSON output to Waybar custom modules over a Unix" \
|
||||
" domain socket. Replaces shell scripts with a single binary." \
|
||||
> "${PKG}/DEBIAN/control"
|
||||
|
||||
dpkg-deb --build "${PKG}"
|
||||
|
||||
mv "${PKG}.deb" "fluxo-rs-${TAG}-amd64.deb"
|
||||
echo "Built: fluxo-rs-${TAG}-amd64.deb"
|
||||
mv "${PKG}.deb" "fluxo-${TAG}-amd64.deb"
|
||||
echo "Built: fluxo-${TAG}-amd64.deb"
|
||||
|
||||
- name: Create Release and Upload Assets
|
||||
if: steps.check_release.outputs.EXISTS == 'false'
|
||||
@@ -101,8 +101,8 @@ jobs:
|
||||
Commit: ${{ github.sha }}
|
||||
Branch: ${{ github.ref_name }}
|
||||
files: |
|
||||
fluxo-rs-${{ steps.get_version.outputs.TAG }}-amd64.deb
|
||||
target/release/fluxo-rs
|
||||
fluxo-${{ steps.get_version.outputs.TAG }}-amd64.deb
|
||||
target/release/fluxo
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
|
||||
Generated
+1
-1
@@ -572,7 +572,7 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "fluxo-rs"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bluer",
|
||||
|
||||
+18
-1
@@ -1,8 +1,12 @@
|
||||
[package]
|
||||
name = "fluxo-rs"
|
||||
version = "0.5.2"
|
||||
version = "0.5.4"
|
||||
edition = "2024"
|
||||
|
||||
[[bin]]
|
||||
name = "fluxo"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
default = ["mod-audio", "mod-bt", "mod-network", "mod-hardware", "mod-dbus"]
|
||||
mod-audio = ["dep:libpulse-binding"]
|
||||
@@ -38,3 +42,16 @@ zbus = { version = "5", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
|
||||
[package.metadata.deb]
|
||||
maintainer = "Nils Pukropp"
|
||||
copyright = "2024-2026 Nils Pukropp"
|
||||
depends = "$auto"
|
||||
section = "utils"
|
||||
priority = "optional"
|
||||
assets = [
|
||||
["target/release/fluxo", "usr/bin/", "755"],
|
||||
["dist/fluxo.service", "usr/lib/systemd/user/", "644"],
|
||||
["README.md", "usr/share/doc/fluxo/", "644"],
|
||||
["example.config.toml", "usr/share/doc/fluxo/", "644"],
|
||||
]
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# fluxo-rs
|
||||
# fluxo
|
||||
|
||||
`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.
|
||||
`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.
|
||||
|
||||
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
|
||||
|
||||
- **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.
|
||||
- **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.
|
||||
- **Multi-threaded Polling**: Decoupled Tokio subsystem threads ensure that a hang in one system (e.g., a slow GPU probe) never freezes your Waybar.
|
||||
@@ -33,11 +33,60 @@ With its **100% Native, Content-Based Event-Driven Architecture**, it consumes e
|
||||
| `kbd` | Keyboard Layout | `{layout}` |
|
||||
| `dnd` | Do Not Disturb (SwayNC) | active/inactive strings |
|
||||
|
||||
## Installation
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
cargo build --release
|
||||
cp target/release/fluxo ~/.cargo/bin/
|
||||
```
|
||||
|
||||
### Debian/Ubuntu (.deb)
|
||||
|
||||
```bash
|
||||
cargo install cargo-deb
|
||||
cargo deb
|
||||
sudo dpkg -i target/debian/fluxo-rs_*.deb
|
||||
```
|
||||
|
||||
The `.deb` package installs the binary to `/usr/bin/fluxo`, the systemd user service to `/usr/lib/systemd/user/fluxo.service`, and documentation to `/usr/share/doc/fluxo/`.
|
||||
|
||||
## Setup
|
||||
|
||||
1. **Build**: `cargo build --release`
|
||||
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.
|
||||
1. **Configure**: Create `~/.config/fluxo/config.toml` (see `example.config.toml`). Ensure you map your `[signals]`.
|
||||
2. **Start the daemon** via systemd (recommended) or manually:
|
||||
|
||||
### systemd (recommended)
|
||||
|
||||
If installed from the `.deb`, the service file is already in place. For manual installs:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cp dist/fluxo.service ~/.config/systemd/user/
|
||||
```
|
||||
|
||||
If your binary is not at `~/.cargo/bin/fluxo`, edit the `ExecStart=` path in the service file.
|
||||
|
||||
Then enable and start:
|
||||
|
||||
```bash
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now fluxo
|
||||
```
|
||||
|
||||
Check status:
|
||||
|
||||
```bash
|
||||
systemctl --user status fluxo
|
||||
journalctl --user -u fluxo -f
|
||||
```
|
||||
|
||||
### Manual
|
||||
|
||||
```bash
|
||||
fluxo daemon
|
||||
```
|
||||
|
||||
## Waybar Configuration
|
||||
|
||||
@@ -45,21 +94,21 @@ To achieve zero-latency updates and zero-polling CPU usage, set `interval: 0` on
|
||||
|
||||
```jsonc
|
||||
"custom/volume": {
|
||||
"exec": "fluxo-rs vol",
|
||||
"exec": "fluxo vol",
|
||||
"return-type": "json",
|
||||
"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"
|
||||
"on-click": "fluxo vol mute",
|
||||
"on-scroll-up": "fluxo vol up 1",
|
||||
"on-scroll-down": "fluxo vol down 1",
|
||||
"on-click-right": "fluxo vol cycle"
|
||||
},
|
||||
"custom/bluetooth-audio": {
|
||||
"format": "{}",
|
||||
"return-type": "json",
|
||||
"exec": "fluxo-rs bt",
|
||||
"on-click": "fluxo-rs bt menu",
|
||||
"on-click-right": "fluxo-rs bt cycle_mode",
|
||||
"exec": "fluxo bt",
|
||||
"on-click": "fluxo bt menu",
|
||||
"on-click-right": "fluxo bt cycle_mode",
|
||||
"signal": 9,
|
||||
"interval": 0,
|
||||
"tooltip": true
|
||||
@@ -68,7 +117,21 @@ To achieve zero-latency updates and zero-polling CPU usage, set `interval: 0` on
|
||||
|
||||
## Debugging
|
||||
|
||||
Start the daemon with `RUST_LOG=debug` to see detailed logs of library interactions and circuit breaker status:
|
||||
Use `--loglevel` to control log verbosity (trace, debug, info, warn, error):
|
||||
|
||||
```bash
|
||||
RUST_LOG=debug fluxo-rs daemon
|
||||
fluxo daemon --loglevel debug
|
||||
```
|
||||
|
||||
Or via the `RUST_LOG` environment variable:
|
||||
|
||||
```bash
|
||||
RUST_LOG=debug fluxo daemon
|
||||
```
|
||||
|
||||
For module help and available arguments:
|
||||
|
||||
```bash
|
||||
fluxo help # overview of all modules
|
||||
fluxo help vol # detailed help for a specific module
|
||||
```
|
||||
|
||||
+4
-3
@@ -466,11 +466,12 @@ fn print_module_detail(m: &ModuleHelp) {
|
||||
println!("\x1b[1mFORMAT TOKENS:\x1b[0m (for use in config.toml format strings)\n");
|
||||
let max_token = m.tokens.iter().map(|(t, _)| t.len()).max().unwrap_or(0);
|
||||
for (token, desc) in m.tokens {
|
||||
let padded = format!("{{{}}}", token);
|
||||
println!(
|
||||
" \x1b[33m{{{:<width$}}}\x1b[0m {}",
|
||||
token,
|
||||
" \x1b[33m{:<width$}\x1b[0m {}",
|
||||
padded,
|
||||
desc,
|
||||
width = max_token
|
||||
width = max_token + 2 // +2 for the braces
|
||||
);
|
||||
}
|
||||
println!();
|
||||
|
||||
+48
-4
@@ -30,20 +30,49 @@ mod signaler;
|
||||
mod state;
|
||||
mod utils;
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use tracing::{error, info};
|
||||
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
||||
|
||||
#[derive(Clone, ValueEnum)]
|
||||
enum LogLevel {
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
|
||||
impl From<LogLevel> for tracing::Level {
|
||||
fn from(level: LogLevel) -> Self {
|
||||
match level {
|
||||
LogLevel::Trace => tracing::Level::TRACE,
|
||||
LogLevel::Debug => tracing::Level::DEBUG,
|
||||
LogLevel::Info => tracing::Level::INFO,
|
||||
LogLevel::Warn => tracing::Level::WARN,
|
||||
LogLevel::Error => tracing::Level::ERROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "fluxo")]
|
||||
#[command(about = "A high-performance daemon/client for Waybar custom modules", long_about = None)]
|
||||
#[command(disable_help_subcommand = true)]
|
||||
#[command(disable_help_subcommand = true, disable_help_flag = true)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
|
||||
/// Print help information
|
||||
#[arg(short, long, global = true)]
|
||||
help: bool,
|
||||
|
||||
/// Set the log level (trace, debug, info, warn, error)
|
||||
#[arg(long, global = true, value_enum)]
|
||||
loglevel: Option<LogLevel>,
|
||||
|
||||
/// Module name to query or interact with
|
||||
module: Option<String>,
|
||||
|
||||
@@ -70,12 +99,27 @@ enum Commands {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
// Explicit --loglevel takes priority, then RUST_LOG env var, then a
|
||||
// sensible default: INFO for the daemon, WARN for client commands.
|
||||
let default_level = if let Some(level) = &cli.loglevel {
|
||||
tracing::Level::from(level.clone())
|
||||
} else if matches!(&cli.command, Some(Commands::Daemon { .. })) {
|
||||
tracing::Level::INFO
|
||||
} else {
|
||||
tracing::Level::WARN
|
||||
};
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt::layer().with_target(false).pretty())
|
||||
.with(EnvFilter::from_default_env().add_directive(tracing::Level::INFO.into()))
|
||||
.with(EnvFilter::from_default_env().add_directive(default_level.into()))
|
||||
.init();
|
||||
|
||||
let cli = Cli::parse();
|
||||
if cli.help {
|
||||
help::print_help(None);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(command) = &cli.command {
|
||||
match command {
|
||||
|
||||
@@ -58,7 +58,7 @@ impl AudioDaemon {
|
||||
ThreadedMainloop::new().expect("Failed to create pulse threaded mainloop");
|
||||
|
||||
let mut context =
|
||||
Context::new(&mainloop, "fluxo-rs").expect("Failed to create pulse context");
|
||||
Context::new(&mainloop, "fluxo").expect("Failed to create pulse context");
|
||||
|
||||
context
|
||||
.connect(None, ContextFlag::NOFLAGS, None)
|
||||
|
||||
Reference in New Issue
Block a user