use std::error::Error;
use std::fmt;
pub type NetavarkResult<T> = Result<T, NetavarkError>;
#[macro_export]
macro_rules! wrap {
($result:expr, $msg:expr) => {
$result.map_err(|err| NetavarkError::wrap($msg, err.into()))
};
}
#[derive(Debug)]
pub struct NetavarkErrorList(Vec<NetavarkError>);
impl NetavarkErrorList {
pub fn new() -> Self {
Self(vec![])
}
pub fn push(&mut self, err: NetavarkError) {
match err {
NetavarkError::List(mut list) => self.0.append(&mut list.0),
err => self.0.push(err),
}
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Default for NetavarkErrorList {
fn default() -> Self {
Self::new()
}
}
pub trait ErrorWrap<T> {
fn wrap<S>(self, msg: S) -> NetavarkResult<T>
where
S: Into<String>;
}
impl<T> ErrorWrap<T> for NetavarkResult<T> {
fn wrap<S>(self, msg: S) -> NetavarkResult<T>
where
S: Into<String>,
{
self.map_err(|err| NetavarkError::wrap(msg, err))
}
}
#[derive(Debug)]
pub enum NetavarkError {
Message(String),
ExitCode(String, i32),
Chain(String, Box<NetavarkError>),
Io(std::io::Error),
Dbus(zbus::Error),
DbusVariant(zbus::zvariant::Error),
Sysctl(sysctl::SysctlError),
Serde(serde_json::Error),
Netlink(netlink_packet_core::error::ErrorMessage),
DHCPProxy(tonic::Status),
List(NetavarkErrorList),
}
#[derive(Debug, Serialize, Deserialize)]
pub struct JsonError {
pub error: String,
}
impl NetavarkError {
pub fn msg<S>(msg: S) -> NetavarkError
where
S: Into<String>,
{
NetavarkError::Message(msg.into())
}
pub fn wrap<S>(msg: S, chained: NetavarkError) -> NetavarkError
where
S: Into<String>,
{
NetavarkError::Chain(msg.into(), Box::new(chained))
}
pub fn print_json(&self) {
let to_json = JsonError {
error: self.to_string(),
};
println!(
"{}",
serde_json::to_string(&to_json).unwrap_or(format!(
"Failed to serialize error message: {}",
to_json.error
))
);
}
pub fn get_exit_code(&self) -> i32 {
match *self {
NetavarkError::ExitCode(_, i) => i,
_ => 1,
}
}
pub fn unwrap(&self) -> &NetavarkError {
match self {
NetavarkError::Chain(_, inner) => inner.unwrap(),
_ => self,
}
}
}
impl fmt::Display for NetavarkError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NetavarkError::Message(s) => write!(f, "{s}"),
NetavarkError::ExitCode(s, _) => write!(f, "{s}"),
NetavarkError::Chain(s, e) => write!(f, "{s}: {e}"),
NetavarkError::Io(e) => write!(f, "IO error: {e}"),
NetavarkError::Dbus(e) => write!(f, "DBus error: {e}"),
NetavarkError::DbusVariant(e) => write!(f, "DBus Variant Error: {e}"),
NetavarkError::Sysctl(e) => write!(f, "Sysctl error: {e}"),
NetavarkError::Serde(e) => write!(f, "JSON Decoding error: {e}"),
NetavarkError::Netlink(e) => write!(f, "Netlink error: {e}"),
NetavarkError::DHCPProxy(e) => write!(f, "dhcp proxy error: {e}"),
NetavarkError::List(list) => {
if list.0.len() == 1 {
write!(f, "{}", list.0[0])
} else {
write!(f, "netavark encountered multiple errors:")?;
for e in &list.0 {
write!(f, "\n\t- {e}")?;
}
Ok(())
}
}
}
}
}
impl Error for NetavarkError {}
impl From<std::io::Error> for NetavarkError {
fn from(err: std::io::Error) -> NetavarkError {
NetavarkError::Io(err)
}
}
impl From<zbus::Error> for NetavarkError {
fn from(err: zbus::Error) -> NetavarkError {
NetavarkError::Dbus(err)
}
}
impl From<zbus::zvariant::Error> for NetavarkError {
fn from(err: zbus::zvariant::Error) -> NetavarkError {
NetavarkError::DbusVariant(err)
}
}
impl From<sysctl::SysctlError> for NetavarkError {
fn from(err: sysctl::SysctlError) -> NetavarkError {
NetavarkError::Sysctl(err)
}
}
impl From<serde_json::Error> for NetavarkError {
fn from(err: serde_json::Error) -> NetavarkError {
NetavarkError::Serde(err)
}
}
impl From<ipnet::PrefixLenError> for NetavarkError {
fn from(e: ipnet::PrefixLenError) -> Self {
NetavarkError::Message(format!("{e}"))
}
}
impl From<netlink_packet_core::error::ErrorMessage> for NetavarkError {
fn from(err: netlink_packet_core::error::ErrorMessage) -> Self {
NetavarkError::Netlink(err)
}
}
impl From<tonic::Status> for NetavarkError {
fn from(err: tonic::Status) -> Self {
NetavarkError::DHCPProxy(err)
}
}