use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Delivery {
Accepted,
Rejected,
Unknown,
}
impl fmt::Display for Delivery {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Delivery::Accepted => "accepted",
Delivery::Rejected => "rejected",
Delivery::Unknown => "unknown",
})
}
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("{0}")]
Policy(String),
#[error("{0}")]
Validation(String),
#[error("{method} failed: {status} {message}")]
Http {
method: String,
status: u16,
message: String,
},
#[error("{method} failed: {message}")]
Transport {
method: String,
message: String,
},
#[error("{method}: gateway response too large (over {limit} bytes)")]
TooLarge {
method: String,
limit: usize,
},
#[error("{message}")]
Desktop {
code: String,
message: String,
},
#[error("{method}: {message}")]
InvalidResponse {
method: String,
message: String,
},
}
impl Error {
pub fn status(&self) -> Option<u16> {
match self {
Error::Http { status, .. } => Some(*status),
_ => None,
}
}
pub fn is_unauthorized(&self) -> bool {
matches!(self.status(), Some(401) | Some(417))
}
pub fn delivery(&self) -> Delivery {
match self {
Error::Policy(_) | Error::Validation(_) => Delivery::Rejected,
Error::Http { status, .. } if *status < 500 => Delivery::Rejected,
_ => Delivery::Unknown,
}
}
}
#[cfg(test)]
mod auth_tests {
use super::*;
fn http(status: u16) -> Error {
Error::Http {
status,
method: "listAgents".into(),
message: String::new(),
}
}
#[test]
fn expired_session_417_counts_as_unauthorized() {
assert!(http(401).is_unauthorized());
assert!(http(417).is_unauthorized());
assert!(!http(400).is_unauthorized());
assert!(!http(500).is_unauthorized());
}
}