#[derive(Debug)] pub enum Error { // FIXME: can't even return url's ParseError directly......... UrlParseError(String), ReqwestError(reqwest::Error), SubsonicError(SubsonicError), } impl From for Error { fn from(err: reqwest::Error) -> Self { Self::ReqwestError(err) } } #[derive(Debug, serde::Deserialize)] pub struct SubsonicError { pub code: u32, pub message: String, } #[derive(Debug, serde::Deserialize)] pub struct SubsonicResponse { #[serde(rename = "subsonic-response")] inner: SubsonicResponseInner, } #[derive(Debug, serde::Deserialize)] #[serde(tag = "status")] pub enum SubsonicResponseInner { #[serde(rename = "ok")] Ok(T), #[serde(rename = "failed")] Failed { error: SubsonicError }, } impl SubsonicResponseInner { fn fixup(self) -> Result { match self { Self::Ok(t) => Ok(t), Self::Failed { error } => Err(Error::SubsonicError(error)), } } } pub struct Client { client: reqwest::Client, base_url: reqwest::Url, } impl Client { pub fn new(url: &str, username: &str, token: &str, salt: &str) -> Result { Ok(Client { client: reqwest::Client::builder() .user_agent("audrey/linux") // Audrey.Const.user_agent .build()?, base_url: reqwest::Url::parse_with_params( url, &[ ("u", username), ("t", token), ("s", salt), ("v", "1.16.1"), ("c", "eu.callcc.audrey"), ("f", "json"), ], ) .map_err(|err| Error::UrlParseError(err.to_string()))?, }) } pub async fn ping(&self) -> Result<(), Error> { let mut url = self.base_url.clone(); url.path_segments_mut() .expect("can't modify url path segments") .extend(&["rest", "ping"]); self.client .get(url) .send() .await? .error_for_status()? .json::>() .await? .inner .fixup() } }