This commit is contained in:
@@ -64,31 +64,31 @@ jobs:
|
|||||||
VERSION: ${{ steps.get_version.outputs.VERSION }}
|
VERSION: ${{ steps.get_version.outputs.VERSION }}
|
||||||
TAG: ${{ steps.get_version.outputs.TAG }}
|
TAG: ${{ steps.get_version.outputs.TAG }}
|
||||||
run: |
|
run: |
|
||||||
PKG="fluxo-rs_${VERSION}_amd64"
|
PKG="fluxo_${VERSION}_amd64"
|
||||||
|
|
||||||
mkdir -p "${PKG}/DEBIAN"
|
mkdir -p "${PKG}/DEBIAN"
|
||||||
mkdir -p "${PKG}/usr/bin"
|
mkdir -p "${PKG}/usr/bin"
|
||||||
|
|
||||||
cp target/release/fluxo-rs "${PKG}/usr/bin/"
|
cp target/release/fluxo "${PKG}/usr/bin/"
|
||||||
strip "${PKG}/usr/bin/fluxo-rs"
|
strip "${PKG}/usr/bin/fluxo"
|
||||||
|
|
||||||
printf '%s\n' \
|
printf '%s\n' \
|
||||||
"Package: fluxo-rs" \
|
"Package: fluxo" \
|
||||||
"Version: ${VERSION}" \
|
"Version: ${VERSION}" \
|
||||||
"Section: utils" \
|
"Section: utils" \
|
||||||
"Priority: optional" \
|
"Priority: optional" \
|
||||||
"Architecture: amd64" \
|
"Architecture: amd64" \
|
||||||
"Maintainer: fluxo-rs contributors" \
|
"Maintainer: fluxo contributors" \
|
||||||
"Description: High-performance daemon/client for Waybar custom modules" \
|
"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" \
|
" serves formatted JSON output to Waybar custom modules over a Unix" \
|
||||||
" domain socket. Replaces shell scripts with a single binary." \
|
" domain socket. Replaces shell scripts with a single binary." \
|
||||||
> "${PKG}/DEBIAN/control"
|
> "${PKG}/DEBIAN/control"
|
||||||
|
|
||||||
dpkg-deb --build "${PKG}"
|
dpkg-deb --build "${PKG}"
|
||||||
|
|
||||||
mv "${PKG}.deb" "fluxo-rs-${TAG}-amd64.deb"
|
mv "${PKG}.deb" "fluxo-${TAG}-amd64.deb"
|
||||||
echo "Built: fluxo-rs-${TAG}-amd64.deb"
|
echo "Built: fluxo-${TAG}-amd64.deb"
|
||||||
|
|
||||||
- name: Create Release and Upload Assets
|
- name: Create Release and Upload Assets
|
||||||
if: steps.check_release.outputs.EXISTS == 'false'
|
if: steps.check_release.outputs.EXISTS == 'false'
|
||||||
@@ -101,8 +101,8 @@ jobs:
|
|||||||
Commit: ${{ github.sha }}
|
Commit: ${{ github.sha }}
|
||||||
Branch: ${{ github.ref_name }}
|
Branch: ${{ github.ref_name }}
|
||||||
files: |
|
files: |
|
||||||
fluxo-rs-${{ steps.get_version.outputs.TAG }}-amd64.deb
|
fluxo-${{ steps.get_version.outputs.TAG }}-amd64.deb
|
||||||
target/release/fluxo-rs
|
target/release/fluxo
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
env:
|
env:
|
||||||
|
|||||||
Generated
+1
-1
@@ -572,7 +572,7 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fluxo-rs"
|
name = "fluxo-rs"
|
||||||
version = "0.5.2"
|
version = "0.5.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bluer",
|
"bluer",
|
||||||
|
|||||||
+5
-1
@@ -1,8 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fluxo-rs"
|
name = "fluxo-rs"
|
||||||
version = "0.5.2"
|
version = "0.5.3"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "fluxo"
|
||||||
|
path = "src/main.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["mod-audio", "mod-bt", "mod-network", "mod-hardware", "mod-dbus"]
|
default = ["mod-audio", "mod-bt", "mod-network", "mod-hardware", "mod-dbus"]
|
||||||
mod-audio = ["dep:libpulse-binding"]
|
mod-audio = ["dep:libpulse-binding"]
|
||||||
|
|||||||
@@ -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.
|
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
|
## 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.
|
- **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.
|
- **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.
|
- **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.
|
- **Multi-threaded Polling**: Decoupled Tokio subsystem threads ensure that a hang in one system (e.g., a slow GPU probe) never freezes your Waybar.
|
||||||
@@ -37,7 +37,7 @@ With its **100% Native, Content-Based Event-Driven Architecture**, it consumes e
|
|||||||
|
|
||||||
1. **Build**: `cargo build --release`
|
1. **Build**: `cargo build --release`
|
||||||
2. **Configure**: Create `~/.config/fluxo/config.toml` (see `example.config.toml`). Ensure you map your `[signals]`.
|
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.
|
3. **Daemon**: Start `fluxo daemon`. It is highly recommended to run this as a systemd user service.
|
||||||
|
|
||||||
## Waybar Configuration
|
## Waybar Configuration
|
||||||
|
|
||||||
@@ -45,21 +45,21 @@ To achieve zero-latency updates and zero-polling CPU usage, set `interval: 0` on
|
|||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
"custom/volume": {
|
"custom/volume": {
|
||||||
"exec": "fluxo-rs vol",
|
"exec": "fluxo vol",
|
||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"interval": 0,
|
"interval": 0,
|
||||||
"signal": 8, // Must match the value in config.toml [signals]
|
"signal": 8, // Must match the value in config.toml [signals]
|
||||||
"on-click": "fluxo-rs vol mute",
|
"on-click": "fluxo vol mute",
|
||||||
"on-scroll-up": "fluxo-rs vol up 1",
|
"on-scroll-up": "fluxo vol up 1",
|
||||||
"on-scroll-down": "fluxo-rs vol down 1",
|
"on-scroll-down": "fluxo vol down 1",
|
||||||
"on-click-right": "fluxo-rs vol cycle"
|
"on-click-right": "fluxo vol cycle"
|
||||||
},
|
},
|
||||||
"custom/bluetooth-audio": {
|
"custom/bluetooth-audio": {
|
||||||
"format": "{}",
|
"format": "{}",
|
||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"exec": "fluxo-rs bt",
|
"exec": "fluxo bt",
|
||||||
"on-click": "fluxo-rs bt menu",
|
"on-click": "fluxo bt menu",
|
||||||
"on-click-right": "fluxo-rs bt cycle_mode",
|
"on-click-right": "fluxo bt cycle_mode",
|
||||||
"signal": 9,
|
"signal": 9,
|
||||||
"interval": 0,
|
"interval": 0,
|
||||||
"tooltip": true
|
"tooltip": true
|
||||||
@@ -70,5 +70,5 @@ To achieve zero-latency updates and zero-polling CPU usage, set `interval: 0` on
|
|||||||
|
|
||||||
Start the daemon with `RUST_LOG=debug` to see detailed logs of library interactions and circuit breaker status:
|
Start the daemon with `RUST_LOG=debug` to see detailed logs of library interactions and circuit breaker status:
|
||||||
```bash
|
```bash
|
||||||
RUST_LOG=debug fluxo-rs daemon
|
RUST_LOG=debug fluxo daemon
|
||||||
```
|
```
|
||||||
|
|||||||
+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");
|
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);
|
let max_token = m.tokens.iter().map(|(t, _)| t.len()).max().unwrap_or(0);
|
||||||
for (token, desc) in m.tokens {
|
for (token, desc) in m.tokens {
|
||||||
|
let padded = format!("{{{}}}", token);
|
||||||
println!(
|
println!(
|
||||||
" \x1b[33m{{{:<width$}}}\x1b[0m {}",
|
" \x1b[33m{:<width$}\x1b[0m {}",
|
||||||
token,
|
padded,
|
||||||
desc,
|
desc,
|
||||||
width = max_token
|
width = max_token + 2 // +2 for the braces
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
|
|||||||
+48
-4
@@ -30,20 +30,49 @@ mod signaler;
|
|||||||
mod state;
|
mod state;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
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)]
|
#[derive(Parser)]
|
||||||
#[command(name = "fluxo")]
|
#[command(name = "fluxo")]
|
||||||
#[command(about = "A high-performance daemon/client for Waybar custom modules", long_about = None)]
|
#[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 {
|
struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
command: Option<Commands>,
|
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 name to query or interact with
|
||||||
module: Option<String>,
|
module: Option<String>,
|
||||||
|
|
||||||
@@ -70,12 +99,27 @@ enum Commands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
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()
|
tracing_subscriber::registry()
|
||||||
.with(fmt::layer().with_target(false).pretty())
|
.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();
|
.init();
|
||||||
|
|
||||||
let cli = Cli::parse();
|
if cli.help {
|
||||||
|
help::print_help(None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(command) = &cli.command {
|
if let Some(command) = &cli.command {
|
||||||
match command {
|
match command {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ impl AudioDaemon {
|
|||||||
ThreadedMainloop::new().expect("Failed to create pulse threaded mainloop");
|
ThreadedMainloop::new().expect("Failed to create pulse threaded mainloop");
|
||||||
|
|
||||||
let mut context =
|
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
|
context
|
||||||
.connect(None, ContextFlag::NOFLAGS, None)
|
.connect(None, ContextFlag::NOFLAGS, None)
|
||||||
|
|||||||
Reference in New Issue
Block a user