use bytes::{Buf, Bytes, BytesMut};
use moqtap_codec::dispatch::AnyControlMessage;
use moqtap_codec::varint::VarInt;
use moqtap_codec::version::DraftVersion;
#[derive(Debug, Clone)]
pub struct ParsedFrame {
pub message: AnyControlMessage,
pub raw_bytes: Option<Bytes>,
}
#[derive(Debug)]
pub enum ParseResult {
Messages(Vec<ParsedFrame>),
NeedMore,
}
pub struct ControlStreamParser {
buf: BytesMut,
draft: DraftVersion,
capture_raw: bool,
}
impl ControlStreamParser {
pub fn new(draft: DraftVersion) -> Self {
Self { buf: BytesMut::with_capacity(4096), draft, capture_raw: false }
}
pub fn new_capturing(draft: DraftVersion) -> Self {
Self { buf: BytesMut::with_capacity(4096), draft, capture_raw: true }
}
pub fn feed(&mut self, data: &[u8]) -> ParseResult {
self.buf.extend_from_slice(data);
let mut frames = Vec::new();
loop {
if self.buf.is_empty() {
break;
}
let type_len = varint_len(self.buf[0]);
if self.buf.len() < type_len {
break;
}
let mut cursor = &self.buf[..type_len];
if VarInt::decode(&mut cursor).is_err() {
break;
}
let (payload_len, total) = if self.draft.uses_fixed_length_framing() {
if self.buf.len() < type_len + 2 {
break;
}
let hi = self.buf[type_len] as usize;
let lo = self.buf[type_len + 1] as usize;
let payload_len = (hi << 8) | lo;
(payload_len, type_len + 2 + payload_len)
} else {
if self.buf.len() <= type_len {
break;
}
let payload_len_varint_len = varint_len(self.buf[type_len]);
if self.buf.len() < type_len + payload_len_varint_len {
break;
}
let mut cursor = &self.buf[type_len..type_len + payload_len_varint_len];
let payload_len = match VarInt::decode(&mut cursor) {
Ok(v) => v.into_inner() as usize,
Err(_) => break,
};
(payload_len, type_len + payload_len_varint_len + payload_len)
};
let _ = payload_len;
if self.buf.len() < total {
break;
}
let raw_bytes = if self.capture_raw {
Some(Bytes::copy_from_slice(&self.buf[..total]))
} else {
None
};
let mut decode_buf = &self.buf[..total];
match AnyControlMessage::decode(self.draft, &mut decode_buf) {
Ok(message) => {
self.buf.advance(total);
frames.push(ParsedFrame { message, raw_bytes });
}
Err(_) => {
self.buf.advance(total);
break;
}
}
}
if frames.is_empty() {
ParseResult::NeedMore
} else {
ParseResult::Messages(frames)
}
}
pub fn draft(&self) -> DraftVersion {
self.draft
}
}
impl Default for ControlStreamParser {
fn default() -> Self {
Self::new(DraftVersion::Draft14)
}
}
fn varint_len(first_byte: u8) -> usize {
1 << (first_byte >> 6)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn varint_len_values() {
assert_eq!(varint_len(0x00), 1);
assert_eq!(varint_len(0x3F), 1);
assert_eq!(varint_len(0x40), 2);
assert_eq!(varint_len(0x80), 4);
assert_eq!(varint_len(0xC0), 8);
}
}