1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-04 20:21:02 +02:00

feat: logging support and proper error handling

This commit is contained in:
Jake Stanger 2022-08-21 23:36:07 +01:00
parent 917838c98c
commit ab8f7ecfc8
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
28 changed files with 1056 additions and 388 deletions

View file

@ -2,57 +2,76 @@ use mpd_client::commands::responses::Status;
use mpd_client::raw::MpdProtocolError;
use mpd_client::{Client, Connection};
use std::path::PathBuf;
use std::time::Duration;
use tokio::net::{TcpStream, UnixStream};
use tokio::spawn;
use tokio::time::sleep;
fn is_unix_socket(host: &String) -> bool {
pub async fn wait_for_connection(
hosts: Vec<String>,
interval: Duration,
max_retries: Option<usize>,
) -> Option<Client> {
let mut retries = 0;
spawn(async move {
let max_retries = max_retries.unwrap_or(usize::MAX);
loop {
if retries == max_retries {
break None;
}
if let Some(conn) = try_get_mpd_conn(&hosts).await {
break Some(conn.0);
}
retries += 1;
sleep(interval).await;
}
})
.await
.expect("Error occurred while handling tasks")
}
/// Cycles through each MPD host and
/// returns the first one which connects,
/// or none if there are none
async fn try_get_mpd_conn(hosts: &[String]) -> Option<Connection> {
for host in hosts {
let connection = if is_unix_socket(host) {
connect_unix(host).await
} else {
connect_tcp(host).await
};
if let Ok(connection) = connection {
return Some(connection);
}
}
None
}
fn is_unix_socket(host: &str) -> bool {
PathBuf::from(host).is_file()
}
pub async fn get_connection(host: &String) -> Result<Connection, MpdProtocolError> {
if is_unix_socket(host) {
connect_unix(host).await
} else {
connect_tcp(host).await
}
}
async fn connect_unix(host: &String) -> Result<Connection, MpdProtocolError> {
let connection = UnixStream::connect(host)
.await
.unwrap_or_else(|_| panic!("Error connecting to unix socket: {}", host));
async fn connect_unix(host: &str) -> Result<Connection, MpdProtocolError> {
let connection = UnixStream::connect(host).await?;
Client::connect(connection).await
}
async fn connect_tcp(host: &String) -> Result<Connection, MpdProtocolError> {
let connection = TcpStream::connect(host)
.await
.unwrap_or_else(|_| panic!("Error connecting to unix socket: {}", host));
async fn connect_tcp(host: &str) -> Result<Connection, MpdProtocolError> {
let connection = TcpStream::connect(host).await?;
Client::connect(connection).await
}
// /// Gets MPD server status.
// /// Panics on error.
// pub async fn get_status(client: &Client) -> Status {
// client
// .command(commands::Status)
// .await
// .expect("Failed to get MPD server status")
// }
/// Gets the duration of the current song
pub fn get_duration(status: &Status) -> u64 {
status
.duration
.expect("Failed to get duration from MPD status")
.as_secs()
pub fn get_duration(status: &Status) -> Option<u64> {
status.duration.map(|duration| duration.as_secs())
}
/// Gets the elapsed time of the current song
pub fn get_elapsed(status: &Status) -> u64 {
status
.elapsed
.expect("Failed to get elapsed time from MPD status")
.as_secs()
pub fn get_elapsed(status: &Status) -> Option<u64> {
status.elapsed.map(|duration| duration.as_secs())
}

View file

@ -2,10 +2,11 @@ mod client;
mod popup;
use self::popup::Popup;
use crate::modules::mpd::client::{get_connection, get_duration, get_elapsed};
use crate::modules::mpd::client::{get_duration, get_elapsed, wait_for_connection};
use crate::modules::mpd::popup::{MpdPopup, PopupEvent};
use crate::modules::{Module, ModuleInfo};
use dirs::home_dir;
use color_eyre::Result;
use dirs::{audio_dir, home_dir};
use glib::Continue;
use gtk::prelude::*;
use gtk::{Button, Orientation};
@ -14,9 +15,11 @@ use mpd_client::{commands, Tag};
use regex::Regex;
use serde::Deserialize;
use std::path::PathBuf;
use std::time::Duration;
use tokio::spawn;
use tokio::sync::mpsc;
use tokio::time::sleep;
use tracing::error;
#[derive(Debug, Deserialize, Clone)]
pub struct MpdModule {
@ -41,16 +44,18 @@ fn default_format() -> String {
String::from("{icon} {title} / {artist}")
}
#[allow(clippy::unnecessary_wraps)]
fn default_icon_play() -> Option<String> {
Some(String::from(""))
}
#[allow(clippy::unnecessary_wraps)]
fn default_icon_pause() -> Option<String> {
Some(String::from(""))
}
fn default_music_dir() -> PathBuf {
home_dir().unwrap().join("Music")
audio_dir().unwrap_or_else(|| home_dir().map(|dir| dir.join("Music")).unwrap_or_default())
}
/// Attempts to read the first value for a tag
@ -84,8 +89,8 @@ enum Event {
}
impl Module<Button> for MpdModule {
fn into_widget(self, info: &ModuleInfo) -> Button {
let re = Regex::new(r"\{([\w-]+)}").unwrap();
fn into_widget(self, info: &ModuleInfo) -> Result<Button> {
let re = Regex::new(r"\{([\w-]+)}")?;
let tokens = get_tokens(&re, self.format.as_str());
let button = Button::new();
@ -107,13 +112,17 @@ impl Module<Button> for MpdModule {
let music_dir = self.music_dir.clone();
button.connect_clicked(move |_| {
click_tx.send(Event::Open).unwrap();
click_tx
.send(Event::Open)
.expect("Failed to send popup open event");
});
let host = self.host.clone();
let host2 = self.host.clone();
spawn(async move {
let (client, _) = get_connection(&host).await.unwrap(); // TODO: Handle connecting properly
let client = wait_for_connection(vec![host], Duration::from_secs(1), None)
.await
.expect("Unexpected error when trying to connect to MPD server");
loop {
let current_song = client.command(commands::CurrentSong).await;
@ -125,32 +134,38 @@ impl Module<Button> for MpdModule {
.await;
tx.send(Event::Update(Box::new(Some((song.song, status, string)))))
.unwrap();
.expect("Failed to send update event");
} else {
tx.send(Event::Update(Box::new(None))).unwrap();
tx.send(Event::Update(Box::new(None)))
.expect("Failed to send update event");
}
sleep(tokio::time::Duration::from_secs(1)).await;
sleep(Duration::from_secs(1)).await;
}
});
spawn(async move {
let (client, _) = get_connection(&host2).await.unwrap(); // TODO: Handle connecting properly
let client = wait_for_connection(vec![host2], Duration::from_secs(1), None)
.await
.expect("Unexpected error when trying to connect to MPD server");
while let Some(event) = ui_rx.recv().await {
match event {
let res = match event {
PopupEvent::Previous => client.command(commands::Previous).await,
PopupEvent::Toggle => {
let status = client.command(commands::Status).await.unwrap();
match status.state {
PopupEvent::Toggle => match client.command(commands::Status).await {
Ok(status) => match status.state {
PlayState::Playing => client.command(commands::SetPause(true)).await,
PlayState::Paused => client.command(commands::SetPause(false)).await,
PlayState::Stopped => Ok(()),
}
}
},
Err(err) => Err(err),
},
PopupEvent::Next => client.command(commands::Next).await,
};
if let Err(err) = res {
error!("Failed to send command to MPD server: {:?}", err);
}
.unwrap();
}
});
@ -178,7 +193,7 @@ impl Module<Button> for MpdModule {
});
};
button
Ok(button)
}
}
@ -220,10 +235,11 @@ impl MpdModule {
"disc" => try_get_first_tag(song.tags.get(&Tag::Disc)),
"genre" => try_get_first_tag(song.tags.get(&Tag::Genre)),
"track" => try_get_first_tag(song.tags.get(&Tag::Track)),
"duration" => return format_time(get_duration(status)),
"elapsed" => return format_time(get_elapsed(status)),
_ => return token.to_string(),
"duration" => return get_duration(status).map(format_time).unwrap_or_default(),
"elapsed" => return get_elapsed(status).map(format_time).unwrap_or_default(),
_ => Some(token),
};
s.unwrap_or_default().to_string()
}
}
}

View file

@ -90,17 +90,23 @@ impl MpdPopup {
let tx_prev = tx.clone();
btn_prev.connect_clicked(move |_| {
tx_prev.try_send(PopupEvent::Previous).unwrap();
tx_prev
.try_send(PopupEvent::Previous)
.expect("Failed to send prev track message");
});
let tx_toggle = tx.clone();
btn_play_pause.connect_clicked(move |_| {
tx_toggle.try_send(PopupEvent::Toggle).unwrap();
tx_toggle
.try_send(PopupEvent::Toggle)
.expect("Failed to send play/pause track message");
});
let tx_next = tx;
btn_next.connect_clicked(move |_| {
tx_next.try_send(PopupEvent::Next).unwrap();
tx_next
.try_send(PopupEvent::Next)
.expect("Failed to send next track message");
});
Self {
@ -121,7 +127,12 @@ impl MpdPopup {
// only update art when album changes
if prev_album != curr_album {
let cover_path = path.join(song.file_path().parent().unwrap().join("cover.jpg"));
let cover_path = path.join(
song.file_path()
.parent()
.expect("Song path should not be root")
.join("cover.jpg"),
);
if let Ok(pixbuf) = Pixbuf::from_file_at_scale(cover_path, 128, 128, true) {
self.cover.set_from_pixbuf(Some(&pixbuf));