1.0.0
Tschuss Status Quo - Hallo, Zukunft!
This commit is contained in:
120
src/protocol/frame.rs
Normal file
120
src/protocol/frame.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
//! 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<String, String>,
|
||||
}
|
||||
|
||||
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<u8>, 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user