use std::path::PathBuf;
#[cfg(feature = "transport")]
#[derive(Debug, thiserror::Error)]
pub enum TransportError {
#[error("failed to bind Iroh endpoint")]
EndpointBind {
#[source]
source: iroh::endpoint::BindError,
},
#[error("irosh ticket format is invalid")]
TicketFormatInvalid,
#[error(transparent)]
Metadata(#[from] crate::transport::metadata::MetadataError),
#[error(transparent)]
Transfer(#[from] crate::transport::transfer::TransferError),
}
#[cfg(feature = "storage")]
#[derive(Debug, thiserror::Error)]
pub enum StorageError {
#[error("failed to create directory at {path}")]
DirectoryCreate {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to read file at {path}")]
FileRead {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to write file at {path}")]
FileWrite {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to delete file at {path}")]
FileDelete {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to read directory at {path}")]
DirectoryRead {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to read directory entry")]
DirectoryEntryRead {
#[source]
source: std::io::Error,
},
#[error("failed to serialize peer profile")]
PeerProfileSerialize {
#[source]
source: serde_json::Error,
},
#[error("failed to parse peer profile")]
PeerProfileParse {
#[source]
source: serde_json::Error,
},
#[error("node secret at {path} is invalid: {details}")]
NodeSecretInvalid { path: PathBuf, details: String },
#[error("peer name is invalid: {name}")]
PeerNameInvalid { name: String },
#[error("failed to read public key at {path}")]
PublicKeyRead {
path: PathBuf,
#[source]
source: russh::keys::ssh_key::Error,
},
#[error("failed to write public key at {path}")]
PublicKeyWrite {
path: PathBuf,
#[source]
source: russh::keys::ssh_key::Error,
},
#[error("failed to format public key")]
PublicKeyFormat {
#[source]
source: russh::keys::ssh_key::Error,
},
#[error("blocking storage task failed during {operation}")]
BlockingTaskFailed {
operation: &'static str,
#[source]
source: tokio::task::JoinError,
},
}
#[derive(Debug, thiserror::Error)]
pub enum ClientError {
#[error("failed to connect to P2P endpoint")]
ConnectFailed {
#[source]
source: iroh::endpoint::ConnectError,
},
#[error("failed to open SSH transport stream")]
StreamOpenFailed {
#[source]
source: iroh::endpoint::ConnectionError,
},
#[error("metadata request failed: {detail}")]
MetadataFailed { detail: String },
#[error("failed to negotiate SSH protocol")]
SshNegotiationFailed {
#[source]
source: russh::Error,
},
#[error("failed to open SSH session channel")]
ChannelOpenFailed {
#[source]
source: russh::Error,
},
#[error("failed to request PTY")]
PtyRequestFailed {
#[source]
source: russh::Error,
},
#[error("failed to request shell")]
ShellRequestFailed {
#[source]
source: russh::Error,
},
#[error("failed to execute remote command")]
ExecFailed {
#[source]
source: russh::Error,
},
#[error("failed to send data")]
DataSendFailed {
#[source]
source: russh::Error,
},
#[error("failed to send EOF")]
EofSendFailed {
#[source]
source: russh::Error,
},
#[error("failed to resize PTY window")]
WindowChangeFailed {
#[source]
source: russh::Error,
},
#[error("failed to disconnect SSH session")]
DisconnectFailed {
#[source]
source: russh::Error,
},
#[error("terminal I/O error")]
TerminalIo {
#[source]
source: std::io::Error,
},
#[error("SSH peer disconnected during handshake")]
SshHandshakeDisconnected { detail: Option<String> },
#[error("upload failed: {details}")]
UploadFailed { details: String },
#[error("download failed: {details}")]
DownloadFailed { details: String },
#[error("failed to {operation} at {path}")]
FileIo {
operation: &'static str,
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("invalid transfer target: {reason}")]
TransferTargetInvalid { reason: &'static str },
#[error("transfer rejected by remote: {details}")]
TransferRejected { details: String },
#[error("transfer control operation failed: {details}")]
TransferFailed { details: String },
#[error("transport unavailable: {details}")]
TransportUnavailable { details: &'static str },
}
#[derive(Debug, thiserror::Error)]
pub enum ServerError {
#[error("failed to start Iroh background service")]
ServerStart {
#[source]
source: iroh::endpoint::BindError,
},
#[error("failed to format host key")]
FormatHostKey {
#[source]
source: russh::keys::ssh_key::Error,
},
#[error("transfer operation failed: {details}")]
TransferFailed { details: String },
#[error("failed to {operation} at {path}")]
FileIo {
operation: &'static str,
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("transfer rejected: {details}")]
TransferRejected { details: String },
#[error("failed to spawn remote process")]
ProcessSpawnFailed {
#[source]
source: std::io::Error,
},
#[error("blocking server task failed during {operation}")]
BlockingTaskFailed {
operation: &'static str,
#[source]
source: tokio::task::JoinError,
},
#[error("failed to query process {pid}: {details}")]
ProcessQueryFailed { pid: u32, details: String },
#[error("SSH channel error during {operation}: {details}")]
ChannelError {
operation: &'static str,
details: String,
},
#[error("shell error: {details}")]
ShellError { details: String },
}
#[non_exhaustive]
#[derive(Debug, thiserror::Error)]
pub enum IroshError {
#[cfg(feature = "transport")]
#[error("transport error")]
Transport(#[from] TransportError),
#[cfg(feature = "storage")]
#[error("storage error")]
Storage(#[from] StorageError),
#[error("server error")]
Server(#[from] ServerError),
#[error("client error")]
Client(#[from] ClientError),
#[cfg(any(feature = "server", feature = "client"))]
#[error("SSH error: {0}")]
Russh(#[from] russh::Error),
#[error("SSH authentication failed")]
AuthenticationFailed,
#[error("server key mismatch: expected {expected}, got {actual}")]
ServerKeyMismatch { expected: String, actual: String },
#[error("unknown peer: {name}")]
UnknownPeer { name: String },
#[error("invalid connection target: {raw}")]
InvalidTarget { raw: String },
}
pub type Result<T> = std::result::Result<T, IroshError>;