use std::fmt;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("i/o error: `{0}`")]
IoError(#[from] std::io::Error),
#[error("protocol error: `{0}`")]
Protocol(ProtocolError),
#[error("i2p error: `{0}`")]
I2p(I2pError),
#[error("response is malformed")]
Malformed,
}
#[derive(Debug, PartialEq, Eq)]
pub enum ProtocolError {
InvalidState,
InvalidMessage,
Router(I2pError),
}
impl fmt::Display for ProtocolError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidState => write!(f, "invalid state"),
Self::InvalidMessage => write!(f, "invalid message from router"),
Self::Router(error) => write!(f, "router error: {error:?}"),
}
}
}
impl From<ProtocolError> for Error {
fn from(value: ProtocolError) -> Self {
Error::Protocol(value)
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum I2pError {
CantReachPeer,
DuplicateDest,
I2pError(Option<String>),
InvalidKey,
DuplicateId,
KeyNotFound,
PeerNotFound,
Timeout,
}
impl fmt::Display for I2pError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CantReachPeer => write!(f, "the peer exists, but cannot be reached"),
Self::DuplicateDest => write!(f, "the specified destination is already in use"),
Self::I2pError(message) => write!(
f,
"generic i2p error (e.g., i2cp disconnection): {message:?}"
),
Self::InvalidKey => write!(f, "the specified key is not valid (e.g., bad format)"),
Self::KeyNotFound => write!(f, "the naming system can't resolve the given name"),
Self::PeerNotFound => write!(f, "the peer cannot be found on the network"),
Self::Timeout => write!(f, "timeout while waiting for an event (e.g. peer answer)"),
Self::DuplicateId => write!(f, "duplicate id"),
}
}
}
impl TryFrom<(&str, Option<&str>)> for I2pError {
type Error = ();
fn try_from(value: (&str, Option<&str>)) -> Result<Self, Self::Error> {
match value.0 {
"CANT_REACH_PEER" => Ok(I2pError::CantReachPeer),
"DUPLICATE_DEST" => Ok(I2pError::DuplicateDest),
"I2P_ERROR" => Ok(I2pError::I2pError(
value.1.map(|message| message.to_string()),
)),
"INVALID_KEY" => Ok(I2pError::InvalidKey),
"KEY_NOT_FOUND" => Ok(I2pError::KeyNotFound),
"PEER_NOT_FOUND" => Ok(I2pError::PeerNotFound),
"TIMEOUT" => Ok(I2pError::Timeout),
"DUPLICATE_ID" => Ok(I2pError::DuplicateId),
_ => Err(()),
}
}
}