#![allow(
clippy::module_name_repetitions,
reason = "Error suffix is for readability"
)]
use std::io::Error as StdIoError;
#[derive(Debug, thiserror::Error)]
pub enum ClientError {
#[error("Connection error: {0}")]
Connection(#[from] ConnectionError),
#[error("Authentication failed: {reason}")]
Authentication {
reason: String,
},
#[error("Stream error: {0}")]
Stream(#[from] StreamError),
#[error("Protocol error: {0}")]
Protocol(#[from] ProtocolError),
#[error("Operation timed out after {timeout_ms}ms")]
Timeout {
timeout_ms: u128,
},
#[error("Configuration error: {message}")]
Configuration {
message: String,
},
#[error("Protocol mismatch: expected {expected}, actual {actual}")]
ProtocolMismatch {
expected: String,
actual: String,
},
#[error("Invalid internal state: {reason}")]
InvalidInternalState {
reason: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum ConnectionError {
#[error("Failed to connect to {address}: {source}")]
TcpConnect {
address: String,
#[source]
source: StdIoError,
},
#[error("Noise handshake failed: {reason}")]
NoiseHandshake {
reason: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum StreamError {
#[error("Invalid frame format: {reason}")]
InvalidFrame {
reason: String,
},
#[error("Frame too large: {size} bytes (max: {max_size})")]
FrameTooLarge {
size: usize,
max_size: usize,
},
#[error("Read error: {source}")]
Read {
#[source]
source: StdIoError,
},
#[error("Write error: {source}")]
Write {
#[source]
source: StdIoError,
},
}
#[derive(Debug, thiserror::Error)]
pub enum ProtocolError {
#[error("Protobuf parsing failed: {source}")]
ProtobufParse {
#[source]
source: prost::DecodeError,
},
#[error("Protobuf encoding failed: {source}")]
ProtobufEncode {
#[source]
source: prost::EncodeError,
},
#[error("Unexpected plain data: Device is notusing noise encryption protocol")]
UnexpectedPlain,
#[error("Unexpected encryption: Device is using noise encryption protocol")]
UnexpectedEncryption,
#[error("Message validation failed: {reason}")]
ValidationFailed {
reason: String,
},
}
#[derive(Debug, thiserror::Error)]
pub enum DiscoveryError {
#[error("Initialization error: {reason}")]
InitializationError {
reason: String,
},
#[error("Discovery aborted")]
Aborted,
}
#[derive(Debug, thiserror::Error)]
pub enum NoiseError {
#[error("Noise handshake error: {reason}")]
Handshake {
reason: String,
},
#[error("Noise transport error: {reason}")]
Transport {
reason: String,
},
#[error("Invalid noise key: {reason}")]
InvalidKey {
reason: String,
},
#[error("Noise crypto operation failed: {reason}")]
CryptoOperation {
reason: String,
},
}
impl From<snow::Error> for NoiseError {
fn from(err: snow::Error) -> Self {
match err {
snow::Error::Init(_) => Self::Handshake {
reason: err.to_string(),
},
snow::Error::Decrypt => Self::CryptoOperation {
reason: "Decryption failed".to_owned(),
},
_ => Self::Transport {
reason: err.to_string(),
},
}
}
}
impl From<NoiseError> for ClientError {
fn from(err: NoiseError) -> Self {
Self::Connection(ConnectionError::NoiseHandshake {
reason: err.to_string(),
})
}
}
impl From<prost::DecodeError> for ProtocolError {
fn from(err: prost::DecodeError) -> Self {
Self::ProtobufParse { source: err }
}
}
impl From<prost::EncodeError> for ProtocolError {
fn from(err: prost::EncodeError) -> Self {
Self::ProtobufEncode { source: err }
}
}