diff options
Diffstat (limited to 'src/component.rs')
-rw-r--r-- | src/component.rs | 232 |
1 files changed, 0 insertions, 232 deletions
diff --git a/src/component.rs b/src/component.rs deleted file mode 100644 index e06f2cb..0000000 --- a/src/component.rs +++ /dev/null @@ -1,232 +0,0 @@ -use std::{ - future::Future, - io::{BufReader, Read, Write}, - marker::Send, - sync::Arc, -}; - -use tokio::{ - sync::{mpsc::Sender, Mutex}, - task::JoinSet, -}; -use zbus::Connection; - -use crate::{ - dbus::{ - player::{PlaybackStatus, PlayerProxy}, - playerctld::PlayerctldProxy, - }, - i3bar::{Block, Click}, - Error, IGNORED, -}; - -pub use icon::Icon; -pub use next::Next; -pub use play::Play; -pub use prev::Prev; -pub use title::Title; -pub use volume::Volume; - -mod icon; -mod next; -mod play; -mod prev; -mod title; -mod volume; - -pub trait Component: Send + 'static { - type Updater: Update; - type Colorer: Update; - type Handler: Button; - - fn initialize() -> Block; -} - -pub trait Runner: Component + private::Sealed { - fn run<R: Read + Send>(reader: R) -> impl Future<Output = Result<(), Error>> + Send { - async move { - use std::io::BufRead; - - let conn = Connection::session().await?; - - let writer = std::io::stdout(); - - let listeners = tokio::spawn(Self::listeners(conn.clone(), writer)); - let buf_reader = BufReader::new(reader); - - for click in buf_reader - .lines() - .map_while(Result::ok) - .flat_map(|s| serde_json::from_str::<Click>(&s)) - { - let _ = <Self::Handler as Button>::handle(conn.clone(), click).await; - } - - listeners.await? - } - } - - fn listeners<W: Write + Send>( - conn: Connection, - mut writer: W, - ) -> impl Future<Output = Result<(), Error>> + Send { - async move { - let mut join_set = JoinSet::new(); - - let (tx_player, mut rx_player) = tokio::sync::mpsc::channel(128); - let (tx_status, mut rx_status) = tokio::sync::mpsc::channel(128); - let (tx_value, mut rx_value) = tokio::sync::mpsc::channel(128); - - let block = Arc::new(Mutex::new(Self::initialize())); - - tokio::spawn(Self::active_listener(conn.clone(), tx_player)); - - loop { - let output = tokio::select! { - Some(name) = rx_player.recv() => { - join_set.shutdown().await; - - let mut block = block.lock().await; - *block = Self::initialize(); - if !name.is_empty() { - block.instance.clone_from(&Some(name.clone())); - let proxy = PlayerProxy::builder(&conn) - .destination(name.clone())? - .build() - .await?; - join_set.spawn(<Self::Colorer as Update>::listen(tx_status.clone(), proxy.clone())); - join_set.spawn(<Self::Updater as Update>::listen(tx_value.clone(), proxy)); - } - Output::Clear - } - Some(color) = rx_status.recv() => <Self::Colorer as Update>::update(color, block.clone()).await?, - Some(value) = rx_value.recv() => <Self::Updater as Update>::update(value, block.clone()).await? - }; - - match output { - Output::Print => (block.lock().await).write_to(&mut writer)?, - Output::Clear => writer.write_all(&[b'\n'])?, - Output::Skip => continue, - } - - writer.flush()?; - } - } - } - - fn active_listener( - conn: Connection, - tx: Sender<String>, - ) -> impl std::future::Future<Output = Result<(), Error>> + Send { - use futures_util::StreamExt; - - async move { - let proxy = PlayerctldProxy::builder(&conn).build().await?; - let mut last = String::new(); - let mut stream = proxy.receive_player_names_changed().await; - while let Some(signal) = stream.next().await { - let name = signal - .get() - .await? - .into_iter() - .find(|s| s.split('.').nth(3).is_some_and(|s| !IGNORED.contains(&s))) - .unwrap_or_default(); - if name != last { - last.clone_from(&name); - tx.send(name).await?; - } - } - Ok(()) - } - } -} - -impl<T: Component> Runner for T {} - -mod private { - pub trait Sealed {} - - impl<T: super::Component> Sealed for T {} -} - -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -pub enum Output { - Print, - Clear, - #[default] - Skip, -} - -pub trait Update: Send + 'static { - type Value: Send; - - fn listen( - tx: Sender<Self::Value>, - proxy: PlayerProxy<'_>, - ) -> impl Future<Output = Result<(), Error>> + Send; - - fn update( - value: Self::Value, - block: Arc<Mutex<Block>>, - ) -> impl Future<Output = Result<Output, Error>> + Send; -} - -impl Update for () { - type Value = (); - - async fn listen(_: Sender<Self::Value>, _: PlayerProxy<'_>) -> Result<(), Error> { - Ok(()) - } - - async fn update(_: Self::Value, _: Arc<Mutex<Block>>) -> Result<Output, Error> { - Ok(Output::Skip) - } -} - -impl Update for PlaybackStatus { - type Value = (Option<String>, Option<String>); - - async fn listen(tx: Sender<Self::Value>, proxy: PlayerProxy<'_>) -> Result<(), Error> { - use futures_util::StreamExt; - - let black = std::env::var("BASE16_COLOR_00_HEX").ok(); - let cyan = std::env::var("BASE16_COLOR_0C_HEX").ok(); - let yellow = std::env::var("BASE16_COLOR_0A_HEX").ok(); - - let mut stream = proxy.receive_playback_status_changed().await; - while let Some(signal) = stream.next().await { - if let Ok(value) = signal.get().await { - let val = match value { - PlaybackStatus::Playing => (black.clone(), cyan.clone()), - PlaybackStatus::Paused => (black.clone(), yellow.clone()), - PlaybackStatus::Stopped => (None, None), - }; - tx.send(val).await?; - } - } - Ok(()) - } - - async fn update( - (color, background): Self::Value, - block: Arc<Mutex<Block>>, - ) -> Result<Output, Error> { - let mut block = block.lock().await; - block.color = color; - block.background = background; - Ok(Output::Print) - } -} - -pub trait Button { - fn handle( - conn: zbus::Connection, - click: crate::i3bar::Click, - ) -> impl Future<Output = Result<(), Error>> + Send; -} - -impl Button for () { - async fn handle(_: zbus::Connection, _: crate::i3bar::Click) -> Result<(), Error> { - Ok(()) - } -} |