Skip to main content

rocketmq_client_rust/
client_error.rs

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