use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SubsonicErrorCode {
Generic = 0,
MissingParameter = 10,
ClientMustUpgrade = 20,
ServerMustUpgrade = 30,
WrongCredentials = 40,
TokenAuthNotSupported = 41,
AuthMechanismNotSupported = 42,
ConflictingAuthentication = 43,
InvalidApiKey = 44,
NotAuthorized = 50,
TrialExpired = 60,
NotFound = 70,
}
impl SubsonicErrorCode {
pub fn from_code(code: i32) -> Option<Self> {
match code {
0 => Some(Self::Generic),
10 => Some(Self::MissingParameter),
20 => Some(Self::ClientMustUpgrade),
30 => Some(Self::ServerMustUpgrade),
40 => Some(Self::WrongCredentials),
41 => Some(Self::TokenAuthNotSupported),
42 => Some(Self::AuthMechanismNotSupported),
43 => Some(Self::ConflictingAuthentication),
44 => Some(Self::InvalidApiKey),
50 => Some(Self::NotAuthorized),
60 => Some(Self::TrialExpired),
70 => Some(Self::NotFound),
_ => None,
}
}
}
impl fmt::Display for SubsonicErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Generic => write!(f, "Generic error"),
Self::MissingParameter => write!(f, "Missing parameter"),
Self::ClientMustUpgrade => write!(f, "Client must upgrade"),
Self::ServerMustUpgrade => write!(f, "Server must upgrade"),
Self::WrongCredentials => write!(f, "Wrong credentials"),
Self::TokenAuthNotSupported => write!(f, "Token auth not supported"),
Self::AuthMechanismNotSupported => write!(f, "Auth mechanism not supported"),
Self::ConflictingAuthentication => write!(f, "Conflicting authentication"),
Self::InvalidApiKey => write!(f, "Invalid API key"),
Self::NotAuthorized => write!(f, "Not authorized"),
Self::TrialExpired => write!(f, "Trial expired"),
Self::NotFound => write!(f, "Not found"),
}
}
}
#[derive(Debug, Clone)]
pub struct SubsonicApiError {
pub code: i32,
pub message: String,
pub help_url: Option<String>,
}
impl SubsonicApiError {
pub fn error_code(&self) -> Option<SubsonicErrorCode> {
SubsonicErrorCode::from_code(self.code)
}
}
impl fmt::Display for SubsonicApiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(known) = self.error_code() {
write!(
f,
"Subsonic API error {}: {} ({})",
self.code, self.message, known
)
} else {
write!(f, "Subsonic API error {}: {}", self.code, self.message)
}
}
}
impl std::error::Error for SubsonicApiError {}
#[derive(Debug)]
pub enum Error {
Http(reqwest::Error),
Api(SubsonicApiError),
Parse(String),
Url(url::ParseError),
Other(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Http(e) => write!(f, "HTTP error: {e}"),
Error::Api(e) => write!(f, "{e}"),
Error::Parse(msg) => write!(f, "Parse error: {msg}"),
Error::Url(e) => write!(f, "URL error: {e}"),
Error::Other(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Http(e) => Some(e),
Error::Api(e) => Some(e),
Error::Url(e) => Some(e),
Error::Parse(_) | Error::Other(_) => None,
}
}
}
impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
Error::Http(err)
}
}
impl From<url::ParseError> for Error {
fn from(err: url::ParseError) -> Self {
Error::Url(err)
}
}
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Self {
Error::Parse(err.to_string())
}
}