deribit_fix/message/user/
user_response.rs1use crate::error::Result as DeribitFixResult;
10use crate::message::builder::MessageBuilder;
11use crate::model::types::MsgType;
12use base64::{Engine as _, engine::general_purpose};
13use chrono::Utc;
14use deribit_base::{impl_json_debug_pretty, impl_json_display};
15use serde::{Deserialize, Serialize};
16
17pub use super::user_request::UserStatus;
19
20#[derive(Clone, PartialEq, Serialize, Deserialize)]
22pub struct UserResponse {
23 pub user_request_id: String,
25 pub username: String,
27 pub user_status: UserStatus,
29 pub user_status_text: Option<String>,
31 pub raw_data_length: Option<i32>,
33 pub raw_data: Option<Vec<u8>>,
35 pub deribit_label: Option<String>,
37}
38
39impl UserResponse {
40 pub fn new(user_request_id: String, username: String, user_status: UserStatus) -> Self {
42 Self {
43 user_request_id,
44 username,
45 user_status,
46 user_status_text: None,
47 raw_data_length: None,
48 raw_data: None,
49 deribit_label: None,
50 }
51 }
52
53 pub fn logged_in(user_request_id: String, username: String) -> Self {
55 let mut response = Self::new(user_request_id, username, UserStatus::LoggedIn);
56 response.user_status_text = Some("User logged in successfully".to_string());
57 response
58 }
59
60 pub fn logged_out(user_request_id: String, username: String) -> Self {
62 let mut response = Self::new(user_request_id, username, UserStatus::NotLoggedIn);
63 response.user_status_text = Some("User logged out successfully".to_string());
64 response
65 }
66
67 pub fn password_changed(user_request_id: String, username: String) -> Self {
69 let mut response = Self::new(user_request_id, username, UserStatus::PasswordChanged);
70 response.user_status_text = Some("Password changed successfully".to_string());
71 response
72 }
73
74 pub fn user_not_recognised(user_request_id: String, username: String) -> Self {
76 let mut response = Self::new(user_request_id, username, UserStatus::UserNotRecognised);
77 response.user_status_text = Some("User not recognised".to_string());
78 response
79 }
80
81 pub fn password_incorrect(user_request_id: String, username: String) -> Self {
83 let mut response = Self::new(user_request_id, username, UserStatus::PasswordIncorrect);
84 response.user_status_text = Some("Password incorrect".to_string());
85 response
86 }
87
88 pub fn error(user_request_id: String, username: String, error_text: String) -> Self {
90 let mut response = Self::new(user_request_id, username, UserStatus::Other);
91 response.user_status_text = Some(error_text);
92 response
93 }
94
95 pub fn with_user_status_text(mut self, user_status_text: String) -> Self {
97 self.user_status_text = Some(user_status_text);
98 self
99 }
100
101 pub fn with_raw_data(mut self, raw_data: Vec<u8>) -> Self {
103 self.raw_data_length = Some(raw_data.len() as i32);
104 self.raw_data = Some(raw_data);
105 self
106 }
107
108 pub fn with_label(mut self, label: String) -> Self {
110 self.deribit_label = Some(label);
111 self
112 }
113
114 pub fn to_fix_message(
116 &self,
117 sender_comp_id: &str,
118 target_comp_id: &str,
119 msg_seq_num: u32,
120 ) -> DeribitFixResult<String> {
121 let mut builder = MessageBuilder::new()
122 .msg_type(MsgType::UserResponse)
123 .sender_comp_id(sender_comp_id.to_string())
124 .target_comp_id(target_comp_id.to_string())
125 .msg_seq_num(msg_seq_num)
126 .sending_time(Utc::now());
127
128 builder = builder
130 .field(923, self.user_request_id.clone()) .field(553, self.username.clone()) .field(926, i32::from(self.user_status).to_string()); if let Some(user_status_text) = &self.user_status_text {
136 builder = builder.field(927, user_status_text.clone());
137 }
138
139 if let Some(raw_data_length) = &self.raw_data_length {
140 builder = builder.field(95, raw_data_length.to_string());
141 }
142
143 if let Some(raw_data) = &self.raw_data {
144 let encoded_data = general_purpose::STANDARD.encode(raw_data);
146 builder = builder.field(96, encoded_data);
147 }
148
149 if let Some(deribit_label) = &self.deribit_label {
150 builder = builder.field(100010, deribit_label.clone());
151 }
152
153 Ok(builder.build()?.to_string())
154 }
155}
156
157impl_json_display!(UserResponse);
158impl_json_debug_pretty!(UserResponse);
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_user_response_creation() {
166 let response = UserResponse::new(
167 "UR123".to_string(),
168 "testuser".to_string(),
169 UserStatus::LoggedIn,
170 );
171
172 assert_eq!(response.user_request_id, "UR123");
173 assert_eq!(response.username, "testuser");
174 assert_eq!(response.user_status, UserStatus::LoggedIn);
175 assert!(response.user_status_text.is_none());
176 assert!(response.raw_data.is_none());
177 }
178
179 #[test]
180 fn test_user_response_logged_in() {
181 let response = UserResponse::logged_in("UR456".to_string(), "user1".to_string());
182
183 assert_eq!(response.user_status, UserStatus::LoggedIn);
184 assert_eq!(response.username, "user1");
185 assert_eq!(
186 response.user_status_text,
187 Some("User logged in successfully".to_string())
188 );
189 }
190
191 #[test]
192 fn test_user_response_logged_out() {
193 let response = UserResponse::logged_out("UR789".to_string(), "user2".to_string());
194
195 assert_eq!(response.user_status, UserStatus::NotLoggedIn);
196 assert_eq!(response.username, "user2");
197 assert_eq!(
198 response.user_status_text,
199 Some("User logged out successfully".to_string())
200 );
201 }
202
203 #[test]
204 fn test_user_response_password_changed() {
205 let response = UserResponse::password_changed("UR999".to_string(), "user3".to_string());
206
207 assert_eq!(response.user_status, UserStatus::PasswordChanged);
208 assert_eq!(response.username, "user3");
209 assert_eq!(
210 response.user_status_text,
211 Some("Password changed successfully".to_string())
212 );
213 }
214
215 #[test]
216 fn test_user_response_user_not_recognised() {
217 let response =
218 UserResponse::user_not_recognised("UR111".to_string(), "unknown_user".to_string());
219
220 assert_eq!(response.user_status, UserStatus::UserNotRecognised);
221 assert_eq!(response.username, "unknown_user");
222 assert_eq!(
223 response.user_status_text,
224 Some("User not recognised".to_string())
225 );
226 }
227
228 #[test]
229 fn test_user_response_password_incorrect() {
230 let response = UserResponse::password_incorrect("UR222".to_string(), "user4".to_string());
231
232 assert_eq!(response.user_status, UserStatus::PasswordIncorrect);
233 assert_eq!(response.username, "user4");
234 assert_eq!(
235 response.user_status_text,
236 Some("Password incorrect".to_string())
237 );
238 }
239
240 #[test]
241 fn test_user_response_error() {
242 let response = UserResponse::error(
243 "UR333".to_string(),
244 "user5".to_string(),
245 "System temporarily unavailable".to_string(),
246 );
247
248 assert_eq!(response.user_status, UserStatus::Other);
249 assert_eq!(response.username, "user5");
250 assert_eq!(
251 response.user_status_text,
252 Some("System temporarily unavailable".to_string())
253 );
254 }
255
256 #[test]
257 fn test_user_response_with_options() {
258 let raw_data = vec![10, 20, 30, 40];
259 let response = UserResponse::new(
260 "UR444".to_string(),
261 "user6".to_string(),
262 UserStatus::LoggedIn,
263 )
264 .with_user_status_text("Custom login message".to_string())
265 .with_raw_data(raw_data.clone())
266 .with_label("test-user-response".to_string());
267
268 assert_eq!(
269 response.user_status_text,
270 Some("Custom login message".to_string())
271 );
272 assert_eq!(response.raw_data, Some(raw_data));
273 assert_eq!(response.raw_data_length, Some(4));
274 assert_eq!(
275 response.deribit_label,
276 Some("test-user-response".to_string())
277 );
278 }
279
280 #[test]
281 fn test_user_response_to_fix_message() {
282 let response = UserResponse::logged_in("UR123".to_string(), "testuser".to_string())
283 .with_label("test-label".to_string());
284
285 let fix_message = response.to_fix_message("SENDER", "TARGET", 1).unwrap();
286
287 assert!(fix_message.contains("35=BF")); assert!(fix_message.contains("923=UR123")); assert!(fix_message.contains("553=testuser")); assert!(fix_message.contains("926=1")); assert!(fix_message.contains("927=User logged in successfully")); assert!(fix_message.contains("100010=test-label")); }
295
296 #[test]
297 fn test_user_response_minimal_fix_message() {
298 let response = UserResponse::new(
299 "UR456".to_string(),
300 "user".to_string(),
301 UserStatus::NotLoggedIn,
302 );
303
304 let fix_message = response.to_fix_message("SENDER", "TARGET", 2).unwrap();
305
306 assert!(fix_message.contains("35=BF")); assert!(fix_message.contains("923=UR456")); assert!(fix_message.contains("553=user")); assert!(fix_message.contains("926=2")); assert!(!fix_message.contains("\x01927=")); assert!(!fix_message.contains("\x0195=")); assert!(!fix_message.contains("\x0196=")); }
318
319 #[test]
320 fn test_user_response_with_raw_data() {
321 let raw_data = vec![0xFF, 0xFE, 0xFD];
322 let response = UserResponse::new(
323 "UR789".to_string(),
324 "datauser".to_string(),
325 UserStatus::LoggedIn,
326 )
327 .with_raw_data(raw_data.clone());
328
329 let fix_message = response.to_fix_message("SENDER", "TARGET", 3).unwrap();
330
331 assert!(fix_message.contains("95=3")); assert!(fix_message.contains("96=")); }
335}