1use std::time::SystemTimeError;
2
3use kameo::error::SendError;
4use sierradb_cluster::ClusterError;
5use sierradb_cluster::write::error::WriteError;
6use sierradb_protocol::ErrorCode;
7
8pub trait MapRedisError<T> {
10 fn map_redis_err(self) -> Result<T, String>;
11}
12
13impl<T, E: AsRedisError> MapRedisError<T> for Result<T, E> {
14 fn map_redis_err(self) -> Result<T, String> {
15 self.map_err(|err| err.as_redis_error())
16 }
17}
18
19pub trait AsRedisError {
21 fn as_redis_error(&self) -> String;
22}
23
24impl AsRedisError for String {
25 fn as_redis_error(&self) -> String {
26 self.clone()
27 }
28}
29
30impl AsRedisError for &str {
31 fn as_redis_error(&self) -> String {
32 self.to_string()
33 }
34}
35
36impl<M, E: AsRedisError> AsRedisError for SendError<M, E> {
37 fn as_redis_error(&self) -> String {
38 match self {
39 SendError::ActorNotRunning(_) => ErrorCode::ActorDown.with_message("actor not running"),
40 SendError::ActorStopped => {
41 ErrorCode::ActorStopped.with_message("actor died when executing request")
42 }
43 SendError::MailboxFull(_) => {
44 ErrorCode::MailboxFull.with_message("actor mailbox is full")
45 }
46 SendError::HandlerError(err) => err.as_redis_error(),
47 SendError::Timeout(_) => ErrorCode::Timeout.to_string(),
48 }
49 }
50}
51
52impl AsRedisError for WriteError {
53 fn as_redis_error(&self) -> String {
54 let code = match self {
55 WriteError::AllReplicasFailed => ErrorCode::AllReplicasFailed,
56 WriteError::BufferEvicted => ErrorCode::BufferEvicted,
57 WriteError::BufferFull => ErrorCode::BufferFull,
58 WriteError::CircuitBreakerOpen { .. } => ErrorCode::CircuitOpen,
59 WriteError::ConfirmationFailed(_) => ErrorCode::ConfirmFailed,
60 WriteError::ReplicationConfirmationFailed(_) => ErrorCode::ReplConfirmFailed,
61 WriteError::DatabaseOperationFailed(_) => ErrorCode::DbOpFailed,
62 WriteError::InsufficientHealthyReplicas { .. } => ErrorCode::InsufficientReplicas,
63 WriteError::InvalidSender => ErrorCode::InvalidSender,
64 WriteError::StaleWrite => ErrorCode::StaleWrite,
65 WriteError::MissingExpectedPartitionSequence => ErrorCode::MissingPartSeq,
66 WriteError::PartitionNotOwned { .. } => ErrorCode::PartNotOwned,
67 WriteError::ReplicationQuorumFailed { .. } => ErrorCode::QuorumFailed,
68 WriteError::RequestTimeout => ErrorCode::Timeout,
69 WriteError::MaximumForwardsExceeded { .. } => ErrorCode::MaxForwards,
70 WriteError::RemoteOperationFailed(_) => ErrorCode::RemoteOpFailed,
71 WriteError::SequenceConflict => ErrorCode::SeqConflict,
72 WriteError::WrongExpectedSequence { .. } => ErrorCode::WrongSeq,
73 WriteError::WrongExpectedVersion { .. } => ErrorCode::WrongVer,
74 };
75
76 format!("{code} {self}")
77 }
78}
79
80impl AsRedisError for SystemTimeError {
81 fn as_redis_error(&self) -> String {
82 ErrorCode::ClockErr.with_message(self.to_string())
83 }
84}
85
86impl AsRedisError for kameo::error::Infallible {
87 fn as_redis_error(&self) -> String {
88 unreachable!()
89 }
90}
91
92impl AsRedisError for ClusterError {
93 fn as_redis_error(&self) -> String {
94 let code = match self {
95 ClusterError::InsufficientPartitionsForQuorum { .. } => ErrorCode::ClusterDown,
96 ClusterError::NoAvailablePartitions => ErrorCode::ClusterDown,
97 ClusterError::PartitionUnavailable => ErrorCode::ClusterDown,
98 ClusterError::NoAvailableLeaders => ErrorCode::ClusterDown,
99 ClusterError::QuorumNotAchieved { .. } => ErrorCode::TryAgain,
100 ClusterError::WriteTimeout => ErrorCode::Timeout,
101 ClusterError::TooManyForwards => ErrorCode::MaxForwards,
102 ClusterError::CircuitBreakerOpen { .. } => ErrorCode::CircuitOpen,
103 ClusterError::ConfirmationFailure(_) => ErrorCode::ConfirmFailed,
104 ClusterError::Read(_) => ErrorCode::ReadErr,
105 ClusterError::Write(_) => ErrorCode::WriteErr,
106 ClusterError::RemoteSend(_) => ErrorCode::RemoteErr,
107 ClusterError::Noise(_) => ErrorCode::NoiseErr,
108 ClusterError::Transport(_) => ErrorCode::TransportErr,
109 ClusterError::SwarmBuilder(_) => ErrorCode::SwarmErr,
110 };
111
112 match self {
113 ClusterError::InsufficientPartitionsForQuorum { alive, required } => code.with_message(
114 format!("insufficient partitions alive for quorum ({alive}/{required})"),
115 ),
116 ClusterError::NoAvailablePartitions => code.with_message("no available partitions"),
117 ClusterError::PartitionUnavailable => code.with_message("partition unavailable"),
118 ClusterError::NoAvailableLeaders => code.with_message("no available leaders"),
119 ClusterError::QuorumNotAchieved {
120 confirmed,
121 required,
122 } => code.with_message(format!("quorum not achieved ({confirmed}/{required})")),
123 ClusterError::WriteTimeout => code.with_message("write timed out"),
124 ClusterError::TooManyForwards => code.with_message("too many forwards"),
125 ClusterError::CircuitBreakerOpen {
126 estimated_recovery_time,
127 } => match estimated_recovery_time {
128 Some(time) => code.with_message(format!(
129 "circuit breaker open: estimated recovery time: {time:?}"
130 )),
131 None => code.with_message("circuit breaker open"),
132 },
133 ClusterError::ConfirmationFailure(msg) => {
134 code.with_message(format!("failed to write confirmation count: {msg}"))
135 }
136 ClusterError::Read(msg) => code.with_message(format!("read error: {msg}")),
137 ClusterError::Write(msg) => code.with_message(format!("write error: {msg}")),
138 ClusterError::RemoteSend(err) => code.with_message(format!("remote send error: {err}")),
139 ClusterError::Noise(err) => code.with_message(format!("noise error: {err}")),
140 ClusterError::Transport(err) => code.with_message(format!("transport error: {err}")),
141 ClusterError::SwarmBuilder(err) => {
142 code.with_message(format!("swarm builder error: {err}"))
143 }
144 }
145 }
146}