//! MTProto frame types and metadata use std::collections::HashMap; /// Extra metadata associated with a frame #[derive(Debug, Clone, Default)] pub struct FrameExtra { /// Quick ACK flag - request immediate acknowledgment pub quickack: bool, /// Simple ACK - this is an acknowledgment message pub simple_ack: bool, /// Skip sending - internal flag to skip forwarding pub skip_send: bool, /// Custom key-value metadata pub custom: HashMap, } impl FrameExtra { /// Create new empty frame extra pub fn new() -> Self { Self::default() } /// Create with quickack flag set pub fn with_quickack() -> Self { Self { quickack: true, ..Default::default() } } /// Create with simple_ack flag set pub fn with_simple_ack() -> Self { Self { simple_ack: true, ..Default::default() } } /// Check if any flags are set pub fn has_flags(&self) -> bool { self.quickack || self.simple_ack || self.skip_send } } /// Result of reading a frame #[derive(Debug)] pub enum FrameReadResult { /// Successfully read a frame with data and metadata Data(Vec, FrameExtra), /// Connection closed normally Closed, /// Need more data (for non-blocking reads) WouldBlock, } /// Frame encoding/decoding mode #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FrameMode { /// Abridged - 1 or 4 byte length prefix Abridged, /// Intermediate - 4 byte length prefix Intermediate, /// Secure Intermediate - 4 byte length with padding SecureIntermediate, /// Full MTProto - with seq_no and CRC32 Full, } impl FrameMode { /// Get maximum overhead for this frame mode pub fn max_overhead(&self) -> usize { match self { FrameMode::Abridged => 4, FrameMode::Intermediate => 4, FrameMode::SecureIntermediate => 4 + 3, // length + padding FrameMode::Full => 12 + 16, // header + max CBC padding } } } /// Validate message length for MTProto pub fn validate_message_length(len: usize) -> bool { use super::constants::{MIN_MSG_LEN, MAX_MSG_LEN, PADDING_FILLER}; len >= MIN_MSG_LEN && len <= MAX_MSG_LEN && len % PADDING_FILLER.len() == 0 } #[cfg(test)] mod tests { use super::*; #[test] fn test_frame_extra_default() { let extra = FrameExtra::default(); assert!(!extra.quickack); assert!(!extra.simple_ack); assert!(!extra.skip_send); assert!(!extra.has_flags()); } #[test] fn test_frame_extra_flags() { let extra = FrameExtra::with_quickack(); assert!(extra.quickack); assert!(extra.has_flags()); let extra = FrameExtra::with_simple_ack(); assert!(extra.simple_ack); assert!(extra.has_flags()); } #[test] fn test_validate_message_length() { assert!(validate_message_length(12)); // MIN_MSG_LEN assert!(validate_message_length(16)); assert!(!validate_message_length(8)); // Too small assert!(!validate_message_length(13)); // Not aligned to 4 } }