use crate::DeribitFixError;
use crate::model::types::MsgType;
use std::str::FromStr;
#[derive(Clone)]
pub struct FixMessage {
pub fields: Vec<(u32, String)>,
pub raw_message: String,
}
impl FixMessage {
pub fn new() -> Self {
Self {
fields: Vec::new(),
raw_message: String::new(),
}
}
pub fn parse(raw_message: &str) -> crate::Result<Self> {
let mut fields = Vec::new();
for part in raw_message.split('\x01').filter(|s| !s.is_empty()) {
let mut pair = part.splitn(2, '=');
if let (Some(tag_str), Some(value)) = (pair.next(), pair.next()) {
if let Ok(tag) = tag_str.parse::<u32>() {
fields.push((tag, value.to_string()));
} else {
return Err(DeribitFixError::MessageParsing(format!(
"Invalid tag: {tag_str}"
)));
}
} else {
return Err(DeribitFixError::MessageParsing(format!(
"Invalid field: {part}"
)));
}
}
Ok(Self {
fields,
raw_message: raw_message.to_string(),
})
}
pub fn get_field(&self, tag: u32) -> Option<&String> {
self.fields.iter().find(|(t, _)| *t == tag).map(|(_, v)| v)
}
pub fn set_field(&mut self, tag: u32, value: String) {
if let Some(field) = self.fields.iter_mut().find(|(t, _)| *t == tag) {
field.1 = value;
} else {
self.fields.push((tag, value));
}
}
pub fn msg_type(&self) -> Option<MsgType> {
self.get_field(35).and_then(|s| s.parse().ok())
}
pub fn sender_comp_id(&self) -> Option<&String> {
self.get_field(49)
}
pub fn target_comp_id(&self) -> Option<&String> {
self.get_field(56)
}
pub fn msg_seq_num(&self) -> Option<u32> {
self.get_field(34)?.parse().ok()
}
pub fn has_field(&self, tag: u32) -> bool {
self.fields.iter().any(|(t, _)| *t == tag)
}
pub fn calculate_checksum(&self) -> u8 {
let mut field_pairs: Vec<_> = self.fields.iter().collect();
field_pairs.sort_by_key(|(tag, _)| *tag);
let mut message_parts = Vec::new();
for (tag, value) in field_pairs {
if *tag != 10 {
message_parts.push(format!("{tag}={value}"));
}
}
let message_str = message_parts.join("\x01") + "\x01";
let bytes = message_str.as_bytes();
let mut checksum: u32 = 0;
for &byte in bytes {
checksum += byte as u32;
}
(checksum % 256) as u8
}
}
impl FromStr for FixMessage {
type Err = DeribitFixError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s)
}
}
impl Default for FixMessage {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Display for FixMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.raw_message)
}
}
impl std::fmt::Debug for FixMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut readable_message = self.raw_message.replace('\x01', " | ");
if readable_message.ends_with(" | ") {
readable_message.truncate(readable_message.len() - 3);
}
let mut field_descriptions = Vec::new();
for (tag, value) in &self.fields {
let field_name = match *tag {
8 => "BeginString",
9 => "BodyLength",
35 => "MsgType",
49 => "SenderCompID",
56 => "TargetCompID",
34 => "MsgSeqNum",
52 => "SendingTime",
10 => "CheckSum",
11 => "ClOrdID",
37 => "OrderID",
38 => "OrderQty",
39 => "OrdStatus",
40 => "OrdType",
44 => "Price",
54 => "Side",
55 => "Symbol",
59 => "TimeInForce",
95 => "SecureDataLen",
96 => "SecureData",
98 => "EncryptMethod",
108 => "HeartBtInt",
553 => "Username",
554 => "Password",
584 => "MassStatusReqID",
585 => "MassStatusReqType",
710 => "PosReqID",
721 => "PosMaintRptID",
_ => "Unknown",
};
field_descriptions.push(format!("{field_name}({tag})={value}"));
}
f.debug_struct("FixMessage")
.field("fields", &field_descriptions)
.field("readable_message", &readable_message)
.finish()
}
}