Lots of misc code changes

This commit is contained in:
Skye 2023-12-14 23:01:39 -05:00
parent c0f832bcef
commit 5fab9bc98b
13 changed files with 112 additions and 111 deletions

View file

@ -4,18 +4,17 @@ use crate::tiles;
use dbus::nonblock::SyncConnection;
use log::error;
use log::warn;
use serde::{Deserialize, Deserializer};
use smart_default::SmartDefault;
use std::env::var;
use std::env::var;
use std::iter::FromIterator as _;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use structopt::StructOpt;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
@ -97,16 +96,24 @@ pub struct HostnameConfig {
pub update: Duration,
}
type StaticStr = &'static str;
#[derive(SmartDefault, Deserialize, Clone, Debug)]
#[serde(default)]
pub struct IwdConfig {
#[default("wlan0")]
pub interface: Box<str>,
#[serde(deserialize_with = "leak_str")]
// Gotta obfuscate the static lifetime or derive(Deserialize) misbehaves
pub interface: StaticStr,
#[serde(deserialize_with = "deserialize_duration")]
#[default(_code = "Duration::from_secs(5)")]
pub update: Duration,
}
fn leak_str<'de, D: Deserializer<'de>>(deserializer: D) -> Result<&'static str, D::Error> {
Ok(Box::leak(Box::<str>::deserialize(deserializer)?))
}
#[derive(SmartDefault, Deserialize, Clone, Debug)]
#[serde(default)]
pub struct UtcTimeConfig {
@ -173,31 +180,29 @@ struct Args {
pub async fn read_config() -> eyre::Result<Config> {
let args = Args::from_args();
let config_path = match args.config {
Some(config) => config,
None => {
if let Ok(rustybar_config_env) = var("RUSTYBAR_CONFIG") {
rustybar_config_env.into()
} else if let Ok(xdg_config_home) = var("XDG_CONFIG_HOME") {
[&xdg_config_home, "rustybar", "config.toml"]
.iter()
.collect()
let Some(config_path) = args.config.clone().or_else(|| {
Some(if let Ok(rusty_conf) = var("RUSTYBAR_CONFIG") {
rusty_conf.into()
} else if let Ok(config) = var("XDG_CONFIG_HOME") {
PathBuf::from_iter([&config, "rustybar/config.toml"])
} else if let Ok(home) = var("HOME") {
[&home, ".config", "rustybar", "config.toml"]
.iter()
.collect()
PathBuf::from_iter([&home, ".config/rustybar/config.toml"])
} else {
eyre::bail!("Could not find RUSTYBAR_CONFIG, XDG_CONFIG_HOME, or HOME environment variables");
}
}
return None;
})
}) else {
eyre::bail!(
"Could not find RUSTYBAR_CONFIG, XDG_CONFIG_HOME, or HOME environment variables"
)
};
let mut config_contents = vec![];
File::open(config_path)
.await?
.read_to_end(&mut config_contents)
.await?;
Ok(toml::from_str(std::str::from_utf8(&config_contents)?)?)
let string = tokio::fs::read_to_string(config_path)
.await
.or_else(|e| match e.kind() {
std::io::ErrorKind::NotFound => Ok(include_str!("../config.toml.example").to_owned()),
_ => Err(e),
})?;
Ok(toml::from_str(&string)?)
}
pub fn launch_tile(
@ -223,7 +228,7 @@ pub fn launch_tile(
}
};
match result {
Ok(_) => warn!("Tile {} exited without error", tile_id),
Ok(t) => match t {},
Err(e) => error!("Tile {} exited with error: {:?}", tile_id, e),
}
})

View file

@ -45,12 +45,11 @@ pub async fn run(num_tiles: usize, mut receiver: mpsc::Receiver<TileData>) -> ey
.await
.ok_or_eyre("No more messages to recieve")?;
if message.sender_id < num_tiles {
blocks[message.sender_id] = Some(message.block);
} else {
let Some(block) = blocks.get_mut(message.sender_id) else {
eprintln!("Invalid message with sender id {}", message.sender_id);
continue;
}
};
*block = Some(message.block);
let mut serialized = serde_json::to_vec(&blocks).unwrap();
serialized.extend_from_slice(b",\n");
stdout.write_all(&serialized).await?;

View file

@ -74,7 +74,7 @@ pub struct Block {
pub min_width: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub align: Option<Alignment>,
pub name: Box<str>,
pub name: &'static str,
#[serde(serialize_with = "arc_default")]
#[default = ""]
pub instance: Arc<str>,

View file

@ -2,12 +2,12 @@ use crate::config::BatteryConfig;
use crate::output::OutputChannel;
use crate::tile::Block;
use std::convert::Infallible;
use std::path::Path;
use tokio::fs::{try_exists, File};
use tokio::io::AsyncReadExt;
use tokio::fs::try_exists;
use tokio::try_join;
pub async fn battery(config: BatteryConfig, output: OutputChannel) -> eyre::Result<()> {
pub async fn battery(config: BatteryConfig, output: OutputChannel) -> eyre::Result<Infallible> {
let base_dir = Path::new("/sys/class/power_supply").join(&*config.battery);
let file_prefix = if try_exists(base_dir.join("energy_now")).await? {
"energy_"
@ -16,45 +16,26 @@ pub async fn battery(config: BatteryConfig, output: OutputChannel) -> eyre::Resu
};
let now_path = base_dir.join(file_prefix.to_owned() + "now");
let full_path = base_dir.join(file_prefix.to_owned() + "full");
let status_path = base_dir.join("status");
let mut interval = tokio::time::interval(config.update);
loop {
interval.tick().await;
let charge_now = async {
let mut raw = String::new();
File::open(&now_path)
.await?
.read_to_string(&mut raw)
.await?;
let charge: u32 = raw.trim_end().parse()?;
eyre::Result::<_>::Ok(charge)
};
let charge_total = async {
let mut raw = String::new();
File::open(&full_path)
.await?
.read_to_string(&mut raw)
.await?;
let charge: u32 = raw.trim_end().parse()?;
eyre::Result::<_>::Ok(charge)
};
let status = async {
let mut raw = String::new();
File::open(base_dir.join("status"))
.await?
.read_to_string(&mut raw)
.await?;
raw.truncate(raw.trim_end().len());
eyre::Result::<_>::Ok(raw)
};
async fn read_file_to_string(path: &Path) -> eyre::Result<u32> {
Ok(tokio::fs::read_to_string(path).await?.trim_end().parse()?)
}
let charge_now = read_file_to_string(&now_path);
let charge_total = read_file_to_string(&full_path);
let status = read_file_to_string(&status_path);
let (charge_now, charge_total, status) = try_join!(charge_now, charge_total, status)?;
let percentage = charge_now * 100 / charge_total;
output
.send(Block {
full_text: format!("{}% {}", percentage, status).into(),
short_text: format!("{}%", percentage).into_boxed_str().into(),
name: "battery".into(),
name: "battery",
..Default::default()
})
.await?;

View file

@ -3,6 +3,7 @@ use crate::generated::OrgFreedesktopHostname1;
use crate::output::OutputChannel;
use crate::tile::Block;
use dbus::nonblock::{Proxy, SyncConnection};
use std::convert::Infallible;
use std::sync::Arc;
use std::time::Duration;
@ -10,7 +11,7 @@ pub async fn hostname(
config: HostnameConfig,
output: OutputChannel,
dbus_conn: Arc<SyncConnection>,
) -> eyre::Result<()> {
) -> eyre::Result<Infallible> {
let proxy = Proxy::new(
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
@ -26,7 +27,7 @@ pub async fn hostname(
output
.send(Block {
full_text: hostname.into(),
name: "hostname".into(),
name: "hostname",
..Default::default()
})
.await?;

View file

@ -1,10 +1,15 @@
use std::convert::Infallible;
use crate::config::InternetTimeConfig;
use crate::output::OutputChannel;
use crate::tile::Block;
use chrono::prelude::*;
use tokio::time::sleep;
pub async fn internet_time(config: InternetTimeConfig, output: OutputChannel) -> eyre::Result<()> {
pub async fn internet_time(
config: InternetTimeConfig,
output: OutputChannel,
) -> eyre::Result<Infallible> {
// "BMT" is actually just UTC+1
let offset = FixedOffset::east_opt(60 * 60).unwrap();
let factor = 10f64.powi(config.precision.into());
@ -18,15 +23,14 @@ pub async fn internet_time(config: InternetTimeConfig, output: OutputChannel) ->
output
.send(Block {
full_text: format!(
"@{time:0width$.prec$}",
time = internet_time,
"@{internet_time:0width$.prec$}",
// 3 digits + and decimal point
width = config.precision as usize + 4,
prec = config.precision as usize
)
.into_boxed_str(),
short_text: Some(format!("@{:03.0}", internet_time).into_boxed_str()),
name: "internet_time".into(),
name: "internet_time",
..Default::default()
})
.await?;

View file

@ -7,6 +7,7 @@ use dbus::nonblock::{Proxy, SyncConnection};
use dbus::Path;
use eyre::OptionExt;
use std::collections::HashMap;
use std::convert::Infallible;
use std::sync::Arc;
use std::time::Duration;
@ -32,7 +33,7 @@ pub async fn iwd(
config: IwdConfig,
output: OutputChannel,
dbus_conn: Arc<SyncConnection>,
) -> eyre::Result<()> {
) -> eyre::Result<Infallible> {
let root_proxy = Proxy::new("net.connman.iwd", "/", Duration::from_secs(5), dbus_conn);
let mut interval = tokio::time::interval(config.update);
@ -40,7 +41,7 @@ pub async fn iwd(
interval.tick().await;
let managed_objects = root_proxy.get_managed_objects().await?;
let interface_path = get_interface_path(&managed_objects, &config.interface)
let interface_path = get_interface_path(&managed_objects, config.interface)
.ok_or_eyre("Couldn't find interface")?;
let station_path = managed_objects
.get(&interface_path)
@ -62,7 +63,7 @@ pub async fn iwd(
output
.send(Block {
full_text: text.into(),
name: config.interface.clone(),
name: config.interface,
..Default::default()
})
.await?;

View file

@ -1,22 +1,22 @@
use std::convert::Infallible;
use crate::config::LoadConfig;
use crate::output::OutputChannel;
use crate::tile::Block;
use tokio::fs::File;
use tokio::io::AsyncReadExt;
pub async fn load(config: LoadConfig, output: OutputChannel) -> eyre::Result<()> {
pub async fn load(config: LoadConfig, output: OutputChannel) -> eyre::Result<Infallible> {
let mut interval = tokio::time::interval(config.update);
loop {
interval.tick().await;
let mut raw = String::new();
let mut file = File::open("/proc/loadavg").await?;
file.read_to_string(&mut raw).await?;
let (load, _rest) = raw.split_at(raw.find(' ').unwrap_or(0));
let raw = tokio::fs::read_to_string("/proc/loadavg").await?;
let Some((load, _)) = raw.split_once(' ') else {
continue;
};
output
.send(Block {
full_text: load.into(),
name: "load".into(),
name: "load",
..Default::default()
})
.await?;

View file

@ -4,6 +4,7 @@ use crate::tile::Block;
use chrono::prelude::*;
use maxminddb::geoip2;
use std::convert::Infallible;
use std::net::IpAddr;
use std::str::FromStr;
use tokio::sync::watch;
@ -66,12 +67,14 @@ async fn find_time_zone(config: LocalTimeConfig, sender: watch::Sender<State>) -
}
}
pub async fn local_time(config: LocalTimeConfig, output: OutputChannel) -> eyre::Result<()> {
let fallback_tz = if let Some(tz_name) = &config.fallback_zone {
chrono_tz::Tz::from_str(tz_name).ok()
} else {
None
};
pub async fn local_time(
config: LocalTimeConfig,
output: OutputChannel,
) -> eyre::Result<Infallible> {
let fallback_tz = config
.fallback_zone
.as_ref()
.and_then(|tz_name| chrono_tz::Tz::from_str(tz_name).ok());
let (sender, mut receiver) = watch::channel(State { tz: fallback_tz });
let config_clone = config.clone();
@ -97,7 +100,7 @@ pub async fn local_time(config: LocalTimeConfig, output: OutputChannel) -> eyre:
.send(Block {
full_text: local_now.format(&config.format).to_string().into(),
short_text: Some(local_now.format(&config.short_format).to_string().into()),
name: "local_time".into(),
name: "local_time",
..Default::default()
})
.await?;

View file

@ -1,6 +1,7 @@
use crate::config::MemoryConfig;
use crate::output::OutputChannel;
use crate::tile::Block;
use std::convert::Infallible;
use std::{io, str, u64};
use tokio::fs::File;
use tokio::io::AsyncReadExt;
@ -9,11 +10,11 @@ fn prettify_kib(kib: u64) -> Box<str> {
let (mem, unit) = match kib {
0..=0x3ff => (kib, 'k'),
0x400..=0xfffff => (kib >> 10, 'M'),
0x100000..=0x3fffffff => (kib >> 20, 'G'),
0x40000000..=0xffffffffff => (kib >> 30, 'T'),
0x10000000000..=0x3ffffffffffff => (kib >> 40, 'P'),
0x4000000000000..=0xfffffffffffffff => (kib >> 50, 'E'),
0x1000000000000000..=0xffffffffffffffff => (kib >> 60, 'Z'),
0x10_0000..=0x3fff_ffff => (kib >> 20, 'G'),
0x4000_0000..=0xff_ffff_ffff => (kib >> 30, 'T'),
0x100_0000_0000..=0x3_ffff_ffff_ffff => (kib >> 40, 'P'),
0x4_0000_0000_0000..=0xfff_ffff_ffff_ffff => (kib >> 50, 'E'),
0x1000_0000_0000_0000..=0xffff_ffff_ffff_ffff => (kib >> 60, 'Z'),
};
format!("{} {}iB", mem, unit).into_boxed_str()
}
@ -27,7 +28,7 @@ fn extract_value(line: &str) -> eyre::Result<u64> {
.parse()?)
}
pub async fn memory(config: MemoryConfig, output: OutputChannel) -> eyre::Result<()> {
pub async fn memory(config: MemoryConfig, output: OutputChannel) -> eyre::Result<Infallible> {
let mut interval = tokio::time::interval(config.update);
loop {
interval.tick().await;
@ -36,7 +37,7 @@ pub async fn memory(config: MemoryConfig, output: OutputChannel) -> eyre::Result
let mut file = File::open("/proc/meminfo").await?;
file.read_exact(&mut raw).await?;
let string_data = str::from_utf8(&raw)?;
let mut lines = string_data.split('\n');
let mut lines = string_data.lines();
let mem_total = prettify_kib(extract_value(
lines
.next()
@ -56,7 +57,7 @@ pub async fn memory(config: MemoryConfig, output: OutputChannel) -> eyre::Result
.send(Block {
full_text,
short_text: Some(short_text),
name: "memory".into(),
name: "memory",
..Default::default()
})
.await?;

View file

@ -3,21 +3,22 @@ use crate::generated::OrgFreedesktopNetworkManager;
use crate::generated::OrgFreedesktopNetworkManagerAccessPoint;
use crate::generated::OrgFreedesktopNetworkManagerConnectionActive;
use crate::output::OutputChannel;
use crate::tile::Block;
use dbus::nonblock::{Proxy, SyncConnection};
use std::convert::Infallible;
use std::future::pending;
use std::sync::Arc;
use std::time::Duration;
pub async fn network_manager(
config: NetworkManagerConfig,
output: OutputChannel,
_config: NetworkManagerConfig,
_output: OutputChannel,
dbus_conn: Arc<SyncConnection>,
) -> eyre::Result<()> {
) -> eyre::Result<Infallible> {
let root_proxy = Proxy::new(
"org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager",
Duration::from_secs(5),
dbus_conn.clone(),
dbus_conn.as_ref(),
);
let primary_connection = root_proxy.primary_connection().await?;
@ -25,7 +26,7 @@ pub async fn network_manager(
"org.freedesktop.NetworkManager",
primary_connection,
Duration::from_secs(5),
dbus_conn.clone(),
dbus_conn.as_ref(),
);
let specific_object = primary_connection_proxy.specific_object().await?;
@ -33,14 +34,12 @@ pub async fn network_manager(
"org.freedesktop.NetworkManager",
specific_object,
Duration::from_secs(5),
dbus_conn.clone(),
dbus_conn.as_ref(),
);
let ssid = specific_object_proxy.ssid().await?;
log::warn!("got ssid: {}", String::from_utf8_lossy(&ssid));
loop {
tokio::time::sleep(Duration::from_secs(3600)).await;
}
pending().await
}

View file

@ -1,17 +1,22 @@
use std::convert::Infallible;
use crate::config::SystemTimeConfig;
use crate::output::OutputChannel;
use crate::tile::Block;
use chrono::prelude::*;
use tokio::time::sleep;
pub async fn system_time(config: SystemTimeConfig, output: OutputChannel) -> eyre::Result<()> {
pub async fn system_time(
config: SystemTimeConfig,
output: OutputChannel,
) -> eyre::Result<Infallible> {
loop {
let now = Local::now();
output
.send(Block {
full_text: now.format(&config.format).to_string().into(),
short_text: Some(now.format(&config.short_format).to_string().into()),
name: "system_time".into(),
name: "system_time",
..Default::default()
})
.await?;

View file

@ -1,17 +1,19 @@
use std::convert::Infallible;
use crate::config::UtcTimeConfig;
use crate::output::OutputChannel;
use crate::tile::Block;
use chrono::prelude::*;
use tokio::time::sleep;
pub async fn utc_time(config: UtcTimeConfig, output: OutputChannel) -> eyre::Result<()> {
pub async fn utc_time(config: UtcTimeConfig, output: OutputChannel) -> eyre::Result<Infallible> {
loop {
let now = Utc::now();
output
.send(Block {
full_text: now.format(&config.format).to_string().into(),
short_text: Some(now.format(&config.short_format).to_string().into()),
name: "utc_time".into(),
name: "utc_time",
..Default::default()
})
.await?;