huawei_dongle_api/models/
common.rs1use super::enums::ApiErrorCode;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ApiResponse<T> {
9 #[serde(flatten)]
10 pub data: T,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ErrorResponse {
16 pub code: Option<i32>,
17 pub message: Option<String>,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22#[serde(rename = "error")]
23pub struct ApiError {
24 pub code: ApiErrorCode,
26 #[serde(default)]
28 pub message: Option<String>,
29}
30
31impl ApiError {
32 pub fn error_code(&self) -> &ApiErrorCode {
34 &self.code
35 }
36
37 pub fn is_csrf_error(&self) -> bool {
39 self.code.is_csrf_error()
40 }
41
42 pub fn is_session_error(&self) -> bool {
44 self.code.is_session_error()
45 }
46
47 pub fn is_auth_error(&self) -> bool {
49 self.code.is_auth_error()
50 }
51
52 pub fn error_message(&self) -> String {
54 if let Some(msg) = &self.message {
55 if !msg.is_empty() {
56 return msg.clone();
57 }
58 }
59 self.code.to_string()
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename = "response")]
66pub struct Response {
67 #[serde(rename = "OK", default)]
68 pub ok: Option<String>,
69 #[serde(rename = "ErrorCode", default)]
70 pub error_code: Option<String>,
71 #[serde(rename = "ErrorMessage", default)]
72 pub error_message: Option<String>,
73}
74
75impl Response {
76 pub fn is_success(&self) -> bool {
78 self.ok.is_some() || self.error_code.as_deref() == Some("0") || self.error_code.is_none()
79 }
80
81 pub fn error_code(&self) -> Option<i32> {
83 self.error_code.as_ref().and_then(|code| code.parse().ok())
84 }
85
86 pub fn error_message(&self) -> Option<&str> {
88 self.error_message.as_deref()
89 }
90}
91
92pub fn check_for_api_error(xml_text: &str) -> Option<ApiError> {
94 if xml_text.contains("<error>") && xml_text.contains("<code>") {
95 if let Ok(error) = serde_xml_rs::from_str::<ApiError>(xml_text) {
96 return Some(error);
97 }
98 }
99 None
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_api_error_parsing() {
108 let error_xml = r#"<?xml version="1.0" encoding="UTF-8"?>
109<error>
110 <code>125002</code>
111 <message></message>
112</error>"#;
113
114 let error: ApiError = serde_xml_rs::from_str(error_xml).unwrap();
115 assert_eq!(error.code, ApiErrorCode::CsrfTokenInvalid);
116 assert!(error.is_csrf_error());
117 assert!(!error.is_session_error());
118 assert_eq!(error.error_message(), "CSRF token invalid");
119 }
120
121 #[test]
122 fn test_check_for_api_error() {
123 let error_xml = r#"<error><code>125003</code><message/></error>"#;
124 let error = check_for_api_error(error_xml).unwrap();
125
126 assert_eq!(error.code, ApiErrorCode::WrongSessionToken);
127 assert!(error.is_session_error());
128 assert_eq!(error.error_message(), "Wrong session token");
129
130 let success_xml = r#"<response>OK</response>"#;
131 assert!(check_for_api_error(success_xml).is_none());
132 }
133
134 #[test]
135 fn test_error_code_classification() {
136 let mut error = ApiError {
137 code: ApiErrorCode::UsernameOrPasswordWrong,
138 message: None,
139 };
140 assert!(error.is_auth_error());
141 assert!(!error.is_csrf_error());
142 assert!(!error.is_session_error());
143
144 error.code = ApiErrorCode::WrongToken;
145 assert!(error.is_csrf_error());
146 assert!(!error.is_auth_error());
147 }
148}