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