mirror of
https://github.com/figsoda/mmtc
synced 2024-11-21 22:53:02 +00:00
refactor
This commit is contained in:
parent
2fc23792a4
commit
a155feb233
3 changed files with 72 additions and 42 deletions
|
@ -11,17 +11,11 @@ use std::{
|
|||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(default = "fps_default")]
|
||||
pub fps: f64,
|
||||
#[serde(default = "ups_default")]
|
||||
pub ups: f64,
|
||||
pub layout: Widget,
|
||||
}
|
||||
|
||||
fn fps_default() -> f64 {
|
||||
30.0
|
||||
}
|
||||
|
||||
fn ups_default() -> f64 {
|
||||
4.0
|
||||
}
|
||||
|
|
104
src/main.rs
104
src/main.rs
|
@ -14,19 +14,22 @@ use crossterm::{
|
|||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use tokio::{
|
||||
sync::Mutex,
|
||||
sync::mpsc,
|
||||
time::{sleep_until, Duration, Instant},
|
||||
};
|
||||
use tui::{backend::CrosstermBackend, Terminal};
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
io::{stdout, Write},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
process::exit,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::{
|
||||
config::Config,
|
||||
mpd::{Status, Track},
|
||||
};
|
||||
|
||||
fn cleanup() -> Result<()> {
|
||||
disable_raw_mode().context("Failed to clean up terminal")?;
|
||||
|
@ -35,7 +38,7 @@ fn cleanup() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn die<T>(e: impl std::fmt::Display) -> T {
|
||||
fn die<T>(e: impl Display) -> T {
|
||||
if let Err(e) = cleanup() {
|
||||
eprintln!("{}", e);
|
||||
};
|
||||
|
@ -43,48 +46,67 @@ fn die<T>(e: impl std::fmt::Display) -> T {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Command {
|
||||
Quit,
|
||||
UpdateFrame,
|
||||
UpdateQueue(Vec<Track>),
|
||||
UpdateStatus(Status),
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let res = run().await;
|
||||
cleanup()?;
|
||||
res
|
||||
cleanup().and_then(|_| res).map_or_else(Err, |_| exit(0))
|
||||
}
|
||||
|
||||
async fn run() -> Result<()> {
|
||||
let cfg: Config = ron::from_str(&std::fs::read_to_string("mmtc.ron").unwrap()).unwrap();
|
||||
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 6600);
|
||||
|
||||
let mut idle_cl = mpd::init(addr).await.with_context(fail::connect(addr))?;
|
||||
let mut status_cl = mpd::init(addr).await.with_context(fail::connect(addr))?;
|
||||
let mut idle_cl = mpd::init(addr).await?;
|
||||
let mut status_cl = mpd::init(addr).await?;
|
||||
|
||||
let queue = Arc::new(Mutex::new(mpd::queue(&mut idle_cl).await?));
|
||||
let queue1 = Arc::clone(&queue);
|
||||
let status = Arc::new(Mutex::new(mpd::status(&mut status_cl).await?));
|
||||
let status1 = Arc::clone(&status);
|
||||
let mut queue = mpd::queue(&mut idle_cl).await?;
|
||||
let mut status = mpd::status(&mut status_cl).await?;
|
||||
|
||||
let frame_interval = Duration::from_secs_f64(1.0 / cfg.fps);
|
||||
let update_interval = Duration::from_secs_f64(1.0 / cfg.ups);
|
||||
|
||||
let (tx, mut rx) = mpsc::channel(32);
|
||||
let tx1 = tx.clone();
|
||||
let tx2 = tx.clone();
|
||||
let tx3 = tx.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let tx = tx1;
|
||||
loop {
|
||||
mpd::idle_playlist(&mut idle_cl)
|
||||
.await
|
||||
.context("Failed to idle")
|
||||
.unwrap_or_else(die);
|
||||
*queue1.lock().await = mpd::queue(&mut idle_cl)
|
||||
.await
|
||||
.context("Failed to query queue information")
|
||||
.unwrap_or_else(die);
|
||||
tx.send(Command::UpdateQueue(
|
||||
mpd::queue(&mut idle_cl)
|
||||
.await
|
||||
.context("Failed to query queue information")
|
||||
.unwrap_or_else(die),
|
||||
))
|
||||
.await
|
||||
.unwrap_or_else(die);
|
||||
}
|
||||
});
|
||||
|
||||
tokio::spawn(async move {
|
||||
let tx = tx2;
|
||||
loop {
|
||||
let deadline = Instant::now() + update_interval;
|
||||
*status1.lock().await = mpd::status(&mut status_cl)
|
||||
.await
|
||||
.context("Failed to query status")
|
||||
.unwrap_or_else(die);
|
||||
tx.send(Command::UpdateStatus(
|
||||
mpd::status(&mut status_cl)
|
||||
.await
|
||||
.context("Failed to query status")
|
||||
.unwrap_or_else(die),
|
||||
))
|
||||
.await
|
||||
.unwrap_or_else(die);
|
||||
sleep_until(deadline).await;
|
||||
}
|
||||
});
|
||||
|
@ -96,28 +118,40 @@ async fn run() -> Result<()> {
|
|||
let mut term =
|
||||
Terminal::new(CrosstermBackend::new(stdout)).context("Failed to initialize terminal")?;
|
||||
|
||||
loop {
|
||||
let deadline = Instant::now() + frame_interval;
|
||||
let queue = &*queue.lock().await;
|
||||
let status = &*status.lock().await;
|
||||
|
||||
term.draw(|frame| {
|
||||
layout::render(frame, frame.size(), &cfg.layout, queue, status);
|
||||
})
|
||||
.context("Failed to draw to terminal")?;
|
||||
|
||||
while event::poll(Duration::new(0, 0)).context("Failed to poll events")? {
|
||||
match event::read().context("Failed to read events")? {
|
||||
tokio::spawn(async move {
|
||||
let tx = tx3;
|
||||
while let Ok(ev) = event::read() {
|
||||
match ev {
|
||||
Event::Key(KeyEvent { code, .. }) => match code {
|
||||
KeyCode::Char('q') | KeyCode::Esc => {
|
||||
return Ok(());
|
||||
tx.send(Command::Quit).await.unwrap_or_else(die)
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Event::Resize(..) => tx.send(Command::UpdateFrame).await.unwrap_or_else(die),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sleep_until(deadline).await;
|
||||
while let Some(cmd) = rx.recv().await {
|
||||
match cmd {
|
||||
Command::Quit => return Ok(()),
|
||||
Command::UpdateFrame => term
|
||||
.draw(|frame| {
|
||||
layout::render(frame, frame.size(), &cfg.layout, &queue, &status);
|
||||
})
|
||||
.context("Failed to draw to terminal")?,
|
||||
Command::UpdateQueue(new_queue) => {
|
||||
queue = new_queue;
|
||||
tx.send(Command::UpdateFrame).await?;
|
||||
}
|
||||
Command::UpdateStatus(new_status) => {
|
||||
status = new_status;
|
||||
tx.send(Command::UpdateFrame).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::fail;
|
|||
|
||||
pub type Client = BufReader<TcpStream>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Status {
|
||||
pub repeat: bool,
|
||||
pub random: bool,
|
||||
|
@ -19,12 +20,13 @@ pub struct Status {
|
|||
pub song: Option<Song>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Song {
|
||||
pub pos: usize,
|
||||
pub elapsed: u16,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Track {
|
||||
pub file: String,
|
||||
pub artist: Option<String>,
|
||||
|
|
Loading…
Reference in a new issue