rocketmq_client_rust/
client_error.rs

1/*/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17use cheetah_string::CheetahString;
18use rocketmq_common::common::FAQUrl;
19use rocketmq_remoting::remoting_error::RemotingError;
20use thiserror::Error;
21
22#[derive(Debug, Error)]
23pub enum MQClientError {
24    #[error("{0}")]
25    MQClientErr(#[from] ClientErr),
26
27    #[error("{0}")]
28    RemotingTooMuchRequestError(String),
29
30    #[error("{0}")]
31    MQClientBrokerError(#[from] MQBrokerErr),
32
33    #[error("{0}")]
34    RequestTimeoutError(#[from] RequestTimeoutErr),
35
36    #[error("Client exception occurred: CODE:{0}, broker address:{1}, Message:{2}")]
37    OffsetNotFoundError(i32, String, String),
38
39    #[error("{0}")]
40    RemotingError(#[from] RemotingError),
41
42    #[error("{0}")]
43    IllegalArgumentError(String),
44
45    #[error("{0}")]
46    CommonError(#[from] rocketmq_common::error::Error),
47}
48
49#[derive(Error, Debug)]
50#[error("{message}")]
51pub struct MQBrokerErr {
52    response_code: i32,
53    error_message: Option<CheetahString>,
54    broker_addr: Option<CheetahString>,
55    message: CheetahString,
56}
57
58impl MQBrokerErr {
59    pub fn new(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
60        let error_message = error_message.into();
61        let message = FAQUrl::attach_default_url(Some(
62            format!("CODE: {}  DESC: {}", response_code, error_message,).as_str(),
63        ));
64        Self {
65            response_code,
66            error_message: Some(error_message),
67            broker_addr: None,
68            message: CheetahString::from(message),
69        }
70    }
71
72    pub fn new_with_broker(
73        response_code: i32,
74        error_message: impl Into<CheetahString>,
75        broker_addr: impl Into<CheetahString>,
76    ) -> Self {
77        let broker_addr = broker_addr.into();
78        let error_message = error_message.into();
79        let message = FAQUrl::attach_default_url(Some(
80            format!(
81                "CODE: {}  DESC: {} BROKER: {}",
82                response_code, error_message, broker_addr
83            )
84            .as_str(),
85        ));
86        Self {
87            response_code,
88            error_message: Some(error_message),
89            broker_addr: Some(broker_addr),
90            message: CheetahString::from(message),
91        }
92    }
93
94    pub fn response_code(&self) -> i32 {
95        self.response_code
96    }
97
98    pub fn error_message(&self) -> Option<&CheetahString> {
99        self.error_message.as_ref()
100    }
101
102    pub fn broker_addr(&self) -> Option<&CheetahString> {
103        self.broker_addr.as_ref()
104    }
105}
106
107// Note: Macros mq_client_err! and client_broker_err! are now defined in lib.rs
108// to ensure they're available throughout the crate
109
110#[derive(Error, Debug)]
111#[error("{message}")]
112pub struct ClientErr {
113    response_code: i32,
114    error_message: Option<CheetahString>,
115    message: CheetahString,
116}
117
118impl ClientErr {
119    pub fn new(error_message: impl Into<CheetahString>) -> Self {
120        let error_message = error_message.into();
121        let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
122        Self {
123            response_code: -1,
124            error_message: Some(error_message),
125            message: CheetahString::from(message),
126        }
127    }
128
129    pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
130        let error_message = error_message.into();
131        let message = FAQUrl::attach_default_url(Some(
132            format!("CODE: {}  DESC: {}", response_code, error_message,).as_str(),
133        ));
134        Self {
135            response_code,
136            error_message: Some(error_message),
137            message: CheetahString::from(message),
138        }
139    }
140
141    pub fn response_code(&self) -> i32 {
142        self.response_code
143    }
144
145    pub fn error_message(&self) -> Option<&CheetahString> {
146        self.error_message.as_ref()
147    }
148}
149
150#[derive(Error, Debug)]
151#[error("{message}")]
152pub struct RequestTimeoutErr {
153    response_code: i32,
154    error_message: Option<CheetahString>,
155    message: CheetahString,
156}
157
158impl RequestTimeoutErr {
159    pub fn new(error_message: impl Into<CheetahString>) -> Self {
160        let error_message = error_message.into();
161        let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
162        Self {
163            response_code: -1,
164            error_message: Some(error_message),
165            message: CheetahString::from(message),
166        }
167    }
168
169    pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
170        let error_message = error_message.into();
171        let message = FAQUrl::attach_default_url(Some(
172            format!("CODE: {}  DESC: {}", response_code, error_message,).as_str(),
173        ));
174        Self {
175            response_code,
176            error_message: Some(error_message),
177            message: CheetahString::from(message),
178        }
179    }
180
181    pub fn response_code(&self) -> i32 {
182        self.response_code
183    }
184
185    pub fn error_message(&self) -> Option<&CheetahString> {
186        self.error_message.as_ref()
187    }
188}
189
190#[macro_export]
191macro_rules! request_timeout_err {
192    // Handle errors with a custom ResponseCode and formatted string
193    ($response_code:expr, $fmt:expr, $($arg:expr),*) => {{
194        let formatted_msg = format!($fmt, $($arg),*);
195        std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
196            $crate::client_error::RequestTimeoutErr::new_with_code(
197                $response_code as i32,
198                formatted_msg,
199            ),
200        ))
201    }};
202    ($response_code:expr, $error_message:expr) => {{
203        std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
204            $crate::client_error::RequestTimeoutErr::new_with_code(
205                $response_code as i32,
206                $error_message,
207            ),
208        ))
209    }};
210    // Handle errors without a ResponseCode, using only the error message
211    ($error_message:expr) => {{
212        std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
213            $crate::client_error::RequestTimeoutErr::new($error_message),
214        ))
215    }};
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221    use crate::client_error;
222
223    #[test]
224    fn client_err_with_response_code_formats_correctly() {
225        let result: std::result::Result<(), client_error::MQClientError> =
226            Err(mq_client_err!(404, "Error: not found"));
227        assert!(result.is_err());
228        if let Err(MQClientError::MQClientErr(err)) = result {
229            assert_eq!(err.response_code(), 404);
230            assert_eq!(err.error_message().unwrap(), "Error: not found");
231        } else {
232            panic!("Expected MQClientError::MQClientErr");
233        }
234    }
235
236    #[test]
237    fn client_broker_err_with_response_code_and_broker_formats_correctly() {
238        let result: std::result::Result<(), client_error::MQClientError> =
239            Err(client_broker_err!(404, "Error: {}", "127.0.0.1"));
240        assert!(result.is_err());
241        if let Err(MQClientError::MQClientBrokerError(err)) = result {
242            assert_eq!(err.response_code(), 404);
243            assert_eq!(err.error_message().unwrap(), "Error: {}");
244            assert_eq!(err.broker_addr().unwrap(), "127.0.0.1");
245        }
246    }
247
248    #[test]
249    fn client_broker_err_with_response_code_formats_correctly() {
250        let result: std::result::Result<(), client_error::MQClientError> =
251            Err(client_broker_err!(404, "Error: not found"));
252        assert!(result.is_err());
253        if let Err(MQClientError::MQClientBrokerError(err)) = result {
254            assert_eq!(err.response_code(), 404);
255            assert_eq!(err.error_message().unwrap(), "Error: not found");
256            assert!(err.broker_addr().is_none());
257        }
258    }
259
260    #[test]
261    fn request_timeout_err_with_response_code_formats_correctly() {
262        let result: std::result::Result<(), client_error::MQClientError> =
263            request_timeout_err!(408, "Request timed out");
264        assert!(result.is_err());
265        if let Err(MQClientError::RequestTimeoutError(err)) = result {
266            assert_eq!(err.response_code(), 408);
267            assert_eq!(err.error_message().unwrap(), "Request timed out");
268        }
269    }
270
271    #[test]
272    fn request_timeout_err_without_response_code_formats_correctly() {
273        let result: Result<(), client_error::MQClientError> = request_timeout_err!("Timeout error");
274        assert!(result.is_err());
275        if let Err(MQClientError::RequestTimeoutError(err)) = result {
276            assert_eq!(err.response_code(), -1);
277            assert_eq!(err.error_message().unwrap(), "Timeout error");
278        }
279    }
280
281    #[test]
282    fn request_timeout_err_with_multiple_arguments_formats_correctly() {
283        let result: Result<(), client_error::MQClientError> =
284            request_timeout_err!(504, "Error: {} - {}", "Gateway", "Timeout");
285        assert!(result.is_err());
286        if let Err(MQClientError::RequestTimeoutError(err)) = result {
287            assert_eq!(err.response_code(), 504);
288            assert_eq!(err.error_message().unwrap(), "Error: Gateway - Timeout");
289        }
290    }
291
292    #[test]
293    fn mq_client_err_with_response_code_formats_correctly() {
294        let result: std::result::Result<(), client_error::MQClientError> =
295            Err(mq_client_err!(404, "Error: {}", "not found"));
296        assert!(result.is_err());
297        if let Err(MQClientError::MQClientErr(err)) = result {
298            assert_eq!(err.response_code(), 404);
299            assert_eq!(err.error_message().unwrap(), "Error: not found");
300        }
301    }
302
303    #[test]
304    fn mq_client_err_without_response_code_formats_correctly() {
305        let result: Result<(), client_error::MQClientError> = Err(mq_client_err!("simple error"));
306        assert!(result.is_err());
307        if let Err(MQClientError::MQClientErr(err)) = result {
308            assert_eq!(err.response_code(), -1);
309            assert_eq!(err.error_message().unwrap(), "simple error");
310        }
311    }
312
313    #[test]
314    fn mq_client_err_with_multiple_arguments_formats_correctly() {
315        let result: Result<(), client_error::MQClientError> =
316            Err(mq_client_err!(500, "Error: {} - {}", "internal", "server error"));
317        assert!(result.is_err());
318        if let Err(MQClientError::MQClientErr(err)) = result {
319            assert_eq!(err.response_code(), 500);
320            assert_eq!(
321                err.error_message().unwrap(),
322                "Error: internal - server error"
323            );
324        }
325    }
326
327    #[test]
328    fn mq_broker_err_new_initializes_correctly() {
329        let error = MQBrokerErr::new(404, "not found");
330        assert_eq!(error.response_code(), 404);
331        assert_eq!(error.error_message().unwrap(), "not found");
332        assert!(error.broker_addr().is_none());
333    }
334
335    #[test]
336    fn mq_broker_err_new_with_broker_initializes_correctly() {
337        let error = MQBrokerErr::new_with_broker(404, "not found", "127.0.0.1");
338        assert_eq!(error.response_code(), 404);
339        assert_eq!(error.error_message().unwrap(), "not found");
340        assert_eq!(error.broker_addr().unwrap(), "127.0.0.1");
341    }
342
343    #[test]
344    fn client_err_new_initializes_correctly() {
345        let error = ClientErr::new("client error");
346        assert_eq!(error.response_code(), -1);
347        assert_eq!(error.error_message().unwrap(), "client error");
348    }
349
350    #[test]
351    fn client_err_new_with_code_initializes_correctly() {
352        let error = ClientErr::new_with_code(500, "internal error");
353        assert_eq!(error.response_code(), 500);
354        assert_eq!(error.error_message().unwrap(), "internal error");
355    }
356
357    #[test]
358    fn request_timeout_err_new_initializes_correctly() {
359        let error = RequestTimeoutErr::new("timeout error");
360        assert_eq!(error.response_code(), -1);
361        assert_eq!(error.error_message().unwrap(), "timeout error");
362    }
363
364    #[test]
365    fn request_timeout_err_new_with_code_initializes_correctly() {
366        let error = RequestTimeoutErr::new_with_code(408, "request timeout");
367        assert_eq!(error.response_code(), 408);
368        assert_eq!(error.error_message().unwrap(), "request timeout");
369    }
370}
371*/