aboutsummaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/battery.rs38
-rw-r--r--src/utils/cpu.rs18
-rw-r--r--src/utils/disk.rs18
-rw-r--r--src/utils/memory.rs85
-rw-r--r--src/utils/mod.rs10
-rw-r--r--src/utils/mpd.rs27
-rw-r--r--src/utils/spotify.rs45
-rw-r--r--src/utils/time.rs13
-rw-r--r--src/utils/uptime.rs22
-rw-r--r--src/utils/volume.rs31
-rw-r--r--src/utils/weather.rs22
11 files changed, 329 insertions, 0 deletions
diff --git a/src/utils/battery.rs b/src/utils/battery.rs
new file mode 100644
index 0000000..b831773
--- /dev/null
+++ b/src/utils/battery.rs
@@ -0,0 +1,38 @@
+use crate::types::Config;
+use std::fs::File;
+use std::io::Error;
+use std::io::Read;
+
+// getting battery percentage
+pub fn get_battery(config: &Config) -> Result<String, Error> {
+ let battery_full_cap_file = format!(
+ "/sys/class/power_supply/{}/charge_full_design",
+ config.battery.source
+ );
+ let battery_charge_now_file = format!(
+ "/sys/class/power_supply/{}/charge_now",
+ config.battery.source
+ );
+
+ let mut buf = String::new();
+
+ // FIXME: ugly error handling AGAIN fixing later, im lazy
+ match File::open(&battery_full_cap_file) {
+ Ok(mut file) => file.read_to_string(&mut buf)?,
+ Err(_) => return Ok(String::from("check your battery source name")),
+ };
+ let full_design = buf.trim().parse::<u32>().unwrap();
+ buf.clear();
+
+ // NOTE: no need to error check if passed the above match
+ File::open(&battery_charge_now_file)?.read_to_string(&mut buf)?;
+
+ let charge_now = buf.trim().parse::<u32>().unwrap();
+
+ let battery_percentage = (charge_now as f32 / full_design as f32) * 100.0;
+ let result = format!(
+ " {} {:.0}% {}",
+ config.battery.icon, battery_percentage, config.seperator
+ );
+ Ok(result)
+}
diff --git a/src/utils/cpu.rs b/src/utils/cpu.rs
new file mode 100644
index 0000000..3e582ad
--- /dev/null
+++ b/src/utils/cpu.rs
@@ -0,0 +1,18 @@
+use crate::types::Config;
+use std::fs::File;
+use std::io::Read;
+
+// getting cpu temperature
+pub fn get_cpu_temp(config: &Config) -> Result<String, std::io::Error> {
+ let mut buf = String::new();
+ File::open("/sys/class/thermal/thermal_zone0/temp")?.read_to_string(&mut buf)?;
+ let value = buf.trim().parse::<f32>().unwrap();
+
+ let result = format!(
+ " {} {}° {}",
+ config.cpu_temperature.icon,
+ value / 1000.0,
+ config.seperator
+ );
+ Ok(result)
+}
diff --git a/src/utils/disk.rs b/src/utils/disk.rs
new file mode 100644
index 0000000..82785b4
--- /dev/null
+++ b/src/utils/disk.rs
@@ -0,0 +1,18 @@
+use crate::types::Config;
+
+// getting disk usage
+pub fn get_disk(config: &Config) -> String {
+ const GB: u64 = (1024 * 1024) * 1024;
+ let statvfs = nix::sys::statvfs::statvfs("/").unwrap();
+ let mut disk_used = String::new();
+
+ let total = (statvfs.blocks() * statvfs.fragment_size()) / GB;
+ let available = (statvfs.blocks_free() * statvfs.fragment_size()) / GB;
+ let used = total - available;
+
+ disk_used.push_str(&format!("{}G", used));
+ format!(
+ " {} {} {}",
+ config.disk.icon, disk_used, config.seperator
+ )
+}
diff --git a/src/utils/memory.rs b/src/utils/memory.rs
new file mode 100644
index 0000000..1a6c982
--- /dev/null
+++ b/src/utils/memory.rs
@@ -0,0 +1,85 @@
+use crate::types::Config;
+use std::fs::File;
+use std::io::Read;
+
+/*
+mem_used = (mem_total + shmem - mem_free - mem_buffers - mem_cached - mem_srecl
+thanks for htop's developer on stackoverflow for providing this algorithm to
+calculate used memory.
+*/
+pub fn get_memory(config: &Config) -> Result<String, std::io::Error> {
+ let mut buf = String::new();
+
+ File::open("/proc/meminfo")?.read_to_string(&mut buf)?;
+
+ let mut mem_total: u32 = 0;
+ let mut shmem: u32 = 0;
+ let mut mem_free: u32 = 0;
+ let mut mem_buffers: u32 = 0;
+ let mut mem_cached: u32 = 0;
+ let mut mem_srecl: u32 = 0;
+
+ for line in buf.lines() {
+ if mem_total > 0
+ && shmem > 0
+ && mem_free > 0
+ && mem_buffers > 0
+ && mem_cached > 0
+ && mem_srecl > 0
+ {
+ break;
+ }
+ if line.starts_with("MemTotal") {
+ assign_val(line, &mut mem_total);
+ }
+ if line.starts_with("SReclaimable") {
+ assign_val(line, &mut mem_srecl)
+ }
+ if line.starts_with("Cached") {
+ assign_val(line, &mut mem_cached)
+ }
+
+ if line.starts_with("Shmem") {
+ assign_val(line, &mut shmem);
+ }
+
+ if line.starts_with("MemFree") {
+ assign_val(line, &mut mem_free);
+ }
+ if line.starts_with("Buffers") {
+ assign_val(line, &mut mem_buffers);
+ }
+ }
+
+ let mem_used = (mem_total + shmem - mem_free - mem_buffers - mem_cached - mem_srecl) / 1024;
+ let result: String;
+ if mem_used > 1000 {
+ result = format!(
+ " {} {:.1}G {}",
+ config.memory.icon,
+ mem_used as f32 / 1000.0,
+ config.seperator
+ );
+ } else {
+ result = format!(
+ " {} {}M {}",
+ config.memory.icon, mem_used, config.seperator
+ );
+ }
+ Ok(result)
+}
+
+/*
+this helper function will split the line(first argument) by the character(:)
+and then parse the right splited item as u32
+then assign that to the "assignable"(2nd argument).
+*/
+fn assign_val(line: &str, assignable: &mut u32) {
+ let parsed: u32 = line.split(':').collect::<Vec<&str>>()[1]
+ .trim()
+ .split(' ')
+ .collect::<Vec<&str>>()[0]
+ .parse()
+ .unwrap();
+ *assignable = parsed;
+}
diff --git a/src/utils/mod.rs b/src/utils/mod.rs
new file mode 100644
index 0000000..b497999
--- /dev/null
+++ b/src/utils/mod.rs
@@ -0,0 +1,10 @@
+pub mod battery;
+pub mod cpu;
+pub mod disk;
+pub mod memory;
+pub mod mpd;
+pub mod spotify;
+pub mod time;
+pub mod uptime;
+pub mod volume;
+pub mod weather;
diff --git a/src/utils/mpd.rs b/src/utils/mpd.rs
new file mode 100644
index 0000000..e521c4f
--- /dev/null
+++ b/src/utils/mpd.rs
@@ -0,0 +1,27 @@
+use crate::types::Config;
+use mpd::{Client, Song};
+
+// yes, error handling looks fucking sucks!
+// getting mpd song file
+pub fn get_mpd_current(config: &Config) -> String {
+ let stream_path = format!("{}:{}", config.mpd.host, config.mpd.port);
+ let empty_string = String::from("");
+ let mut conn = match Client::connect(&stream_path) {
+ Ok(connection) => connection,
+ _ => return empty_string,
+ };
+ let current: Song = match conn.currentsong() {
+ Ok(opt) => match opt {
+ Some(song) => song,
+ _ => return empty_string,
+ },
+ _ => return empty_string,
+ };
+
+ let result = format!(
+ " {} {} {}",
+ config.mpd.icon, current.file, config.seperator
+ );
+
+ result
+}
diff --git a/src/utils/spotify.rs b/src/utils/spotify.rs
new file mode 100644
index 0000000..4954f3b
--- /dev/null
+++ b/src/utils/spotify.rs
@@ -0,0 +1,45 @@
+use crate::types::Config;
+use dbus::blocking::stdintf::org_freedesktop_dbus::Properties;
+use dbus::{arg, blocking::Connection};
+use std::time::Duration;
+
+// getting spotify current artist and title.
+// FIXME: I know im lazy asshole, this error handling looks ugly, i dont like it too, need to fix soon.
+pub fn get_spotify(config: &Config) -> String {
+ let conn = match Connection::new_session() {
+ Ok(conn) => conn,
+ _ => return String::from(""),
+ };
+
+ let p = conn.with_proxy(
+ "org.mpris.MediaPlayer2.spotify",
+ "/org/mpris/MediaPlayer2",
+ Duration::from_millis(5000),
+ );
+
+ let metadata: arg::PropMap = match p.get("org.mpris.MediaPlayer2.Player", "Metadata") {
+ Ok(data) => data,
+ _ => return String::from(""),
+ };
+
+ let title: Option<&String> = arg::prop_cast(&metadata, "xesam:title");
+ let artist: Option<&Vec<String>> = arg::prop_cast(&metadata, "xesam:artist");
+
+ let title = match title {
+ Some(title) => title,
+ _ => "",
+ };
+
+ let artist = match artist {
+ Some(artist_vec) => match artist_vec.first() {
+ Some(name) => name,
+ _ => "",
+ },
+ None => "",
+ };
+
+ format!(
+ " {} {} - {} {}",
+ config.spotify.icon, artist, title, config.seperator
+ )
+}
diff --git a/src/utils/time.rs b/src/utils/time.rs
new file mode 100644
index 0000000..3149ce6
--- /dev/null
+++ b/src/utils/time.rs
@@ -0,0 +1,13 @@
+use crate::types::Config;
+use chrono::prelude::*;
+
+pub fn get_time(config: &Config) -> String {
+ let now = Local::now();
+
+ format!(
+ " {} {} {}",
+ config.time.icon,
+ now.format(&config.time.format),
+ config.seperator
+ )
+}
diff --git a/src/utils/uptime.rs b/src/utils/uptime.rs
new file mode 100644
index 0000000..027827a
--- /dev/null
+++ b/src/utils/uptime.rs
@@ -0,0 +1,22 @@
+use crate::types::Config;
+use std::fs::File;
+use std::io::Read;
+
+pub fn get_uptime(config: &Config) -> Result<String, std::io::Error> {
+ let mut buf = String::new();
+ File::open("/proc/uptime")?.read_to_string(&mut buf)?;
+
+ let buf: f32 = buf.split(' ').collect::<Vec<&str>>()[0].parse().unwrap();
+
+ let hour = buf.round() as u32 / 3600;
+ let rem = buf as u32 - hour * 3600;
+ let minutes = rem / 60;
+
+ let uptime = if hour > 0 {
+ format!("{}:{}", hour, minutes)
+ } else {
+ format!("{} min", minutes)
+ };
+ let result = format!(" {} {} {}", config.uptime.icon, uptime, config.seperator);
+ Ok(result)
+}
diff --git a/src/utils/volume.rs b/src/utils/volume.rs
new file mode 100644
index 0000000..061ab60
--- /dev/null
+++ b/src/utils/volume.rs
@@ -0,0 +1,31 @@
+use crate::types::Config;
+use alsa::mixer::{Mixer, SelemChannelId, SelemId};
+
+// getting volume percentage
+pub fn get_volume(config: &Config) -> String {
+ let card = if config.volume.card == "PULSE" {
+ "pulse"
+ } else {
+ "default"
+ };
+
+ let mixer = Mixer::new(card, false).expect("Failed to open mixer");
+ let selem_id = SelemId::new("Master", 0);
+ let selem = mixer.find_selem(&selem_id).expect("Couldn't find selem");
+ let selem_chan_id = SelemChannelId::FrontLeft;
+
+ let (min, max) = selem.get_playback_volume_range();
+ let mut raw_volume = selem
+ .get_playback_volume(selem_chan_id)
+ .expect("Failed to get raw_volume");
+
+ let range = max - min;
+ let vol = if range == 0 {
+ 0
+ } else {
+ raw_volume -= min;
+ ((raw_volume as f64 / range as f64) * 100.) as u64
+ };
+
+ format!(" {} {}% {}", config.volume.icon, vol, config.seperator)
+}
diff --git a/src/utils/weather.rs b/src/utils/weather.rs
new file mode 100644
index 0000000..05fa60b
--- /dev/null
+++ b/src/utils/weather.rs
@@ -0,0 +1,22 @@
+use crate::types::Config;
+
+// will make a GET request from wttr.in
+pub fn get_weather(config: &Config) -> String {
+ let format = if config.weather.format.is_empty() {
+ String::from("%l:+%t")
+ } else {
+ config.weather.format.clone()
+ };
+
+ let url = format!("http://wttr.in/{}?format=\"{}", config.weather.city, format);
+ let err_string = String::from("Error");
+ let res = match minreq::get(url).send() {
+ Ok(resp) => match resp.as_str() {
+ Ok(res_str) => res_str.trim_matches('"').to_string(),
+ Err(_) => err_string,
+ },
+ Err(_) => err_string,
+ };
+
+ format!(" {} {} {}", config.weather.icon, res, config.seperator)
+}