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#[macro_export]
108macro_rules! client_broker_err {
109    // Handle errors with a custom ResponseCode and formatted string
110    ($response_code:expr, $error_message:expr, $broker_addr:expr) => {{
111        std::result::Result::Err($crate::client_error::MQClientError::MQClientBrokerError(
112            $crate::client_error::MQBrokerErr::new_with_broker(
113                $response_code as i32,
114                $error_message,
115                $broker_addr,
116            ),
117        ))
118    }};
119    // Handle errors without a ResponseCode, using only the error message
120    ($response_code:expr, $error_message:expr) => {{
121        std::result::Result::Err($crate::client_error::MQClientError::MQClientBrokerError(
122            $crate::client_error::MQBrokerErr::new($response_code as i32, $error_message),
123        ))
124    }};
125}
126
127#[derive(Error, Debug)]
128#[error("{message}")]
129pub struct ClientErr {
130    response_code: i32,
131    error_message: Option<CheetahString>,
132    message: CheetahString,
133}
134
135impl ClientErr {
136    pub fn new(error_message: impl Into<CheetahString>) -> Self {
137        let error_message = error_message.into();
138        let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
139        Self {
140            response_code: -1,
141            error_message: Some(error_message),
142            message: CheetahString::from(message),
143        }
144    }
145
146    pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
147        let error_message = error_message.into();
148        let message = FAQUrl::attach_default_url(Some(
149            format!("CODE: {}  DESC: {}", response_code, error_message,).as_str(),
150        ));
151        Self {
152            response_code,
153            error_message: Some(error_message),
154            message: CheetahString::from(message),
155        }
156    }
157
158    pub fn response_code(&self) -> i32 {
159        self.response_code
160    }
161
162    pub fn error_message(&self) -> Option<&CheetahString> {
163        self.error_message.as_ref()
164    }
165}
166
167// Create a macro to simplify error creation
168#[macro_export]
169macro_rules! mq_client_err {
170    // Handle errors with a custom ResponseCode and formatted string
171    ($response_code:expr, $fmt:expr, $($arg:expr),*) => {{
172        let formatted_msg = format!($fmt, $($arg),*);
173        std::result::Result::Err($crate::client_error::MQClientError::MQClientErr(
174            $crate::client_error::ClientErr::new_with_code($response_code as i32, formatted_msg),
175        ))
176    }};
177
178    ($response_code:expr, $error_message:expr) => {{
179        std::result::Result::Err($crate::client_error::MQClientError::MQClientErr(
180            $crate::client_error::ClientErr::new_with_code(
181                $response_code as i32,
182                $error_message,
183            ),
184        ))
185    }};
186
187    // Handle errors without a ResponseCode, using only the error message
188    ($error_message:expr) => {{
189        std::result::Result::Err($crate::client_error::MQClientError::MQClientErr(
190            $crate::client_error::ClientErr::new($error_message),
191        ))
192    }};
193}
194
195#[derive(Error, Debug)]
196#[error("{message}")]
197pub struct RequestTimeoutErr {
198    response_code: i32,
199    error_message: Option<CheetahString>,
200    message: CheetahString,
201}
202
203impl RequestTimeoutErr {
204    pub fn new(error_message: impl Into<CheetahString>) -> Self {
205        let error_message = error_message.into();
206        let message = FAQUrl::attach_default_url(Some(error_message.as_str()));
207        Self {
208            response_code: -1,
209            error_message: Some(error_message),
210            message: CheetahString::from(message),
211        }
212    }
213
214    pub fn new_with_code(response_code: i32, error_message: impl Into<CheetahString>) -> Self {
215        let error_message = error_message.into();
216        let message = FAQUrl::attach_default_url(Some(
217            format!("CODE: {}  DESC: {}", response_code, error_message,).as_str(),
218        ));
219        Self {
220            response_code,
221            error_message: Some(error_message),
222            message: CheetahString::from(message),
223        }
224    }
225
226    pub fn response_code(&self) -> i32 {
227        self.response_code
228    }
229
230    pub fn error_message(&self) -> Option<&CheetahString> {
231        self.error_message.as_ref()
232    }
233}
234
235#[macro_export]
236macro_rules! request_timeout_err {
237    // Handle errors with a custom ResponseCode and formatted string
238    ($response_code:expr, $fmt:expr, $($arg:expr),*) => {{
239        let formatted_msg = format!($fmt, $($arg),*);
240        std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
241            $crate::client_error::RequestTimeoutErr::new_with_code(
242                $response_code as i32,
243                formatted_msg,
244            ),
245        ))
246    }};
247    ($response_code:expr, $error_message:expr) => {{
248        std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
249            $crate::client_error::RequestTimeoutErr::new_with_code(
250                $response_code as i32,
251                $error_message,
252            ),
253        ))
254    }};
255    // Handle errors without a ResponseCode, using only the error message
256    ($error_message:expr) => {{
257        std::result::Result::Err($crate::client_error::MQClientError::RequestTimeoutError(
258            $crate::client_error::RequestTimeoutErr::new($error_message),
259        ))
260    }};
261}
262
263#[cfg(test)]
264mod tests {
265    use super::*;
266    use crate::client_error;
267
268    #[test]
269    fn client_err_with_response_code_formats_correctly() {
270        let result: std::result::Result<(), client_error::MQClientError> =
271            mq_client_err!(404, "Error: not found");
272        assert!(result.is_err());
273        if let Err(MQClientError::MQClientErr(err)) = result {
274            assert_eq!(err.response_code(), 404);
275            assert_eq!(err.error_message().unwrap(), "Error: not found");
276        } else {
277            panic!("Expected MQClientError::MQClientErr");
278        }
279    }
280
281    #[test]
282    fn client_broker_err_with_response_code_and_broker_formats_correctly() {
283        let result: std::result::Result<(), client_error::MQClientError> =
284            client_broker_err!(404, "Error: {}", "127.0.0.1");
285        assert!(result.is_err());
286        if let Err(MQClientError::MQClientBrokerError(err)) = result {
287            assert_eq!(err.response_code(), 404);
288            assert_eq!(err.error_message().unwrap(), "Error: {}");
289            assert_eq!(err.broker_addr().unwrap(), "127.0.0.1");
290        }
291    }
292
293    #[test]
294    fn client_broker_err_with_response_code_formats_correctly() {
295        let result: std::result::Result<(), client_error::MQClientError> =
296            client_broker_err!(404, "Error: not found");
297        assert!(result.is_err());
298        if let Err(MQClientError::MQClientBrokerError(err)) = result {
299            assert_eq!(err.response_code(), 404);
300            assert_eq!(err.error_message().unwrap(), "Error: not found");
301            assert!(err.broker_addr().is_none());
302        }
303    }
304
305    #[test]
306    fn request_timeout_err_with_response_code_formats_correctly() {
307        let result: std::result::Result<(), client_error::MQClientError> =
308            request_timeout_err!(408, "Request timed out");
309        assert!(result.is_err());
310        if let Err(MQClientError::RequestTimeoutError(err)) = result {
311            assert_eq!(err.response_code(), 408);
312            assert_eq!(err.error_message().unwrap(), "Request timed out");
313        }
314    }
315
316    #[test]
317    fn request_timeout_err_without_response_code_formats_correctly() {
318        let result: Result<(), client_error::MQClientError> = request_timeout_err!("Timeout error");
319        assert!(result.is_err());
320        if let Err(MQClientError::RequestTimeoutError(err)) = result {
321            assert_eq!(err.response_code(), -1);
322            assert_eq!(err.error_message().unwrap(), "Timeout error");
323        }
324    }
325
326    #[test]
327    fn request_timeout_err_with_multiple_arguments_formats_correctly() {
328        let result: Result<(), client_error::MQClientError> =
329            request_timeout_err!(504, "Error: {} - {}", "Gateway", "Timeout");
330        assert!(result.is_err());
331        if let Err(MQClientError::RequestTimeoutError(err)) = result {
332            assert_eq!(err.response_code(), 504);
333            assert_eq!(err.error_message().unwrap(), "Error: Gateway - Timeout");
334        }
335    }
336
337    #[test]
338    fn mq_client_err_with_response_code_formats_correctly() {
339        let result: std::result::Result<(), client_error::MQClientError> =
340            mq_client_err!(404, "Error: {}", "not found");
341        assert!(result.is_err());
342        if let Err(MQClientError::MQClientErr(err)) = result {
343            assert_eq!(err.response_code(), 404);
344            assert_eq!(err.error_message().unwrap(), "Error: not found");
345        }
346    }
347
348    #[test]
349    fn mq_client_err_without_response_code_formats_correctly() {
350        let result: Result<(), client_error::MQClientError> = mq_client_err!("simple error");
351        assert!(result.is_err());
352        if let Err(MQClientError::MQClientErr(err)) = result {
353            assert_eq!(err.response_code(), -1);
354            assert_eq!(err.error_message().unwrap(), "simple error");
355        }
356    }
357
358    #[test]
359    fn mq_client_err_with_multiple_arguments_formats_correctly() {
360        let result: Result<(), client_error::MQClientError> =
361            mq_client_err!(500, "Error: {} - {}", "internal", "server error");
362        assert!(result.is_err());
363        if let Err(MQClientError::MQClientErr(err)) = result {
364            assert_eq!(err.response_code(), 500);
365            assert_eq!(
366                err.error_message().unwrap(),
367                "Error: internal - server error"
368            );
369        }
370    }
371
372    #[test]
373    fn mq_broker_err_new_initializes_correctly() {
374        let error = MQBrokerErr::new(404, "not found");
375        assert_eq!(error.response_code(), 404);
376        assert_eq!(error.error_message().unwrap(), "not found");
377        assert!(error.broker_addr().is_none());
378    }
379
380    #[test]
381    fn mq_broker_err_new_with_broker_initializes_correctly() {
382        let error = MQBrokerErr::new_with_broker(404, "not found", "127.0.0.1");
383        assert_eq!(error.response_code(), 404);
384        assert_eq!(error.error_message().unwrap(), "not found");
385        assert_eq!(error.broker_addr().unwrap(), "127.0.0.1");
386    }
387
388    #[test]
389    fn client_err_new_initializes_correctly() {
390        let error = ClientErr::new("client error");
391        assert_eq!(error.response_code(), -1);
392        assert_eq!(error.error_message().unwrap(), "client error");
393    }
394
395    #[test]
396    fn client_err_new_with_code_initializes_correctly() {
397        let error = ClientErr::new_with_code(500, "internal error");
398        assert_eq!(error.response_code(), 500);
399        assert_eq!(error.error_message().unwrap(), "internal error");
400    }
401
402    #[test]
403    fn request_timeout_err_new_initializes_correctly() {
404        let error = RequestTimeoutErr::new("timeout error");
405        assert_eq!(error.response_code(), -1);
406        assert_eq!(error.error_message().unwrap(), "timeout error");
407    }
408
409    #[test]
410    fn request_timeout_err_new_with_code_initializes_correctly() {
411        let error = RequestTimeoutErr::new_with_code(408, "request timeout");
412        assert_eq!(error.response_code(), 408);
413        assert_eq!(error.error_message().unwrap(), "request timeout");
414    }
415}
416*/