Skip to main content

moqtap_trace/
moqtrace.rs

1use crate::event::TraceEvent;
2use std::io::{BufRead, BufReader, Read, Write};
3
4pub const MOQTRACE_MAGIC: &[u8; 8] = b"MOQTRACE";
5pub const MOQTRACE_VERSION: u32 = 1;
6
7#[derive(Debug, thiserror::Error)]
8pub enum MoqTraceError {
9    #[error("io error: {0}")]
10    Io(#[from] std::io::Error),
11    #[error("json error: {0}")]
12    Json(#[from] serde_json::Error),
13    #[error("invalid magic bytes")]
14    InvalidMagic,
15    #[error("unsupported version: {0}")]
16    UnsupportedVersion(u32),
17}
18
19/// Writes trace events to a .moqtrace file (JSON-lines with header).
20#[derive(Debug)]
21pub struct MoqTraceWriter<W: Write> {
22    inner: W,
23}
24
25/// Reads trace events from a .moqtrace file.
26#[derive(Debug)]
27pub struct MoqTraceReader<R: Read> {
28    inner: BufReader<R>,
29}
30
31impl<W: Write> MoqTraceWriter<W> {
32    pub fn new(mut writer: W) -> Result<Self, MoqTraceError> {
33        writer.write_all(MOQTRACE_MAGIC)?;
34        writer.write_all(&MOQTRACE_VERSION.to_le_bytes())?;
35        Ok(Self { inner: writer })
36    }
37
38    pub fn write_event(&mut self, event: &TraceEvent) -> Result<(), MoqTraceError> {
39        let json = serde_json::to_string(event)?;
40        self.inner.write_all(json.as_bytes())?;
41        self.inner.write_all(b"\n")?;
42        Ok(())
43    }
44
45    pub fn flush(&mut self) -> Result<(), MoqTraceError> {
46        self.inner.flush()?;
47        Ok(())
48    }
49}
50
51impl<R: Read> MoqTraceReader<R> {
52    pub fn new(mut reader: R) -> Result<Self, MoqTraceError> {
53        let mut magic = [0u8; 8];
54        reader.read_exact(&mut magic)?;
55        if &magic != MOQTRACE_MAGIC {
56            return Err(MoqTraceError::InvalidMagic);
57        }
58        let mut version_bytes = [0u8; 4];
59        reader.read_exact(&mut version_bytes)?;
60        let version = u32::from_le_bytes(version_bytes);
61        if version != MOQTRACE_VERSION {
62            return Err(MoqTraceError::UnsupportedVersion(version));
63        }
64        Ok(Self { inner: BufReader::new(reader) })
65    }
66
67    pub fn read_event(&mut self) -> Result<Option<TraceEvent>, MoqTraceError> {
68        let mut line = String::new();
69        let bytes_read = self.inner.read_line(&mut line)?;
70        if bytes_read == 0 || line.trim().is_empty() {
71            return Ok(None);
72        }
73        let event: TraceEvent = serde_json::from_str(line.trim())?;
74        Ok(Some(event))
75    }
76}
77
78impl<R: Read> IntoIterator for MoqTraceReader<R> {
79    type Item = Result<TraceEvent, MoqTraceError>;
80    type IntoIter = MoqTraceIterator<R>;
81
82    fn into_iter(self) -> Self::IntoIter {
83        MoqTraceIterator { reader: self }
84    }
85}
86
87pub struct MoqTraceIterator<R: Read> {
88    reader: MoqTraceReader<R>,
89}
90
91impl<R: Read> Iterator for MoqTraceIterator<R> {
92    type Item = Result<TraceEvent, MoqTraceError>;
93
94    fn next(&mut self) -> Option<Self::Item> {
95        match self.reader.read_event() {
96            Ok(Some(event)) => Some(Ok(event)),
97            Ok(None) => None,
98            Err(e) => Some(Err(e)),
99        }
100    }
101}