deribit_fix/message/
mod.rs1use crate::{
4 error::{DeribitFixError, Result},
5 types::MsgType,
6};
7use chrono::{DateTime, Utc};
8use std::collections::HashMap;
9use tracing::{debug, warn};
10
11#[derive(Debug, Clone)]
13pub struct FixMessage {
14 pub fields: HashMap<u32, String>,
15 pub raw_message: String,
16}
17
18impl FixMessage {
19 pub fn new() -> Self {
21 Self {
22 fields: HashMap::new(),
23 raw_message: String::new(),
24 }
25 }
26
27 pub fn parse(raw_message: &str) -> Result<Self> {
29 let mut fields = HashMap::new();
30
31 let parts: Vec<&str> = raw_message.split('\x01').collect();
33
34 for part in parts {
35 if part.is_empty() {
36 continue;
37 }
38
39 if let Some(eq_pos) = part.find('=') {
40 let tag_str = &part[..eq_pos];
41 let value = &part[eq_pos + 1..];
42
43 if let Ok(tag) = tag_str.parse::<u32>() {
44 fields.insert(tag, value.to_string());
45 } else {
46 warn!("Invalid FIX tag: {}", tag_str);
47 }
48 }
49 }
50
51 if !fields.contains_key(&8) { return Err(DeribitFixError::MessageParsing("Missing BeginString (8)".to_string()));
54 }
55
56 if !fields.contains_key(&35) { return Err(DeribitFixError::MessageParsing("Missing MsgType (35)".to_string()));
58 }
59
60 Ok(Self {
61 fields,
62 raw_message: raw_message.to_string(),
63 })
64 }
65
66 pub fn get_field(&self, tag: u32) -> Option<&String> {
68 self.fields.get(&tag)
69 }
70
71 pub fn set_field(&mut self, tag: u32, value: String) {
73 self.fields.insert(tag, value);
74 }
75
76 pub fn msg_type(&self) -> Option<MsgType> {
78 self.get_field(35)
79 .and_then(|s| MsgType::from_str(s))
80 }
81
82 pub fn sender_comp_id(&self) -> Option<&String> {
84 self.get_field(49)
85 }
86
87 pub fn target_comp_id(&self) -> Option<&String> {
89 self.get_field(56)
90 }
91
92 pub fn msg_seq_num(&self) -> Option<u32> {
94 self.get_field(34)
95 .and_then(|s| s.parse().ok())
96 }
97
98 pub fn to_string(&self) -> String {
100 let mut message = String::new();
101
102 let ordered_tags = [8, 9, 35]; for &tag in &ordered_tags {
107 if let Some(value) = self.fields.get(&tag) {
108 message.push_str(&format!("{}={}\x01", tag, value));
109 }
110 }
111
112 for (&tag, value) in &self.fields {
114 if !ordered_tags.contains(&tag) && tag != 10 { message.push_str(&format!("{}={}\x01", tag, value));
116 }
117 }
118
119 let checksum = self.calculate_checksum(&message);
121 message.push_str(&format!("10={:03}\x01", checksum));
122
123 message
124 }
125
126 fn calculate_checksum(&self, message: &str) -> u8 {
128 let sum: u32 = message.bytes().map(|b| b as u32).sum();
129 (sum % 256) as u8
130 }
131
132 pub fn validate(&self) -> Result<()> {
134 if !self.fields.contains_key(&8) {
136 return Err(DeribitFixError::MessageParsing("Missing BeginString".to_string()));
137 }
138
139 if !self.fields.contains_key(&35) {
140 return Err(DeribitFixError::MessageParsing("Missing MsgType".to_string()));
141 }
142
143 if !self.fields.contains_key(&49) {
144 return Err(DeribitFixError::MessageParsing("Missing SenderCompID".to_string()));
145 }
146
147 if !self.fields.contains_key(&56) {
148 return Err(DeribitFixError::MessageParsing("Missing TargetCompID".to_string()));
149 }
150
151 if !self.fields.contains_key(&34) {
152 return Err(DeribitFixError::MessageParsing("Missing MsgSeqNum".to_string()));
153 }
154
155 Ok(())
156 }
157}
158
159impl Default for FixMessage {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl std::fmt::Display for FixMessage {
166 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167 write!(f, "{}", self.to_string())
168 }
169}
170
171pub struct MessageBuilder {
173 message: FixMessage,
174}
175
176impl MessageBuilder {
177 pub fn new() -> Self {
179 let mut message = FixMessage::new();
180
181 message.set_field(8, "FIX.4.4".to_string()); Self { message }
185 }
186
187 pub fn msg_type(mut self, msg_type: MsgType) -> Self {
189 self.message.set_field(35, msg_type.as_str().to_string());
190 self
191 }
192
193 pub fn sender_comp_id(mut self, sender_comp_id: String) -> Self {
195 self.message.set_field(49, sender_comp_id);
196 self
197 }
198
199 pub fn target_comp_id(mut self, target_comp_id: String) -> Self {
201 self.message.set_field(56, target_comp_id);
202 self
203 }
204
205 pub fn msg_seq_num(mut self, seq_num: u32) -> Self {
207 self.message.set_field(34, seq_num.to_string());
208 self
209 }
210
211 pub fn sending_time(mut self, time: DateTime<Utc>) -> Self {
213 let time_str = time.format("%Y%m%d-%H:%M:%S%.3f").to_string();
214 self.message.set_field(52, time_str);
215 self
216 }
217
218 pub fn field(mut self, tag: u32, value: String) -> Self {
220 self.message.set_field(tag, value);
221 self
222 }
223
224 pub fn build(mut self) -> Result<FixMessage> {
226 let temp_message = self.message.to_string();
228 let body_start = temp_message.find("35=").unwrap_or(0);
229 let body_end = temp_message.rfind("10=").unwrap_or(temp_message.len());
230 let body_length = body_end - body_start;
231
232 self.message.set_field(9, body_length.to_string());
233
234 self.message.validate()?;
236
237 Ok(self.message)
238 }
239}
240
241impl Default for MessageBuilder {
242 fn default() -> Self {
243 Self::new()
244 }
245}