ih_muse_record/file_replayer.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
// crates/ih-muse-record/src/file_replayer.rs
//! Provides the [`FileReplayer`] for replaying recorded events.
//!
//! The recording files should have a specific extension to determine
//! the encoding/serialization format. Supported extensions are:
//!
//! - `.bin` for Bincode serialization
//! - `.json` for JSON serialization
use std::path::Path;
use async_trait::async_trait;
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
use super::SerializationFormat;
use crate::{RecordedEventWithTime, Replayer};
use ih_muse_core::{MuseError, MuseResult};
/// A replayer that reads events from a recording file.
///
/// The serialization format is determined by the file extension.
/// Supported extensions are `.bin` for Bincode and `.json` for JSON.
pub struct FileReplayer {
reader: BufReader<File>,
format: SerializationFormat,
}
impl FileReplayer {
/// Creates a new `FileReplayer`.
///
/// # Arguments
///
/// - `path`: The file path to read recordings from.
///
/// # Errors
///
/// Returns a [`MuseError::Replaying`] if the file cannot be opened.
pub async fn new(path: &Path) -> MuseResult<Self> {
let ext = path.extension().and_then(|e| e.to_str());
let format = SerializationFormat::from_extension(ext)?;
let file = File::open(path)
.await
.map_err(|e| MuseError::Replaying(format!("Failed to open file: {}", e)))?;
log::info!("Using {:?} format for replaying.", format);
Ok(Self {
reader: BufReader::new(file),
format,
})
}
}
#[async_trait]
impl Replayer for FileReplayer {
async fn next_event(&mut self) -> MuseResult<Option<RecordedEventWithTime>> {
match self.format {
SerializationFormat::Bincode => {
// Bincode doesn't support async read directly; read the entire file into memory
let mut buffer = Vec::new();
let bytes_read = self
.reader
.read_to_end(&mut buffer)
.await
.map_err(|e| MuseError::Replaying(e.to_string()))?;
if bytes_read == 0 {
return Ok(None); // EOF
}
let mut cursor = std::io::Cursor::new(buffer);
match bincode::deserialize_from::<_, RecordedEventWithTime>(&mut cursor) {
Ok(timed_event) => Ok(Some(timed_event)),
Err(e) => Err(MuseError::Replaying(format!(
"Failed to deserialize event: {}",
e
))),
}
}
SerializationFormat::Json => {
let mut line = String::new();
match self.reader.read_line(&mut line).await {
Ok(0) => Ok(None), // EOF
Ok(_) => {
let timed_event: RecordedEventWithTime = serde_json::from_str(&line)
.map_err(|e| {
MuseError::Replaying(format!("Failed to deserialize event: {}", e))
})?;
Ok(Some(timed_event))
}
Err(e) => Err(MuseError::Replaying(format!("Failed to read line: {}", e))),
}
}
}
}
}