1#![allow(
2 clippy::module_name_repetitions,
3 reason = "Error suffix is for readability"
4)]
5use std::io::Error as StdIoError;
6
7#[derive(Debug, thiserror::Error)]
9pub enum ClientError {
10 #[error("Connection error: {0}")]
12 Connection(#[from] ConnectionError),
13
14 #[error("Authentication failed: {reason}")]
16 Authentication { reason: String },
17
18 #[error("Stream error: {0}")]
20 Stream(#[from] StreamError),
21
22 #[error("Protocol error: {0}")]
24 Protocol(#[from] ProtocolError),
25
26 #[error("Operation timed out after {timeout_ms}ms")]
28 Timeout { timeout_ms: u128 },
29
30 #[error("Configuration error: {message}")]
32 Configuration { message: String },
33
34 #[error("Protocol mismatch: expected {expected}, actual {actual}")]
36 ProtocolMismatch { expected: String, actual: String },
37
38 #[error("Invalid internal state: {reason}")]
40 InvalidInternalState { reason: String },
41}
42
43#[derive(Debug, thiserror::Error)]
45pub enum ConnectionError {
46 #[error("Failed to connect to {address}: {source}")]
48 TcpConnect {
49 address: String,
50 #[source]
51 source: StdIoError,
52 },
53
54 #[error("Noise handshake failed: {reason}")]
56 NoiseHandshake { reason: String },
57}
58
59#[derive(Debug, thiserror::Error)]
61pub enum StreamError {
62 #[error("Invalid frame format: {reason}")]
64 InvalidFrame { reason: String },
65
66 #[error("Frame too large: {size} bytes (max: {max_size})")]
68 FrameTooLarge { size: usize, max_size: usize },
69
70 #[error("Read error: {source}")]
72 Read {
73 #[source]
74 source: StdIoError,
75 },
76
77 #[error("Write error: {source}")]
79 Write {
80 #[source]
81 source: StdIoError,
82 },
83}
84
85#[derive(Debug, thiserror::Error)]
87pub enum ProtocolError {
88 #[error("Protobuf parsing failed: {source}")]
90 ProtobufParse {
91 #[source]
92 source: prost::DecodeError,
93 },
94
95 #[error("Protobuf encoding failed: {source}")]
97 ProtobufEncode {
98 #[source]
99 source: prost::EncodeError,
100 },
101
102 #[error("Unexpected plain data: Device is notusing noise encryption protocol")]
104 UnexpectedPlain,
105
106 #[error("Unexpected encryption: Device is using noise encryption protocol")]
108 UnexpectedEncryption,
109
110 #[error("Message validation failed: {reason}")]
112 ValidationFailed { reason: String },
113}
114
115#[derive(Debug, thiserror::Error)]
117pub enum DiscoveryError {
118 #[error("Initialization error: {reason}")]
120 InitializationError { reason: String },
121
122 #[error("Discovery aborted")]
124 Aborted,
125}
126
127#[derive(Debug, thiserror::Error)]
129pub enum NoiseError {
130 #[error("Noise handshake error: {reason}")]
132 Handshake { reason: String },
133
134 #[error("Noise transport error: {reason}")]
136 Transport { reason: String },
137
138 #[error("Invalid noise key: {reason}")]
140 InvalidKey { reason: String },
141
142 #[error("Noise crypto operation failed: {reason}")]
144 CryptoOperation { reason: String },
145}
146
147impl From<snow::Error> for NoiseError {
149 fn from(err: snow::Error) -> Self {
150 match err {
151 snow::Error::Init(_) => Self::Handshake {
152 reason: err.to_string(),
153 },
154 snow::Error::Decrypt => Self::CryptoOperation {
155 reason: "Decryption failed".to_owned(),
156 },
157 _ => Self::Transport {
158 reason: err.to_string(),
159 },
160 }
161 }
162}
163
164impl From<NoiseError> for ClientError {
166 fn from(err: NoiseError) -> Self {
167 Self::Connection(ConnectionError::NoiseHandshake {
168 reason: err.to_string(),
169 })
170 }
171}
172
173impl From<prost::DecodeError> for ProtocolError {
175 fn from(err: prost::DecodeError) -> Self {
176 Self::ProtobufParse { source: err }
177 }
178}
179
180impl From<prost::EncodeError> for ProtocolError {
181 fn from(err: prost::EncodeError) -> Self {
182 Self::ProtobufEncode { source: err }
183 }
184}