use chrono::{DateTime, Utc};
use crate::chat::constants::{SEPARATOR_U8, message_codes::MessageCode};
#[derive(Debug)]
pub struct RawMessage {
pub code: MessageCode,
pub _red_code: u32,
pub body: Vec<String>,
pub received_time: DateTime<Utc>,
}
struct MessageHeader {
code: MessageCode,
ret_code: u32,
}
pub fn parse_message(data: &[u8]) -> Result<RawMessage, String> {
let now = Utc::now();
let header_bytes = &data[0..14];
let header = parse_header(header_bytes)?;
let body = &data[14..];
Ok(RawMessage {
code: header.code,
_red_code: header.ret_code,
body: parse_body(body),
received_time: now,
})
}
fn parse_header(header: &[u8]) -> Result<MessageHeader, String> {
if header.len() != 14 {
return Err("Invalid header length".to_string());
}
Ok(MessageHeader {
code: parse_bytes_to_u32(&header[2..6]),
ret_code: parse_bytes_to_u32(&header[12..14]),
})
}
fn parse_body(body: &[u8]) -> Vec<String> {
if body.len() < 2 {
return Vec::new();
}
let data_to_process = &body[1..];
let separator_count = data_to_process.iter().filter(|&&b| b == SEPARATOR_U8).count();
let mut result = Vec::with_capacity(separator_count + 1);
for byte_part in data_to_process.split(|&byte| byte == SEPARATOR_U8) {
match std::str::from_utf8(byte_part) {
Ok(s) => result.push(s.to_string()),
Err(_) => {
let cow_str = String::from_utf8_lossy(byte_part);
result.push(cow_str.into_owned());
}
}
}
result
}
fn parse_bytes_to_u32(bytes: &[u8]) -> u32 {
match std::str::from_utf8(bytes) {
Ok(s) => s.parse::<u32>().unwrap_or(0),
Err(_) => {
String::from_utf8_lossy(bytes).parse::<u32>().unwrap_or(0)
}
}
}