1use std::fmt;
2
3use std::net::SocketAddr;
4
5#[derive(Debug)]
6pub enum ClientError {
7 ConnectionFailed(std::io::Error),
8 ConnectionClosed,
9 IoError(std::io::Error),
10 ProtocolError(String),
11 InvalidResponse(String),
12 Timeout,
13 CrcMismatch {
14 expected: u32,
15 actual: u32,
16 },
17 ServerBackpressure,
18 ServerError(String),
19 NotLeader {
21 leader_addr: Option<SocketAddr>,
22 },
23 TlsError(String),
25}
26
27impl fmt::Display for ClientError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Self::ConnectionFailed(e) => write!(f, "Connection failed: {}", e),
31 Self::ConnectionClosed => write!(f, "Connection closed by server"),
32 Self::IoError(e) => write!(f, "I/O error: {}", e),
33 Self::ProtocolError(msg) => write!(f, "Protocol error: {}", msg),
34 Self::InvalidResponse(msg) => write!(f, "Invalid response: {}", msg),
35 Self::Timeout => write!(f, "Operation timed out"),
36 Self::CrcMismatch { expected, actual } => {
37 write!(
38 f,
39 "CRC mismatch: expected {:#x}, got {:#x}",
40 expected, actual
41 )
42 },
43 Self::ServerBackpressure => write!(f, "Server signaled backpressure"),
44 Self::ServerError(msg) => write!(f, "Server error: {}", msg),
45 Self::NotLeader { leader_addr } => match leader_addr {
46 Some(addr) => write!(f, "Not leader, redirect to {}", addr),
47 None => write!(f, "Not leader, leader unknown"),
48 },
49 Self::TlsError(msg) => write!(f, "TLS error: {}", msg),
50 }
51 }
52}
53
54pub fn parse_not_leader_error(msg: &str) -> Option<Option<SocketAddr>> {
56 if !msg.starts_with("NOT_LEADER:") {
57 return None;
58 }
59
60 if msg.contains("leader unknown") {
61 return Some(None);
62 }
63
64 if let Some(addr_str) = msg.strip_prefix("NOT_LEADER: redirect to ") {
66 if let Ok(addr) = addr_str.trim().parse::<SocketAddr>() {
67 return Some(Some(addr));
68 }
69 }
70
71 Some(None)
72}
73
74impl std::error::Error for ClientError {
75 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
76 match self {
77 Self::ConnectionFailed(e) | Self::IoError(e) => Some(e),
78 _ => None,
79 }
80 }
81}
82
83impl From<std::io::Error> for ClientError {
84 fn from(err: std::io::Error) -> Self {
85 Self::IoError(err)
86 }
87}
88
89impl From<lnc_core::LanceError> for ClientError {
90 fn from(err: lnc_core::LanceError) -> Self {
91 Self::ProtocolError(err.to_string())
92 }
93}
94
95pub type Result<T> = std::result::Result<T, ClientError>;