rusty_common/
error_utils.rs1use crate::{SmartString, error::CommonError};
7use anyhow::Result as AnyhowResult;
8
9pub trait AnyhowErrorExt<T> {
11 fn websocket_connection_error(self, exchange: &str) -> Result<T, CommonError>;
13
14 fn json_parse_error(self, context: &str) -> Result<T, CommonError>;
16
17 fn api_error(self, endpoint: &str) -> Result<T, CommonError>;
19}
20
21impl<T> AnyhowErrorExt<T> for AnyhowResult<T> {
22 #[inline]
23 fn websocket_connection_error(self, exchange: &str) -> Result<T, CommonError> {
24 self.map_err(|e| {
25 CommonError::Websocket(format!("Failed to connect to {exchange} WebSocket: {e}").into())
26 })
27 }
28
29 #[inline]
30 fn json_parse_error(self, context: &str) -> Result<T, CommonError> {
31 self.map_err(|e| CommonError::Json(format!("Failed to parse {context}: {e}").into()))
32 }
33
34 #[inline]
35 fn api_error(self, endpoint: &str) -> Result<T, CommonError> {
36 self.map_err(|e| CommonError::Api(format!("API error at {endpoint}: {e}").into()))
37 }
38}
39
40pub struct ErrorMessages;
42
43impl ErrorMessages {
44 #[inline]
46 pub fn websocket_connect(exchange: &str) -> SmartString {
47 format!("Failed to connect to {exchange} WebSocket").into()
48 }
49
50 #[inline]
52 pub fn websocket_timeout(exchange: &str) -> SmartString {
53 format!("{exchange} WebSocket message timeout").into()
54 }
55
56 #[inline]
58 pub fn json_parse(message_type: &str) -> SmartString {
59 format!("Failed to parse {message_type} message").into()
60 }
61
62 #[inline]
64 pub fn auth_required(endpoint: &str) -> SmartString {
65 format!("Authentication required for {endpoint}").into()
66 }
67
68 #[inline]
70 pub fn api_response(status: u16, endpoint: &str) -> SmartString {
71 format!("API error {status}: {endpoint}").into()
72 }
73}
74
75#[macro_export]
77macro_rules! log_websocket_error {
78 ($exchange:expr, $error:expr) => {
79 log::error!("Failed to connect to {} WebSocket: {}", $exchange, $error);
80 };
81}
82
83#[macro_export]
85macro_rules! log_parse_error {
86 ($message_type:expr, $error:expr) => {
87 log::error!("Failed to parse {} message: {}", $message_type, $error);
88 };
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use anyhow::anyhow;
95
96 #[test]
97 fn test_websocket_connection_error() {
98 let result: AnyhowResult<()> = Err(anyhow!("Connection refused"));
99 let error = result.websocket_connection_error("Binance").unwrap_err();
100
101 match error {
102 CommonError::Websocket(msg) => {
103 assert!(msg.contains("Failed to connect to Binance WebSocket"));
104 assert!(msg.contains("Connection refused"));
105 }
106 _ => panic!("Expected WebSocket error"),
107 }
108 }
109
110 #[test]
111 fn test_json_parse_error() {
112 let result: AnyhowResult<()> = Err(anyhow!("Invalid JSON"));
113 let error = result.json_parse_error("trade").unwrap_err();
114
115 match error {
116 CommonError::Json(msg) => {
117 assert!(msg.contains("Failed to parse trade"));
118 assert!(msg.contains("Invalid JSON"));
119 }
120 _ => panic!("Expected JSON error"),
121 }
122 }
123
124 #[test]
125 fn test_error_messages() {
126 let msg = ErrorMessages::websocket_connect("Upbit");
127 assert_eq!(msg.as_str(), "Failed to connect to Upbit WebSocket");
128
129 let msg = ErrorMessages::json_parse("orderbook");
130 assert_eq!(msg.as_str(), "Failed to parse orderbook message");
131
132 let msg = ErrorMessages::auth_required("private endpoint");
133 assert_eq!(msg.as_str(), "Authentication required for private endpoint");
134 }
135}