1use crate::httpx;
20use crate::tracingcomponent::MetricsName;
21use http::StatusCode;
22use std::error::Error as StdError;
23use std::fmt::{Display, Formatter};
24
25pub type Result<T> = std::result::Result<T, Error>;
26
27#[derive(Debug, Clone, PartialEq)]
28pub struct Error {
29 inner: ErrorImpl,
30}
31
32impl Display for Error {
33 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
34 write!(f, "{}", self.inner.kind)
35 }
36}
37
38impl StdError for Error {}
39
40impl Error {
41 pub(crate) fn new_server_error(e: ServerError) -> Error {
42 Self {
43 inner: ErrorImpl {
44 kind: Box::new(ErrorKind::Server(e)),
45 },
46 }
47 }
48
49 pub(crate) fn new_message_error(
50 msg: impl Into<String>,
51 endpoint: impl Into<Option<String>>,
52 ) -> Error {
53 Self {
54 inner: ErrorImpl {
55 kind: Box::new(ErrorKind::Message {
56 msg: msg.into(),
57 endpoint: endpoint.into(),
58 }),
59 },
60 }
61 }
62
63 pub(crate) fn new_encoding_error(msg: impl Into<String>) -> Error {
64 Self {
65 inner: ErrorImpl {
66 kind: Box::new(ErrorKind::Encoding { msg: msg.into() }),
67 },
68 }
69 }
70
71 pub(crate) fn new_invalid_argument_error(
72 msg: impl Into<String>,
73 arg: impl Into<Option<String>>,
74 ) -> Self {
75 Self {
76 inner: ErrorImpl {
77 kind: Box::new(ErrorKind::InvalidArgument {
78 msg: msg.into(),
79 arg: arg.into(),
80 }),
81 },
82 }
83 }
84
85 pub(crate) fn new_http_error(error: httpx::error::Error, endpoint: impl Into<String>) -> Self {
86 Self {
87 inner: ErrorImpl {
88 kind: Box::new(ErrorKind::Http {
89 error,
90 endpoint: endpoint.into(),
91 }),
92 },
93 }
94 }
95
96 pub(crate) fn new_unsupported_feature_error(feature: String) -> Self {
97 Self {
98 inner: ErrorImpl {
99 kind: Box::new(ErrorKind::UnsupportedFeature { feature }),
100 },
101 }
102 }
103
104 pub fn kind(&self) -> &ErrorKind {
105 &self.inner.kind
106 }
107}
108
109#[derive(Debug, Clone)]
110struct ErrorImpl {
111 kind: Box<ErrorKind>,
112}
113
114impl PartialEq for ErrorImpl {
115 fn eq(&self, other: &Self) -> bool {
116 self.kind == other.kind
117 }
118}
119
120#[derive(Clone, Debug, PartialEq, Eq)]
121#[non_exhaustive]
122pub enum ErrorKind {
123 Server(ServerError),
124 #[non_exhaustive]
125 Http {
126 error: httpx::error::Error,
127 endpoint: String,
128 },
129 #[non_exhaustive]
130 Message {
131 msg: String,
132 endpoint: Option<String>,
133 },
134 #[non_exhaustive]
135 InvalidArgument {
136 msg: String,
137 arg: Option<String>,
138 },
139 #[non_exhaustive]
140 Encoding {
141 msg: String,
142 },
143 UnsupportedFeature {
144 feature: String,
145 },
146}
147
148impl Display for ErrorKind {
149 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
150 match self {
151 ErrorKind::Server(e) => write!(f, "{e}"),
152 ErrorKind::Http { error, endpoint } => {
153 write!(f, "http error {error}: endpoint {endpoint}")
154 }
155 ErrorKind::Message { msg, endpoint } => {
156 if let Some(endpoint) = endpoint {
157 write!(f, "message error for endpoint {endpoint}: {msg}")
158 } else {
159 write!(f, "message error: {msg}")
160 }
161 }
162 ErrorKind::InvalidArgument { msg, arg } => {
163 if let Some(arg) = arg {
164 write!(f, "invalid argument error for argument {arg}: {msg}")
165 } else {
166 write!(f, "invalid argument error: {msg}")
167 }
168 }
169 ErrorKind::Encoding { msg } => write!(f, "encoding error: {msg}"),
170 ErrorKind::UnsupportedFeature { feature } => {
171 write!(f, "unsupported feature: {feature}")
172 }
173 }
174 }
175}
176
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub struct ServerError {
179 kind: ServerErrorKind,
180
181 index_name: String,
182
183 error_text: String,
184 endpoint: String,
185 status_code: StatusCode,
186}
187
188impl Display for ServerError {
189 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190 write!(
191 f,
192 "server error for index {} at endpoint {}, status code: {}: {}, error text: {}",
193 self.index_name, self.endpoint, self.status_code, self.kind, self.error_text
194 )
195 }
196}
197
198impl ServerError {
199 pub(crate) fn new(
200 kind: ServerErrorKind,
201 index_name: impl Into<String>,
202 error_text: impl Into<String>,
203 endpoint: impl Into<String>,
204 status_code: StatusCode,
205 ) -> Self {
206 Self {
207 kind,
208 error_text: error_text.into(),
209 index_name: index_name.into(),
210 endpoint: endpoint.into(),
211 status_code,
212 }
213 }
214
215 pub fn kind(&self) -> &ServerErrorKind {
216 &self.kind
217 }
218
219 pub fn index_name(&self) -> &str {
220 &self.index_name
221 }
222
223 pub fn endpoint(&self) -> &str {
224 &self.endpoint
225 }
226
227 pub fn status_code(&self) -> StatusCode {
228 self.status_code
229 }
230
231 pub fn error_text(&self) -> &str {
232 &self.error_text
233 }
234}
235
236#[derive(Clone, Debug, PartialEq, Eq)]
237#[non_exhaustive]
238pub enum ServerErrorKind {
239 Internal,
240 AuthenticationFailure,
241 IndexExists,
242 IndexNotFound,
243 UnknownIndexType,
244 SourceTypeIncorrect,
245 SourceNotFound,
246 NoIndexPartitionsPlanned,
247 NoIndexPartitionsFound,
248 UnsupportedFeature,
249 RateLimitedFailure,
250 Unknown,
251}
252
253impl Display for ServerErrorKind {
254 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
255 match self {
256 ServerErrorKind::Internal => write!(f, "internal server error"),
257 ServerErrorKind::AuthenticationFailure => write!(f, "authentication failure"),
258 ServerErrorKind::IndexExists => write!(f, "index exists"),
259 ServerErrorKind::IndexNotFound => write!(f, "index not found"),
260 ServerErrorKind::UnknownIndexType => write!(f, "unknown index type"),
261 ServerErrorKind::SourceTypeIncorrect => write!(f, "source type incorrect"),
262 ServerErrorKind::SourceNotFound => write!(f, "source not found"),
263 ServerErrorKind::NoIndexPartitionsPlanned => write!(f, "no index partitions planned"),
264 ServerErrorKind::NoIndexPartitionsFound => write!(f, "no index partitions found"),
265 ServerErrorKind::UnsupportedFeature => write!(f, "unsupported feature"),
266 ServerErrorKind::RateLimitedFailure => write!(f, "rate limited failure"),
267 ServerErrorKind::Unknown => write!(f, "unknown error"),
268 }
269 }
270}
271
272impl MetricsName for Error {
273 fn metrics_name(&self) -> &'static str {
274 match self.kind() {
275 ErrorKind::Server(e) => e.kind().metrics_name(),
276 ErrorKind::Http { error, .. } => error.metrics_name(),
277 ErrorKind::Message { .. } => "searchx._OTHER",
278 ErrorKind::InvalidArgument { .. } => "searchx.InvalidArgument",
279 ErrorKind::Encoding { .. } => "searchx.Encoding",
280 ErrorKind::UnsupportedFeature { .. } => "searchx.UnsupportedFeature",
281 }
282 }
283}
284
285impl MetricsName for ServerErrorKind {
286 fn metrics_name(&self) -> &'static str {
287 match self {
288 ServerErrorKind::Internal => "searchx.Internal",
289 ServerErrorKind::AuthenticationFailure => "searchx.AuthenticationFailure",
290 ServerErrorKind::IndexExists => "searchx.IndexExists",
291 ServerErrorKind::IndexNotFound => "searchx.IndexNotFound",
292 ServerErrorKind::UnknownIndexType => "searchx.UnknownIndexType",
293 ServerErrorKind::SourceTypeIncorrect => "searchx.SourceTypeIncorrect",
294 ServerErrorKind::SourceNotFound => "searchx.SourceNotFound",
295 ServerErrorKind::NoIndexPartitionsPlanned => "searchx.NoIndexPartitionsPlanned",
296 ServerErrorKind::NoIndexPartitionsFound => "searchx.NoIndexPartitionsFound",
297 ServerErrorKind::UnsupportedFeature => "searchx.UnsupportedFeature",
298 ServerErrorKind::RateLimitedFailure => "searchx.RateLimitedFailure",
299 ServerErrorKind::Unknown => "searchx._OTHER",
300 }
301 }
302}