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 {
17 reason: String,
19 },
20
21 #[error("Stream error: {0}")]
23 Stream(#[from] StreamError),
24
25 #[error("Protocol error: {0}")]
27 Protocol(#[from] ProtocolError),
28
29 #[error("Operation timed out after {timeout_ms}ms")]
31 Timeout {
32 timeout_ms: u128,
34 },
35
36 #[error("Configuration error: {message}")]
38 Configuration {
39 message: String,
41 },
42
43 #[error("Protocol mismatch: expected {expected}, actual {actual}")]
45 ProtocolMismatch {
46 expected: String,
48 actual: String,
50 },
51
52 #[error("Invalid internal state: {reason}")]
54 InvalidInternalState {
55 reason: String,
57 },
58}
59
60#[derive(Debug, thiserror::Error)]
62pub enum ConnectionError {
63 #[error("Failed to connect to {address}: {source}")]
65 TcpConnect {
66 address: String,
68 #[source]
70 source: StdIoError,
71 },
72
73 #[error("Noise handshake failed: {reason}")]
75 NoiseHandshake {
76 reason: String,
78 },
79}
80
81#[derive(Debug, thiserror::Error)]
83pub enum StreamError {
84 #[error("Invalid frame format: {reason}")]
86 InvalidFrame {
87 reason: String,
89 },
90
91 #[error("Frame too large: {size} bytes (max: {max_size})")]
93 FrameTooLarge {
94 size: usize,
96 max_size: usize,
98 },
99
100 #[error("Read error: {source}")]
102 Read {
103 #[source]
105 source: StdIoError,
106 },
107
108 #[error("Write error: {source}")]
110 Write {
111 #[source]
113 source: StdIoError,
114 },
115}
116
117#[derive(Debug, thiserror::Error)]
119pub enum ProtocolError {
120 #[error("Protobuf parsing failed: {source}")]
122 ProtobufParse {
123 #[source]
125 source: prost::DecodeError,
126 },
127
128 #[error("Protobuf encoding failed: {source}")]
130 ProtobufEncode {
131 #[source]
133 source: prost::EncodeError,
134 },
135
136 #[error("Unexpected plain data: Device is notusing noise encryption protocol")]
138 UnexpectedPlain,
139
140 #[error("Unexpected encryption: Device is using noise encryption protocol")]
142 UnexpectedEncryption,
143
144 #[error("Message validation failed: {reason}")]
146 ValidationFailed {
147 reason: String,
149 },
150}
151
152#[derive(Debug, thiserror::Error)]
154pub enum DiscoveryError {
155 #[error("Initialization error: {reason}")]
157 InitializationError {
158 reason: String,
160 },
161
162 #[error("Discovery aborted")]
164 Aborted,
165}
166
167#[derive(Debug, thiserror::Error)]
169pub enum NoiseError {
170 #[error("Noise handshake error: {reason}")]
172 Handshake {
173 reason: String,
175 },
176
177 #[error("Noise transport error: {reason}")]
179 Transport {
180 reason: String,
182 },
183
184 #[error("Invalid noise key: {reason}")]
186 InvalidKey {
187 reason: String,
189 },
190
191 #[error("Noise crypto operation failed: {reason}")]
193 CryptoOperation {
194 reason: String,
196 },
197}
198
199impl From<snow::Error> for NoiseError {
201 fn from(err: snow::Error) -> Self {
202 match err {
203 snow::Error::Init(_) => Self::Handshake {
204 reason: err.to_string(),
205 },
206 snow::Error::Decrypt => Self::CryptoOperation {
207 reason: "Decryption failed".to_owned(),
208 },
209 _ => Self::Transport {
210 reason: err.to_string(),
211 },
212 }
213 }
214}
215
216impl From<NoiseError> for ClientError {
218 fn from(err: NoiseError) -> Self {
219 Self::Connection(ConnectionError::NoiseHandshake {
220 reason: err.to_string(),
221 })
222 }
223}
224
225impl From<prost::DecodeError> for ProtocolError {
227 fn from(err: prost::DecodeError) -> Self {
228 Self::ProtobufParse { source: err }
229 }
230}
231
232impl From<prost::EncodeError> for ProtocolError {
233 fn from(err: prost::EncodeError) -> Self {
234 Self::ProtobufEncode { source: err }
235 }
236}