use async_net::{AsyncToSocketAddrs, TcpStream};
use futures_lite::{io::BufReader, AsyncWriteExt};
use std::net::SocketAddr;
use crate::resp::WrappedResponse;
use crate::{
client::resp::{
handlers::ResponseHandler,
read_resp_line,
respmap_handlers::{ListallResponse, ListallinfoResponse},
},
cmd::{self, MpdCmd},
DatabaseVersion, Error, Filter, Stats, Status, Subsystem, Track,
};
#[derive(Default)]
pub struct MpdClient {
stream: Option<BufReader<TcpStream>>,
addr: Option<SocketAddr>,
}
impl MpdClient {
pub fn new() -> Self {
Self {
stream: None,
addr: None,
}
}
pub async fn connect<A: AsyncToSocketAddrs>(&mut self, addr: A) -> Result<String, Error> {
let stream = TcpStream::connect(addr).await?;
let sock_addr = stream.peer_addr()?;
let reader = BufReader::new(stream);
log::debug!("server: {:?}", sock_addr);
self.stream = Some(reader);
self.addr = Some(sock_addr);
Ok(self.read_version().await?)
}
pub async fn reconnect(&mut self) -> Result<(), Error> {
if let Some(addr) = self.addr {
log::debug!("Reconnection to: {:?}", addr);
self.connect(addr).await.map(|_| ())
} else {
log::warn!("Reconnect without previous connection");
Err(Error::Disconnected)
}
}
async fn read_version(&mut self) -> Result<String, Error> {
let br = self.stream.as_mut().ok_or(Error::Disconnected)?;
let version = read_resp_line(br).await?;
log::debug!("Connected: {}", version);
Ok(version)
}
pub async fn stats(&mut self) -> Result<Stats, Error> {
self.exec(cmd::Stats).await
}
pub async fn status(&mut self) -> Result<Status, Error> {
let status = self.exec(cmd::Status).await?;
Ok(status)
}
pub async fn update(&mut self, path: Option<&str>) -> Result<DatabaseVersion, Error> {
self.exec(cmd::Update(path)).await
}
pub async fn rescan(&mut self, path: Option<&str>) -> Result<DatabaseVersion, Error> {
self.exec(cmd::Rescan(path)).await
}
pub async fn idle(&mut self) -> Result<Subsystem, Error> {
self.exec(cmd::Idle).await
}
pub async fn noidle(&mut self) -> Result<(), Error> {
self.exec(cmd::NoIdle).await
}
pub async fn setvol(&mut self, volume: u32) -> Result<(), Error> {
self.exec(cmd::Setvol(volume)).await
}
pub async fn repeat(&mut self, repeat: bool) -> Result<(), Error> {
self.exec(cmd::Repeat(repeat)).await
}
pub async fn random(&mut self, random: bool) -> Result<(), Error> {
self.exec(cmd::Random(random)).await
}
pub async fn consume(&mut self, consume: bool) -> Result<(), Error> {
self.exec(cmd::Consume(consume)).await
}
pub async fn play(&mut self) -> Result<(), Error> {
self.play_pause(true).await
}
pub async fn playid(&mut self, id: u32) -> Result<(), Error> {
self.exec(cmd::PlayId(id)).await
}
pub async fn pause(&mut self) -> Result<(), Error> {
self.play_pause(false).await
}
pub async fn play_pause(&mut self, play: bool) -> Result<(), Error> {
self.exec(cmd::PlayPause(!play)).await
}
pub async fn next(&mut self) -> Result<(), Error> {
self.exec(cmd::Next).await
}
pub async fn prev(&mut self) -> Result<(), Error> {
self.exec(cmd::Prev).await
}
pub async fn stop(&mut self) -> Result<(), Error> {
self.exec(cmd::Stop).await
}
pub async fn listall(&mut self, path: Option<&str>) -> Result<ListallResponse, Error> {
self.exec(cmd::Listall(path)).await
}
pub async fn listallinfo(&mut self, path: Option<&str>) -> Result<ListallinfoResponse, Error> {
self.exec(cmd::ListallInfo(path)).await
}
pub async fn queue_add(&mut self, path: &str) -> Result<(), Error> {
self.exec(cmd::QueueAdd(path)).await
}
pub async fn queue_clear(&mut self) -> Result<(), Error> {
self.exec(cmd::QueueClear).await
}
pub async fn queue(&mut self) -> Result<Vec<Track>, Error> {
self.exec(cmd::PlaylistInfo).await
}
pub async fn search(&mut self, filter: &Filter) -> Result<Vec<Track>, Error> {
self.exec(cmd::Search(filter.to_query().as_deref())).await
}
pub async fn exec_wrapped<C>(&mut self, cmd: C) -> Result<WrappedResponse, crate::Error>
where
C: MpdCmd,
{
self.exec(cmd).await.map(Into::into)
}
pub async fn exec<C>(
&mut self,
cmd: C,
) -> Result<<C::Handler as ResponseHandler>::Response, crate::Error>
where
C: MpdCmd,
{
let cmdline = cmd.to_cmdline();
self.send_command(&cmdline).await?;
let br = self.stream.as_mut().ok_or(Error::Disconnected)?;
C::Handler::handle(br).await
}
async fn send_command(&mut self, line: &str) -> Result<(), crate::Error> {
self.stream
.as_mut()
.ok_or(crate::Error::Disconnected)?
.get_mut()
.write_all(line.as_bytes())
.await
.map_err(|_| crate::Error::Disconnected)?;
Ok(())
}
}