tachyon-i2p 0.0.2

Safe async wrapper around i2pd-sys (native I2P `.b32.i2p` eepsite support).
Documentation
//! Error type returned by this crate's fallible operations.

use std::fmt;

/// Errors that can occur while starting the router, creating a destination, or using a stream.
#[derive(Debug)]
#[non_exhaustive]
pub enum I2pError {
    /// [`I2pRouter::start`](crate::I2pRouter::start) was called while another [`I2pRouter`](crate::I2pRouter)
    /// is already running in this process. libi2pd keeps its router context as a process-wide
    /// global, so only one can ever be active at a time -- this is a hard limitation of the
    /// underlying library, not an arbitrary restriction added here.
    AlreadyRunning,
    /// The application name passed to [`I2pRouter::start`](crate::I2pRouter::start) contained an
    /// interior NUL byte and can't be passed through the C ABI.
    InvalidAppName,
    /// The blocking worker task backing an async call panicked. This should never happen in
    /// practice; if it does, it indicates a bug in this crate or in libi2pd itself.
    WorkerPanicked,
    /// libi2pd failed to create the requested destination (transient or from a keys buffer).
    /// libi2pd's own API reports this as a bare failure with no further detail.
    DestinationCreationFailed,
    /// libi2pd failed to generate a new destination keypair.
    KeyGenerationFailed,
    /// [`Destination::connect`](crate::Destination::connect) did not reach the remote
    /// destination within the given timeout (or failed outright) -- most commonly because a real
    /// I2P tunnel had to be built over the live network first, which can take from several
    /// seconds up to a few minutes.
    ConnectFailed,
    /// The destination was destroyed (dropped) while an [`accept`](crate::Destination::accept)
    /// call was still pending.
    DestinationClosed,
    /// An I/O error occurred reading/writing a persistent keys file.
    Io(std::io::Error),
}

impl fmt::Display for I2pError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::AlreadyRunning => f.write_str("an I2pRouter is already running in this process"),
            Self::InvalidAppName => f.write_str("application name contains an interior NUL byte"),
            Self::WorkerPanicked => f.write_str("internal blocking worker task panicked"),
            Self::DestinationCreationFailed => {
                f.write_str("libi2pd failed to create the destination")
            }
            Self::KeyGenerationFailed => {
                f.write_str("libi2pd failed to generate a destination keypair")
            }
            Self::ConnectFailed => f.write_str("failed to connect to the remote I2P destination"),
            Self::DestinationClosed => f.write_str("the destination was closed"),
            Self::Io(e) => write!(f, "I/O error: {e}"),
        }
    }
}

impl std::error::Error for I2pError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Io(e) => Some(e),
            _ => None,
        }
    }
}