async_mpd/client/resp/
handlers.rs

1use async_net::TcpStream;
2use async_trait::async_trait;
3
4use futures_lite::io::BufReader;
5use futures_lite::{AsyncBufReadExt, StreamExt};
6
7use std::marker::PhantomData;
8use std::str::FromStr;
9
10use crate::resp::WrappedResponse;
11use crate::{
12    client::resp::{
13        read_resp_line,
14        respmap::RespMap,
15        respmap_handlers::{mixed_stream, tracks, ListallinfoResponse},
16    },
17    Error, Track,
18};
19
20#[async_trait]
21/// Response Handler for Cmd
22pub trait ResponseHandler: Sized {
23    /// The type of response
24    type Response: Into<WrappedResponse>;
25
26    async fn handle(reader: &mut BufReader<TcpStream>) -> Result<Self::Response, crate::Error>;
27}
28
29pub struct Tracks;
30
31#[async_trait]
32impl ResponseHandler for Tracks {
33    type Response = Vec<Track>;
34
35    async fn handle(reader: &mut BufReader<TcpStream>) -> Result<Self::Response, Error> {
36        tracks(reader).await.map_err(Into::into)
37    }
38}
39
40pub struct MixedResponseResponse;
41
42#[async_trait]
43impl ResponseHandler for MixedResponseResponse {
44    type Response = ListallinfoResponse;
45
46    async fn handle(reader: &mut BufReader<TcpStream>) -> Result<Self::Response, Error> {
47        mixed_stream(reader).await.map_err(Into::into)
48    }
49}
50
51pub struct RespMapResponse<T> {
52    _0: PhantomData<T>,
53}
54
55#[async_trait]
56impl<T: From<RespMap> + Into<WrappedResponse>> ResponseHandler for RespMapResponse<T> {
57    type Response = T;
58
59    async fn handle(reader: &mut BufReader<TcpStream>) -> Result<Self::Response, Error> {
60        let mut map = RespMap::new();
61        let mut lines = reader.lines();
62
63        while let Some(line) = lines.next().await {
64            let line = line?;
65            log::debug!("line: '{}'", line);
66
67            if &line == "OK" {
68                break;
69            }
70
71            if line.starts_with("ACK ") {
72                return Err(crate::Error::ServerError { msg: line });
73            }
74
75            if let Some((k, v)) = line.split_once(": ") {
76                map.insert(k, v);
77            }
78        }
79
80        Ok(map.into())
81    }
82}
83
84pub struct SingleLineResp<T> {
85    _0: PhantomData<T>,
86}
87
88#[async_trait]
89impl<E: Into<crate::Error>, T: FromStr<Err = E> + Into<WrappedResponse>> ResponseHandler
90    for SingleLineResp<T>
91{
92    type Response = T;
93
94    async fn handle(reader: &mut BufReader<TcpStream>) -> Result<Self::Response, Error> {
95        let line = read_resp_line(reader).await?;
96
97        let (_key, value) = line.split_once(": ").ok_or(crate::Error::ValueError {msg: "invalid line".to_string() })?;
98
99        T::from_str(value).map_err(Into::into)
100    }
101}
102
103pub struct OkResponse;
104
105#[async_trait]
106impl ResponseHandler for OkResponse {
107    type Response = ();
108
109    async fn handle(reader: &mut BufReader<TcpStream>) -> Result<Self::Response, crate::Error> {
110        let mut lines = reader.lines();
111
112        if let Some(line) = lines.next().await {
113            let line = line?;
114
115            if &line == "OK" {
116                Ok(())
117            } else {
118                Err(crate::Error::ServerError { msg: line })
119            }
120        } else {
121            Ok(())
122        }
123    }
124}