use crate::common::error::Result;
use crate::common::protocol::{Frame, SerializationFormat};
use crate::common::compression::{CompressionUtil, CompressionAlgorithm};
use crate::common::serializer::SerializationUtil;
#[derive(Clone)]
pub struct MessageParser {
default_format: SerializationFormat,
default_compression: CompressionAlgorithm,
}
impl MessageParser {
pub fn new(format: SerializationFormat, compression: CompressionAlgorithm) -> Self {
Self {
default_format: format,
default_compression: compression,
}
}
pub fn protobuf() -> Self {
Self::new(SerializationFormat::Protobuf, CompressionAlgorithm::None)
}
pub fn json() -> Self {
Self::new(SerializationFormat::Json, CompressionAlgorithm::None)
}
pub fn default_format(&self) -> SerializationFormat {
self.default_format
}
pub fn default_compression(&self) -> CompressionAlgorithm {
self.default_compression
}
pub fn parse(&self, data: &[u8]) -> Result<Frame> {
let (decompressed, _algorithm) = CompressionUtil::auto_decompress(data)?;
let detected_serializers = SerializationUtil::auto_detect(&decompressed);
for serializer in detected_serializers {
if let Ok(frame) = serializer.deserialize(&decompressed) {
return Ok(frame);
}
}
for format in [SerializationFormat::Protobuf, SerializationFormat::Json] {
if let Some(serializer) = SerializationUtil::get_serializer(format) {
if let Ok(frame) = serializer.deserialize(&decompressed) {
return Ok(frame);
}
}
}
Err(crate::common::error::FlareError::deserialization_error(
"Failed to parse message: no compatible serializer found".to_string(),
))
}
pub fn parse_with_format(&self, data: &[u8], format: SerializationFormat) -> Result<Frame> {
let (decompressed, _algorithm) = CompressionUtil::auto_decompress(data)?;
let serializer = SerializationUtil::get_serializer(format)
.ok_or_else(|| crate::common::error::FlareError::deserialization_error(
format!("Serializer not found for format: {:?}", format)
))?;
serializer.deserialize(&decompressed)
}
pub fn serialize(&self, frame: &Frame) -> Result<Vec<u8>> {
self.serialize_with_format(frame, self.default_format, self.default_compression)
}
pub fn serialize_with_format(
&self,
frame: &Frame,
format: SerializationFormat,
compression: CompressionAlgorithm,
) -> Result<Vec<u8>> {
let serializer = SerializationUtil::get_serializer(format)
.ok_or_else(|| crate::common::error::FlareError::encoding_error(
format!("Serializer not found for format: {:?}", format)
))?;
let data = serializer.serialize(frame)?;
CompressionUtil::compress(&data, compression)
}
pub fn get_compression_from_frame(frame: &Frame) -> CompressionAlgorithm {
if let Some(compression_bytes) = frame.metadata.get("compression") {
if let Ok(compression_str) = std::str::from_utf8(compression_bytes) {
if let Some(algorithm) = CompressionAlgorithm::from_str(compression_str) {
return algorithm;
}
}
}
CompressionAlgorithm::None
}
pub fn get_format_from_frame(frame: &Frame) -> Option<SerializationFormat> {
if let Some(format_bytes) = frame.metadata.get("format") {
if let Ok(format_str) = std::str::from_utf8(format_bytes) {
match format_str.to_lowercase().as_str() {
"protobuf" => return Some(SerializationFormat::Protobuf),
"json" => return Some(SerializationFormat::Json),
_ => {}
}
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::protocol::{FrameBuilder, ping};
#[test]
fn test_parse_protobuf() {
let parser = MessageParser::protobuf();
let frame = FrameBuilder::new()
.with_command(crate::common::protocol::Command {
r#type: Some(crate::common::protocol::command::Type::System(ping())),
})
.build();
let data = parser.serialize(&frame).unwrap();
let parsed = parser.parse_with_format(&data, SerializationFormat::Protobuf).unwrap();
assert_eq!(frame.message_id, parsed.message_id);
}
#[test]
fn test_parse_json() {
let parser = MessageParser::json();
let frame = FrameBuilder::new()
.with_command(crate::common::protocol::Command {
r#type: Some(crate::common::protocol::command::Type::System(ping())),
})
.build();
let data = parser.serialize_with_format(&frame, SerializationFormat::Json, CompressionAlgorithm::None).unwrap();
let parsed = parser.parse_with_format(&data, SerializationFormat::Json).unwrap();
assert_eq!(frame.message_id, parsed.message_id);
}
}