audrey/src/subsonic.rs

89 lines
2.3 KiB
Rust
Raw Normal View History

2024-10-31 12:16:42 +00:00
#[derive(Debug)]
pub enum Error {
// FIXME: can't even return url's ParseError directly.........
UrlParseError(String),
ReqwestError(reqwest::Error),
SubsonicError(SubsonicError),
}
2024-10-30 09:06:10 +00:00
2024-10-31 12:16:42 +00:00
impl From<reqwest::Error> 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<T> {
#[serde(rename = "subsonic-response")]
inner: SubsonicResponseInner<T>,
}
#[derive(Debug, serde::Deserialize)]
#[serde(tag = "status")]
pub enum SubsonicResponseInner<T> {
#[serde(rename = "ok")]
Ok(T),
#[serde(rename = "failed")]
Failed { error: SubsonicError },
}
impl<T> SubsonicResponseInner<T> {
fn fixup(self) -> Result<T, Error> {
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<Self, Error> {
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()
2024-10-31 20:41:02 +00:00
// literally can't fail
.unwrap_or_else(|_| unsafe { std::hint::unreachable_unchecked() })
2024-10-31 12:16:42 +00:00
.extend(&["rest", "ping"]);
self.client
.get(url)
.send()
.await?
.error_for_status()?
.json::<SubsonicResponse<()>>()
.await?
.inner
.fixup()
}
}